changeset 14604:481d3d06198d

Merge
author prr
date Tue, 17 Nov 2015 10:29:28 -0800
parents 3c1ed8084a75 7ee52e42f56f
children 535b61fec549 641634ba1c11
files test/java/util/stream/bootlib/java/util/stream/CollectorOps.java test/java/util/stream/bootlib/java/util/stream/DefaultMethodStreams.java test/java/util/stream/bootlib/java/util/stream/DoubleStreamTestDataProvider.java test/java/util/stream/bootlib/java/util/stream/DoubleStreamTestScenario.java test/java/util/stream/bootlib/java/util/stream/FlagDeclaringOp.java test/java/util/stream/bootlib/java/util/stream/IntStreamTestDataProvider.java test/java/util/stream/bootlib/java/util/stream/IntStreamTestScenario.java test/java/util/stream/bootlib/java/util/stream/IntermediateTestOp.java test/java/util/stream/bootlib/java/util/stream/LambdaTestHelpers.java test/java/util/stream/bootlib/java/util/stream/LambdaTestMode.java test/java/util/stream/bootlib/java/util/stream/LoggingTestCase.java test/java/util/stream/bootlib/java/util/stream/LongStreamTestDataProvider.java test/java/util/stream/bootlib/java/util/stream/LongStreamTestScenario.java test/java/util/stream/bootlib/java/util/stream/OpTestCase.java test/java/util/stream/bootlib/java/util/stream/SpliteratorTestHelper.java test/java/util/stream/bootlib/java/util/stream/StatefulTestOp.java test/java/util/stream/bootlib/java/util/stream/StatelessTestOp.java test/java/util/stream/bootlib/java/util/stream/StreamOpFlagTestHelper.java test/java/util/stream/bootlib/java/util/stream/StreamTestDataProvider.java test/java/util/stream/bootlib/java/util/stream/StreamTestScenario.java test/java/util/stream/bootlib/java/util/stream/TestData.java test/java/util/stream/bootlib/java/util/stream/TestFlagExpectedOp.java test/java/util/stream/bootlib/java/util/stream/ThowableHelper.java test/java/util/stream/boottest/java/util/stream/DoubleNodeTest.java test/java/util/stream/boottest/java/util/stream/FlagOpTest.java test/java/util/stream/boottest/java/util/stream/IntNodeTest.java test/java/util/stream/boottest/java/util/stream/LongNodeTest.java test/java/util/stream/boottest/java/util/stream/NodeBuilderTest.java test/java/util/stream/boottest/java/util/stream/NodeTest.java test/java/util/stream/boottest/java/util/stream/SliceSpliteratorTest.java test/java/util/stream/boottest/java/util/stream/SpinedBufferTest.java test/java/util/stream/boottest/java/util/stream/StreamFlagsTest.java test/java/util/stream/boottest/java/util/stream/StreamOpFlagsTest.java test/java/util/stream/boottest/java/util/stream/StreamReuseTest.java
diffstat 433 files changed, 21423 insertions(+), 10890 deletions(-) [+]
line wrap: on
line diff
--- a/.hgtags	Tue Nov 10 13:46:45 2015 +0300
+++ b/.hgtags	Tue Nov 17 10:29:28 2015 -0800
@@ -334,3 +334,4 @@
 0d0a63b325592607974612f9cfb48590975aa2d6 jdk9-b89
 b433e4dfb830fea60e5187e4580791b62cc362d2 jdk9-b90
 97624df5026a2fb191793697dbd2c604c4d5c66e jdk9-b91
+6a5c99506f44538b879d8635a3979849ed587130 jdk9-b92
--- a/make/Import.gmk	Tue Nov 10 13:46:45 2015 +0300
+++ b/make/Import.gmk	Tue Nov 17 10:29:28 2015 -0800
@@ -1,5 +1,5 @@
 #
-# Copyright (c) 2012, 2014, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2012, 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
@@ -45,8 +45,16 @@
 #
 # Import hotspot
 #
+
+# Don't import jsig library for static builds
+ifneq ($(STATIC_BUILD), true)
+  JSIG_IMPORT = jsig.*
+else
+  JSIG_IMPORT = 
+endif
+
 HOTSPOT_BASE_IMPORT_FILES := \
-    $(addprefix $(LIBRARY_PREFIX), jvm.* jsig.* jvm_db.* jvm_dtrace.*) \
+    $(addprefix $(LIBRARY_PREFIX), jvm.* $(JSIG_IMPORT) jvm_db.* jvm_dtrace.*) \
     Xusage.txt \
     #
 
@@ -79,32 +87,34 @@
 
 ################################################################################
 
-ifeq ($(OPENJDK_TARGET_OS), macosx)
-  JSIG_DEBUGINFO := $(strip $(wildcard $(HOTSPOT_DIST)/lib$(OPENJDK_TARGET_CPU_LIBDIR)/libjsig$(SHARED_LIBRARY_SUFFIX).dSYM) \
-      $(wildcard $(HOTSPOT_DIST)/lib$(OPENJDK_TARGET_CPU_LIBDIR)/libjsig.diz) )
-else
-  JSIG_DEBUGINFO := $(strip $(wildcard $(HOTSPOT_DIST)/lib$(OPENJDK_TARGET_CPU_LIBDIR)/libjsig.debuginfo) \
-      $(wildcard $(HOTSPOT_DIST)/lib$(OPENJDK_TARGET_CPU_LIBDIR)/libjsig.diz) )
-endif
+ifneq ($(STATIC_BUILD), true)
+  ifeq ($(OPENJDK_TARGET_OS), macosx)
+    JSIG_DEBUGINFO := $(strip $(wildcard $(HOTSPOT_DIST)/lib$(OPENJDK_TARGET_CPU_LIBDIR)/libjsig$(SHARED_LIBRARY_SUFFIX).dSYM) \
+        $(wildcard $(HOTSPOT_DIST)/lib$(OPENJDK_TARGET_CPU_LIBDIR)/libjsig.diz) )
+  else
+    JSIG_DEBUGINFO := $(strip $(wildcard $(HOTSPOT_DIST)/lib$(OPENJDK_TARGET_CPU_LIBDIR)/libjsig.debuginfo) \
+        $(wildcard $(HOTSPOT_DIST)/lib$(OPENJDK_TARGET_CPU_LIBDIR)/libjsig.diz) )
+  endif
 
-ifneq ($(OPENJDK_TARGET_OS), windows)
-  ifeq ($(JVM_VARIANT_SERVER), true)
-    BASE_TARGETS += $(BASE_INSTALL_LIBRARIES_HERE)/server/$(LIBRARY_PREFIX)jsig$(SHARED_LIBRARY_SUFFIX)
-    ifneq (, $(JSIG_DEBUGINFO))
-      BASE_TARGETS += $(BASE_INSTALL_LIBRARIES_HERE)/server/$(foreach I,$(JSIG_DEBUGINFO),$(notdir $I))
+  ifneq ($(OPENJDK_TARGET_OS), windows)
+    ifeq ($(JVM_VARIANT_SERVER), true)
+      BASE_TARGETS += $(BASE_INSTALL_LIBRARIES_HERE)/server/$(LIBRARY_PREFIX)jsig$(SHARED_LIBRARY_SUFFIX)
+      ifneq (, $(JSIG_DEBUGINFO))
+        BASE_TARGETS += $(BASE_INSTALL_LIBRARIES_HERE)/server/$(foreach I,$(JSIG_DEBUGINFO),$(notdir $I))
+      endif
     endif
-  endif
-  ifeq ($(JVM_VARIANT_CLIENT), true)
-    BASE_TARGETS += $(BASE_INSTALL_LIBRARIES_HERE)/client/$(LIBRARY_PREFIX)jsig$(SHARED_LIBRARY_SUFFIX)
-    ifneq (, $(JSIG_DEBUGINFO))
-      BASE_TARGETS += $(BASE_INSTALL_LIBRARIES_HERE)/client/$(foreach I,$(JSIG_DEBUGINFO),$(notdir $I))
+    ifeq ($(JVM_VARIANT_CLIENT), true)
+      BASE_TARGETS += $(BASE_INSTALL_LIBRARIES_HERE)/client/$(LIBRARY_PREFIX)jsig$(SHARED_LIBRARY_SUFFIX)
+      ifneq (, $(JSIG_DEBUGINFO))
+        BASE_TARGETS += $(BASE_INSTALL_LIBRARIES_HERE)/client/$(foreach I,$(JSIG_DEBUGINFO),$(notdir $I))
+      endif
     endif
-  endif
-  ifneq ($(OPENJDK_TARGET_OS), macosx)
-    ifeq ($(JVM_VARIANT_MINIMAL1), true)
-      BASE_TARGETS += $(BASE_INSTALL_LIBRARIES_HERE)/minimal/$(LIBRARY_PREFIX)jsig$(SHARED_LIBRARY_SUFFIX)
-      ifneq (,$(JSIG_DEBUGINFO))
-        BASE_TARGETS += $(BASE_INSTALL_LIBRARIES_HERE)/minimal/$(foreach I,$(JSIG_DEBUGINFO),$(notdir $I))
+    ifneq ($(OPENJDK_TARGET_OS), macosx)
+      ifeq ($(JVM_VARIANT_MINIMAL1), true)
+        BASE_TARGETS += $(BASE_INSTALL_LIBRARIES_HERE)/minimal/$(LIBRARY_PREFIX)jsig$(SHARED_LIBRARY_SUFFIX)
+        ifneq (,$(JSIG_DEBUGINFO))
+          BASE_TARGETS += $(BASE_INSTALL_LIBRARIES_HERE)/minimal/$(foreach I,$(JSIG_DEBUGINFO),$(notdir $I))
+        endif
       endif
     endif
   endif
--- a/make/data/charsetmapping/DoubleByte-X.java.template	Tue Nov 10 13:46:45 2015 +0300
+++ b/make/data/charsetmapping/DoubleByte-X.java.template	Tue Nov 17 10:29:28 2015 -0800
@@ -50,12 +50,12 @@
 
     public CharsetDecoder newDecoder() {
         initb2c();
-        return new  DoubleByte.Decoder$DECTYPE$(this, b2c, b2cSB, $B2MIN$, $B2MAX$);
+        return new  DoubleByte.Decoder$DECTYPE$(this, b2c, b2cSB, $B2MIN$, $B2MAX$, $ASCIICOMPATIBLE$);
     }
 
     public CharsetEncoder newEncoder() {
         initc2b();
-        return new DoubleByte.Encoder$ENCTYPE$(this, $ENC_REPLACEMENT$ c2b, c2bIndex); 
+        return new DoubleByte.Encoder$ENCTYPE$(this, $ENC_REPLACEMENT$ c2b, c2bIndex, $ASCIICOMPATIBLE$);
     }
 
     $B2C$
--- a/make/data/charsetmapping/SingleByte-X.java.template	Tue Nov 10 13:46:45 2015 +0300
+++ b/make/data/charsetmapping/SingleByte-X.java.template	Tue Nov 17 10:29:28 2015 -0800
@@ -48,11 +48,11 @@
     }
 
     public CharsetDecoder newDecoder() {
-        return new SingleByte.Decoder(this, b2c);
+        return new SingleByte.Decoder(this, b2c, $ASCIICOMPATIBLE$);
     }
 
     public CharsetEncoder newEncoder() {
-        return new SingleByte.Encoder(this, c2b, c2bIndex);
+        return new SingleByte.Encoder(this, c2b, c2bIndex, $ASCIICOMPATIBLE$);
     }
 
     private final static String b2cTable = $B2CTABLE$
--- a/make/gensrc/Gensrc-java.base.gmk	Tue Nov 10 13:46:45 2015 +0300
+++ b/make/gensrc/Gensrc-java.base.gmk	Tue Nov 17 10:29:28 2015 -0800
@@ -1,5 +1,5 @@
 #
-# Copyright (c) 2011, 2013, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2011, 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
@@ -38,15 +38,15 @@
 
 include GensrcProperties.gmk
 
-$(eval $(call SetupCompileProperties,LIST_RESOURCE_BUNDLE, \
-    $(filter %.properties, \
-        $(call CacheFind, $(JDK_TOPDIR)/src/java.base/share/classes/sun/launcher/resources)), \
-    ListResourceBundle))
+$(eval $(call SetupCompileProperties, LIST_RESOURCE_BUNDLE, \
+    SRC_DIRS := $(JDK_TOPDIR)/src/java.base/share/classes/sun/launcher/resources, \
+    CLASS := ListResourceBundle, \
+))
 
-$(eval $(call SetupCompileProperties,SUN_UTIL, \
-    $(filter %.properties, \
-        $(call CacheFind, $(JDK_TOPDIR)/src/java.base/share/classes/sun/util/resources)), \
-    sun.util.resources.LocaleNamesBundle))
+$(eval $(call SetupCompileProperties, SUN_UTIL, \
+    SRC_DIRS := $(JDK_TOPDIR)/src/java.base/share/classes/sun/util/resources, \
+    CLASS := sun.util.resources.LocaleNamesBundle, \
+))
 
 GENSRC_JAVA_BASE += $(LIST_RESOURCE_BUNDLE) $(SUN_UTIL)
 
--- a/make/gensrc/Gensrc-java.desktop.gmk	Tue Nov 10 13:46:45 2015 +0300
+++ b/make/gensrc/Gensrc-java.desktop.gmk	Tue Nov 17 10:29:28 2015 -0800
@@ -1,5 +1,5 @@
 #
-# Copyright (c) 2011, 2014, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2011, 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
@@ -66,11 +66,11 @@
   PROP_SRC_DIRS += $(JDK_TOPDIR)/src/java.desktop/share/classes/com/sun/java/swing/plaf/gtk/resources
 endif
 
-PROP_SRC_FILES := $(filter-out %cursors.properties, \
-    $(filter %.properties, $(call CacheFind, $(PROP_SRC_DIRS))))
-
-$(eval $(call SetupCompileProperties,COMPILE_PROPERTIES, \
-    $(PROP_SRC_FILES), ListResourceBundle))
+$(eval $(call SetupCompileProperties, COMPILE_PROPERTIES, \
+    SRC_DIRS := $(PROP_SRC_DIRS), \
+    EXCLUDE := %cursors.properties, \
+    CLASS := ListResourceBundle, \
+))
 
 GENSRC_JAVA_DESKTOP += $(COMPILE_PROPERTIES)
 
--- a/make/gensrc/Gensrc-java.logging.gmk	Tue Nov 10 13:46:45 2015 +0300
+++ b/make/gensrc/Gensrc-java.logging.gmk	Tue Nov 17 10:29:28 2015 -0800
@@ -1,5 +1,5 @@
 #
-# Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved.
 # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 #
 # This code is free software; you can redistribute it and/or modify it
@@ -29,10 +29,10 @@
 
 include GensrcProperties.gmk
 
-$(eval $(call SetupCompileProperties,COMPILE_PROPERTIES, \
-    $(filter %.properties, \
-        $(call CacheFind, $(JDK_TOPDIR)/src/java.logging/share/classes/sun/util/logging/resources)), \
-    ListResourceBundle))
+$(eval $(call SetupCompileProperties, COMPILE_PROPERTIES, \
+    SRC_DIRS := $(JDK_TOPDIR)/src/java.logging/share/classes/sun/util/logging/resources, \
+    CLASS := ListResourceBundle, \
+))
 
 TARGETS += $(COMPILE_PROPERTIES)
 
--- a/make/gensrc/Gensrc-java.management.gmk	Tue Nov 10 13:46:45 2015 +0300
+++ b/make/gensrc/Gensrc-java.management.gmk	Tue Nov 17 10:29:28 2015 -0800
@@ -1,5 +1,5 @@
 #
-# Copyright (c) 2011, 2013, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2011, 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
@@ -32,10 +32,10 @@
 
 include GensrcProperties.gmk
 
-$(eval $(call SetupCompileProperties,COMPILE_PROPERTIES, \
-    $(filter %.properties, \
-        $(call CacheFind, $(JDK_TOPDIR)/src/java.management/share/classes/sun/management/resources)), \
-    ListResourceBundle))
+$(eval $(call SetupCompileProperties, COMPILE_PROPERTIES, \
+    SRC_DIRS := $(JDK_TOPDIR)/src/java.management/share/classes/sun/management/resources, \
+    CLASS := ListResourceBundle, \
+))
 
 TARGETS += $(COMPILE_PROPERTIES)
 
--- a/make/gensrc/Gensrc-jdk.dev.gmk	Tue Nov 10 13:46:45 2015 +0300
+++ b/make/gensrc/Gensrc-jdk.dev.gmk	Tue Nov 17 10:29:28 2015 -0800
@@ -1,5 +1,5 @@
 #
-# Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved.
 # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 #
 # This code is free software; you can redistribute it and/or modify it
@@ -29,11 +29,10 @@
 
 include GensrcProperties.gmk
 
-$(eval $(call SetupCompileProperties,COMPILE_PROPERTIES, \
-    $(filter %.properties, \
-        $(call CacheFind, \
-            $(JDK_TOPDIR)/src/jdk.dev/share/classes/jdk/tools/jimage/resources)), \
-    ListResourceBundle))
+$(eval $(call SetupCompileProperties, COMPILE_PROPERTIES, \
+    SRC_DIRS := $(JDK_TOPDIR)/src/jdk.dev/share/classes/jdk/tools/jimage/resources, \
+    CLASS := ListResourceBundle, \
+))
 
 TARGETS += $(COMPILE_PROPERTIES)
 
--- a/make/gensrc/Gensrc-jdk.jartool.gmk	Tue Nov 10 13:46:45 2015 +0300
+++ b/make/gensrc/Gensrc-jdk.jartool.gmk	Tue Nov 17 10:29:28 2015 -0800
@@ -29,11 +29,10 @@
 
 include GensrcProperties.gmk
 
-$(eval $(call SetupCompileProperties,COMPILE_PROPERTIES, \
-    $(filter %.properties, \
-        $(call CacheFind, \
-            $(JDK_TOPDIR)/src/jdk.jartool/share/classes/sun/tools/jar/resources)), \
-    ListResourceBundle))
+$(eval $(call SetupCompileProperties, COMPILE_PROPERTIES, \
+    SRC_DIRS := $(JDK_TOPDIR)/src/jdk.jartool/share/classes/sun/tools/jar/resources, \
+    CLASS := ListResourceBundle, \
+))
 
 TARGETS += $(COMPILE_PROPERTIES)
 
--- a/make/gensrc/Gensrc-jdk.jdi.gmk	Tue Nov 10 13:46:45 2015 +0300
+++ b/make/gensrc/Gensrc-jdk.jdi.gmk	Tue Nov 17 10:29:28 2015 -0800
@@ -1,5 +1,5 @@
 #
-# Copyright (c) 2011, 2014, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2011, 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
@@ -34,7 +34,7 @@
 JAVA_FILE := $(SUPPORT_OUTPUTDIR)/gensrc/jdk.jdi/com/sun/tools/jdi/JDWP.java
 
 # Both the header and java file are created using the same recipe. By declaring
-# this rule and adding header file to dependencies for java file, both are 
+# this rule and adding header file to dependencies for java file, both are
 # rebuilt if either is missing
 $(HEADER_FILE): $(JDWP_SPEC_FILE) $(BUILD_TOOLS_JDK)
 
@@ -90,10 +90,10 @@
 
 include GensrcProperties.gmk
 
-$(eval $(call SetupCompileProperties,COMPILE_PROPERTIES, \
-    $(filter %.properties, \
-        $(call CacheFind, $(JDK_TOPDIR)/src/jdk.jdi/share/classes/com/sun/tools/jdi/resources)), \
-    ListResourceBundle))
+$(eval $(call SetupCompileProperties, COMPILE_PROPERTIES, \
+    SRC_DIRS := $(JDK_TOPDIR)/src/jdk.jdi/share/classes/com/sun/tools/jdi/resources, \
+    CLASS := ListResourceBundle, \
+))
 
 GENSRC_JDK_JDI += $(COMPILE_PROPERTIES)
 
--- a/make/gensrc/Gensrc-jdk.localedata.gmk	Tue Nov 10 13:46:45 2015 +0300
+++ b/make/gensrc/Gensrc-jdk.localedata.gmk	Tue Nov 17 10:29:28 2015 -0800
@@ -1,5 +1,5 @@
 #
-# Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved.
 # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 #
 # This code is free software; you can redistribute it and/or modify it
@@ -35,10 +35,10 @@
 
 include GensrcProperties.gmk
 
-$(eval $(call SetupCompileProperties,COMPILE_PROPERTIES, \
-    $(filter %.properties, \
-        $(call CacheFind, $(JDK_TOPDIR)/src/jdk.localedata/share/classes/sun/util/resources)), \
-    sun.util.resources.LocaleNamesBundle))
+$(eval $(call SetupCompileProperties, COMPILE_PROPERTIES, \
+    SRC_DIRS := $(JDK_TOPDIR)/src/jdk.localedata/share/classes/sun/util/resources, \
+    CLASS := sun.util.resources.LocaleNamesBundle, \
+))
 
 # Skip generating zh_HK from zh_TW for this module.
 GENSRC_JDK_LOCALEDATA += $(filter-out %_zh_HK.java, $(COMPILE_PROPERTIES))
--- a/make/gensrc/GensrcProperties.gmk	Tue Nov 10 13:46:45 2015 +0300
+++ b/make/gensrc/GensrcProperties.gmk	Tue Nov 17 10:29:28 2015 -0800
@@ -1,5 +1,5 @@
 #
-# Copyright (c) 2011, 2014, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2011, 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
@@ -49,30 +49,40 @@
 endef
 
 ################################################################################
-# Creates a rule that runs CompileProperties on a set of properties files.
-# Param 1 - Variable to add targets to, must not contain space
-# Param 2 - Properties files to process
-# Param 3 - The super class for the generated classes
-# Param 4 - Module path root, defaults to $(JDK_TOPDIR)/src
-define SetupCompileProperties
-  $1_SRCS := $2
-  $1_CLASS := $3
-  $1_MODULE_PATH_ROOT := $4
-
+# Setup make rules that runs CompileProperties on a set of properties files.
+#
+# Parameter 1 is the name of the rule. This name is used as variable prefix,
+# and the targets generated are listed in a variable by that name.
+#
+# Remaining parameters are named arguments. These include:
+# SRC_DIRS   Directories containing properties files to process.
+# EXCLUDE   Exclude files matching this pattern.
+# CLASS   The super class for the generated classes.
+# MODULE_PATH_ROOT   Module path root, defaults to $(JDK_TOPDIR)/src.
+SetupCompileProperties = $(NamedParamsMacroTemplate)
+define SetupCompilePropertiesBody
+  # Set default value unless overridden
   ifeq ($$($1_MODULE_PATH_ROOT), )
     $1_MODULE_PATH_ROOT := $(JDK_TOPDIR)/src
   endif
 
+  # Locate all properties files in the given source dirs.
+  $1_SRC_FILES := $$(filter %.properties, $$(call CacheFind, $$($1_SRC_DIRS)))
+
+  ifneq ($$($1_EXCLUDE), )
+    $1_SRC_FILES := $$(filter-out $$($1_EXCLUDE), $$($1_SRC_FILES))
+  endif
+
   # Convert .../src/<module>/share/classes/com/sun/tools/javac/resources/javac_zh_CN.properties
   # to .../support/gensrc/<module>/com/sun/tools/javac/resources/javac_zh_CN.java
-  # Strip away prefix and suffix, leaving for example only: 
+  # Strip away prefix and suffix, leaving for example only:
   # "<module>/share/classes/com/sun/tools/javac/resources/javac_zh_CN"
   $1_JAVAS := $$(patsubst $$($1_MODULE_PATH_ROOT)/%, \
       $(SUPPORT_OUTPUTDIR)/gensrc/%, \
       $$(patsubst %.properties, %.java, \
       $$(subst /$(OPENJDK_TARGET_OS)/classes,, \
       $$(subst /$(OPENJDK_TARGET_OS_TYPE)/classes,, \
-      $$(subst /share/classes,, $$($1_SRCS))))))
+      $$(subst /share/classes,, $$($1_SRC_FILES))))))
 
   # Generate the package dirs for the to be generated java files. Sort to remove
   # duplicates.
@@ -82,22 +92,22 @@
   # "-compile ...javac_zh_CN.properties ...javac_zh_CN.java java.util.ListResourceBundle"
   # suitable to be fed into the CompileProperties command.
   $1_CMDLINE := $$(subst _SPACE_, $(SPACE), \
-      $$(join $$(addprefix -compile_SPACE_, $$($1_SRCS)), \
+      $$(join $$(addprefix -compile_SPACE_, $$($1_SRC_FILES)), \
       $$(addsuffix _SPACE_$$($1_CLASS), \
       $$(addprefix _SPACE_, $$($1_JAVAS)))))
 
-  $1_TARGET := $(SUPPORT_OUTPUTDIR)/gensrc/$(MODULE)/_the.$1.done
+  $1_TARGET := $(SUPPORT_OUTPUTDIR)/gensrc/$(MODULE)/_the.$1.marker
   $1_CMDLINE_FILE := $(SUPPORT_OUTPUTDIR)/gensrc/$(MODULE)/_the.$1.cmdline
 
 # Now setup the rule for the generation of the resource bundles.
-  $$($1_TARGET): $$($1_SRCS) $$($1_JAVAS) $(BUILD_TOOLS_JDK)
+  $$($1_TARGET): $$($1_SRC_FILES) $$($1_JAVAS) $(BUILD_TOOLS_JDK)
 	$(MKDIR) -p $$(@D) $$($1_DIRS)
-	$(ECHO) Compiling $$(words $$($1_SRCS)) properties into resource bundles for $(MODULE)
+	$(ECHO) Compiling $$(words $$($1_SRC_FILES)) properties into resource bundles for $(MODULE)
 	$$(eval $$(call ListPathsSafely, $1_CMDLINE, $$($1_CMDLINE_FILE)))
 	$(TOOL_COMPILEPROPERTIES) -quiet @$$($1_CMDLINE_FILE)
 	$(TOUCH) $$@
 
-  $$($1_JAVAS): $$($1_SRCS)
+  $$($1_JAVAS): $$($1_SRC_FILES)
 
   # Create zh_HK versions of all zh_TW files created above
   $$(eval $$(call SetupCopy-zh_HK,$1_HK,$$(filter %_zh_TW.java, $$($1_JAVAS))))
--- a/make/launcher/LauncherCommon.gmk	Tue Nov 10 13:46:45 2015 +0300
+++ b/make/launcher/LauncherCommon.gmk	Tue Nov 17 10:29:28 2015 -0800
@@ -122,8 +122,23 @@
     endif
 
     $1_CFLAGS += -DPACKAGE_PATH='"$(PACKAGE_PATH)"'
-    $1_LDFLAGS += -Wl,-all_load $(SUPPORT_OUTPUTDIR)/native/java.base/libjli_static.a \
+    $1_LDFLAGS += -Wl,-all_load \
         -sectcreate __TEXT __info_plist $(MACOSX_PLIST_DIR)/$$($1_PLIST_FILE)
+    ifeq ($(STATIC_BUILD), true)
+      $1_LDFLAGS += -exported_symbols_list \
+              $(SUPPORT_OUTPUTDIR)/build-static/exported.symbols
+      $1_LIBS += \
+          $(shell $(FIND) $(SUPPORT_OUTPUTDIR)/modules_libs/java.base -name "*.a") \
+          $(SUPPORT_OUTPUTDIR)/modules_libs/jdk.jdwp.agent/libdt_socket.a \
+          $(SUPPORT_OUTPUTDIR)/modules_libs/jdk.jdwp.agent/libjdwp.a \
+          $(SUPPORT_OUTPUTDIR)/native/java.base/$(LIBRARY_PREFIX)fdlibm$(STATIC_LIBRARY_SUFFIX) \
+          -framework CoreFoundation \
+          -framework Foundation \
+          -framework SystemConfiguration \
+          -lstdc++ -liconv
+    else
+      $1_LIBS += $(SUPPORT_OUTPUTDIR)/native/java.base/libjli_static.a
+    endif
     $1_LIBS += -framework Cocoa -framework Security \
         -framework ApplicationServices
   endif
--- a/make/lib/CoreLibraries.gmk	Tue Nov 10 13:46:45 2015 +0300
+++ b/make/lib/CoreLibraries.gmk	Tue Nov 17 10:29:28 2015 -0800
@@ -435,10 +435,14 @@
       OBJECT_DIR := $(SUPPORT_OUTPUTDIR)/native/$(MODULE)/libjli_static, \
       DEBUG_SYMBOLS := $(DEBUG_ALL_BINARIES)))
 
-  $(SUPPORT_OUTPUTDIR)/native/$(MODULE)/libjli_static.a: $(BUILD_LIBJLI_STATIC)
+  ifeq ($(STATIC_BUILD), true)
+    TARGETS += $(BUILD_LIBJLI_STATIC)
+  else
+    $(SUPPORT_OUTPUTDIR)/native/$(MODULE)/libjli_static.a: $(BUILD_LIBJLI_STATIC)
 	$(call install-file)
 
-  TARGETS += $(SUPPORT_OUTPUTDIR)/native/$(MODULE)/libjli_static.a
+    TARGETS += $(SUPPORT_OUTPUTDIR)/native/$(MODULE)/libjli_static.a
+  endif
 
 else ifeq ($(OPENJDK_TARGET_OS), aix)
   # AIX also requires a static libjli because the compiler doesn't support '-rpath'
--- a/make/lib/Lib-java.base.gmk	Tue Nov 10 13:46:45 2015 +0300
+++ b/make/lib/Lib-java.base.gmk	Tue Nov 17 10:29:28 2015 -0800
@@ -1,5 +1,5 @@
 #
-# Copyright (c) 2011, 2014, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2011, 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
@@ -33,3 +33,29 @@
 include NetworkingLibraries.gmk
 include NioLibraries.gmk
 include SecurityLibraries.gmk
+
+ifeq ($(STATIC_BUILD), true)
+  JAVA_BASE_EXPORT_SYMBOLS_SRC := \
+      $(SUPPORT_OUTPUTDIR)/modules_libs/java.base/jli/$(LIBRARY_PREFIX)jli.symbols \
+      $(SUPPORT_OUTPUTDIR)/modules_libs/java.base/$(LIBRARY_PREFIX)java.symbols \
+      $(SUPPORT_OUTPUTDIR)/modules_libs/java.base/$(LIBRARY_PREFIX)net.symbols \
+      $(SUPPORT_OUTPUTDIR)/modules_libs/java.base/$(LIBRARY_PREFIX)nio.symbols \
+      $(SUPPORT_OUTPUTDIR)/modules_libs/java.base/$(LIBRARY_PREFIX)verify.symbols \
+      $(SUPPORT_OUTPUTDIR)/modules_libs/java.base/$(LIBRARY_PREFIX)zip.symbols \
+      $(SUPPORT_OUTPUTDIR)/modules_libs/java.base/$(LIBRARY_PREFIX)jimage.symbols \
+      $(SUPPORT_OUTPUTDIR)/modules_libs/java.base/server/$(LIBRARY_PREFIX)jvm.symbols \
+      #
+
+  JAVA_BASE_EXPORT_SYMBOL_FILE := $(SUPPORT_OUTPUTDIR)/modules_libs/java.base/java.base.symbols
+
+  $(JAVA_BASE_EXPORT_SYMBOL_FILE): $(JAVA_BASE_EXPORT_SYMBOLS_SRC)
+	$(ECHO) $(LOG_INFO) "Generating java.base.symbols file"
+	$(CAT) $^ > $@
+
+  # The individual symbol files is generated when the respective lib is built
+  $(JAVA_BASE_EXPORT_SYMBOLS_SRC): $(BUILD_LIBJLI) $(BUILD_LIBJAVA) \
+      $(BUILD_LIBNET) $(BUILD_LIBNIO) $(BUILD_LIBVERIFY) $(BUILD_LIBZIP) \
+      $(BUILD_LIBJIMAGE)
+
+  TARGETS += $(JAVA_BASE_EXPORT_SYMBOL_FILE)
+endif
--- a/make/lib/Lib-jdk.jdwp.agent.gmk	Tue Nov 10 13:46:45 2015 +0300
+++ b/make/lib/Lib-jdk.jdwp.agent.gmk	Tue Nov 17 10:29:28 2015 -0800
@@ -102,3 +102,23 @@
 TARGETS += $(BUILD_LIBJDWP)
 
 ################################################################################
+
+ifeq ($(STATIC_BUILD), true)
+  JDK_JDWP_AGENT_EXPORT_SYMBOLS_SRC := \
+      $(SUPPORT_OUTPUTDIR)/modules_libs/jdk.jdwp.agent/$(LIBRARY_PREFIX)dt_socket.symbols \
+      $(SUPPORT_OUTPUTDIR)/modules_libs/jdk.jdwp.agent/$(LIBRARY_PREFIX)jdwp.symbols
+
+  JDK_JDWP_AGENT_EXPORT_SYMBOL_FILE := $(SUPPORT_OUTPUTDIR)/modules_libs/jdk.jdwp.agent/jdk.jdwp.agent.symbols
+
+  $(JDK_JDWP_AGENT_EXPORT_SYMBOL_FILE): $(JDK_JDWP_AGENT_EXPORT_SYMBOLS_SRC)
+	$(ECHO) $(LOG_INFO) "Generating jdk.jdwp.agent symbols file"
+	$(CAT) $^ > $@
+
+  # The individual symbol files is generated when the respective lib is built
+  $(JDK_JDWP_AGENT_EXPORT_SYMBOLS_SRC): $(BUILD_LIBDT_SOCKET) $(BUILD_LIBJDWP)
+
+  TARGETS += $(JDK_JDWP_AGENT_EXPORT_SYMBOL_FILE)
+
+endif
+
+################################################################################
--- a/make/lib/SecurityLibraries.gmk	Tue Nov 10 13:46:45 2015 +0300
+++ b/make/lib/SecurityLibraries.gmk	Tue Nov 17 10:29:28 2015 -0800
@@ -26,38 +26,41 @@
 include LibCommon.gmk
 
 ifeq ($(OPENJDK_TARGET_OS), macosx)
+  # JavaNativeFoundation framework not supported in static builds 
+  ifneq ($(STATIC_BUILD), true)
 
   ################################################################################
 
-  LIBOSXSECURITY_DIRS := $(JDK_TOPDIR)/src/java.base/macosx/native/libosxsecurity
-  LIBOSXSECURITY_CFLAGS := -I$(LIBOSXSECURITY_DIRS) \
-      $(LIBJAVA_HEADER_FLAGS) \
-      -I$(SUPPORT_OUTPUTDIR)/headers/java.base \
+    LIBOSXSECURITY_DIRS := $(JDK_TOPDIR)/src/java.base/macosx/native/libosxsecurity
+    LIBOSXSECURITY_CFLAGS := -I$(LIBOSXSECURITY_DIRS) \
+        $(LIBJAVA_HEADER_FLAGS) \
+        -I$(SUPPORT_OUTPUTDIR)/headers/java.base \
 
-  $(eval $(call SetupNativeCompilation,BUILD_LIBOSXSECURITY, \
-      LIBRARY := osxsecurity, \
-      OUTPUT_DIR := $(INSTALL_LIBRARIES_HERE), \
-      SRC := $(LIBOSXSECURITY_DIRS), \
-      OPTIMIZATION := LOW, \
-      CFLAGS := $(CFLAGS_JDKLIB) \
-          $(LIBOSXSECURITY_CFLAGS), \
-      DISABLED_WARNINGS_clang := deprecated-declarations, \
-      LDFLAGS := $(LDFLAGS_JDKLIB) \
-          -L$(SUPPORT_OUTPUTDIR)/modules_libs/java.base \
-          $(call SET_SHARED_LIBRARY_ORIGIN) \
-          -fobjc-link-runtime, \
-      LIBS := \
-          -framework JavaNativeFoundation \
-          -framework CoreServices \
-          -framework Security \
-          $(JDKLIB_LIBS), \
-      OBJECT_DIR := $(SUPPORT_OUTPUTDIR)/native/$(MODULE)/libosxsecurity, \
-      DEBUG_SYMBOLS := $(DEBUG_ALL_BINARIES)))
+    $(eval $(call SetupNativeCompilation,BUILD_LIBOSXSECURITY, \
+        LIBRARY := osxsecurity, \
+        OUTPUT_DIR := $(INSTALL_LIBRARIES_HERE), \
+        SRC := $(LIBOSXSECURITY_DIRS), \
+        OPTIMIZATION := LOW, \
+        CFLAGS := $(CFLAGS_JDKLIB) \
+            $(LIBOSXSECURITY_CFLAGS), \
+        DISABLED_WARNINGS_clang := deprecated-declarations, \
+        LDFLAGS := $(LDFLAGS_JDKLIB) \
+            -L$(SUPPORT_OUTPUTDIR)/modules_libs/java.base \
+            $(call SET_SHARED_LIBRARY_ORIGIN) \
+            -fobjc-link-runtime, \
+        LIBS := \
+            -framework JavaNativeFoundation \
+            -framework CoreServices \
+            -framework Security \
+            $(JDKLIB_LIBS), \
+        OBJECT_DIR := $(SUPPORT_OUTPUTDIR)/native/$(MODULE)/libosxsecurity, \
+        DEBUG_SYMBOLS := $(DEBUG_ALL_BINARIES)))
 
-  $(BUILD_LIBOSXSECURITY): $(BUILD_LIBJAVA)
+    $(BUILD_LIBOSXSECURITY): $(BUILD_LIBJAVA)
 
-  TARGETS += $(BUILD_LIBOSXSECURITY)
+    TARGETS += $(BUILD_LIBOSXSECURITY)
 
   ################################################################################
 
+  endif
 endif
--- a/make/mapfiles/libjava/mapfile-vers	Tue Nov 10 13:46:45 2015 +0300
+++ b/make/mapfiles/libjava/mapfile-vers	Tue Nov 17 10:29:28 2015 -0800
@@ -211,6 +211,7 @@
 		Java_java_lang_SecurityManager_getClassContext;
 		Java_java_lang_Shutdown_halt0;
 		Java_java_lang_String_intern;
+		Java_java_lang_StringUTF16_isBigEndian;
 		Java_java_lang_System_identityHashCode;
 		Java_java_lang_System_initProperties;
 		Java_java_lang_System_mapLibraryName;
--- a/make/mapfiles/libjava/reorder-sparc	Tue Nov 10 13:46:45 2015 +0300
+++ b/make/mapfiles/libjava/reorder-sparc	Tue Nov 17 10:29:28 2015 -0800
@@ -57,6 +57,7 @@
 text: .text%JNU_ClassString;
 text: .text%JNU_CopyObjectArray;
 text: .text%Java_java_lang_String_intern;
+text: .text%Java_java_lang_StringUTF16_isBigEndian;
 text: .text%Java_java_lang_ClassLoader_findLoadedClass0;
 text: .text%Java_java_lang_ClassLoader_findBootstrapClass;
 text: .text%Java_java_lang_Throwable_fillInStackTrace;
--- a/make/mapfiles/libjava/reorder-sparcv9	Tue Nov 10 13:46:45 2015 +0300
+++ b/make/mapfiles/libjava/reorder-sparcv9	Tue Nov 17 10:29:28 2015 -0800
@@ -29,6 +29,7 @@
 text: .text%Java_sun_reflect_Reflection_getCallerClass__I;
 text: .text%Java_java_lang_Class_forName0;
 text: .text%Java_java_lang_String_intern;
+text: .text%Java_java_lang_StringUTF16_isBigEndian;
 text: .text%Java_java_lang_Float_floatToRawIntBits;
 text: .text%Java_java_lang_Double_doubleToRawLongBits;
 text: .text%Java_java_lang_ClassLoader_findLoadedClass0;
--- a/make/mapfiles/libjava/reorder-x86	Tue Nov 10 13:46:45 2015 +0300
+++ b/make/mapfiles/libjava/reorder-x86	Tue Nov 17 10:29:28 2015 -0800
@@ -31,6 +31,7 @@
 text: .text%Java_sun_reflect_Reflection_getCallerClass__I;
 text: .text%Java_java_lang_Class_forName0;
 text: .text%Java_java_lang_String_intern;
+text: .text%Java_java_lang_StringUTF16_isBigEndian;
 text: .text%Java_sun_reflect_NativeConstructorAccessorImpl_newInstance0;
 text: .text%Java_java_lang_Throwable_fillInStackTrace;
 text: .text%Java_java_lang_System_setOut0;
--- a/make/mapfiles/libnio/mapfile-macosx	Tue Nov 10 13:46:45 2015 +0300
+++ b/make/mapfiles/libnio/mapfile-macosx	Tue Nov 17 10:29:28 2015 -0800
@@ -75,6 +75,7 @@
                 Java_sun_nio_ch_IOUtil_makePipe;
                 Java_sun_nio_ch_IOUtil_randomBytes;
                 Java_sun_nio_ch_IOUtil_setfdVal;
+                Java_sun_nio_ch_IOUtil_iovMax;
 		Java_sun_nio_ch_KQueue_kqueue;
 		Java_sun_nio_ch_KQueue_keventRegister;
 		Java_sun_nio_ch_KQueue_keventPoll;
--- a/make/src/classes/build/tools/charsetmapping/DBCS.java	Tue Nov 10 13:46:45 2015 +0300
+++ b/make/src/classes/build/tools/charsetmapping/DBCS.java	Tue Nov 17 10:29:28 2015 -0800
@@ -197,6 +197,7 @@
                        .replace("$B1MAX$"   , "0x" + Integer.toString(b1Max, 16))
                        .replace("$B2MIN$"   , "0x" + Integer.toString(b2Min, 16))
                        .replace("$B2MAX$"   , "0x" + Integer.toString(b2Max, 16))
+                       .replace("$ASCIICOMPATIBLE$", isASCII ? "true" : "false")
                        .replace("$B2C$", b2c)
                        .replace("$C2BLENGTH$", "0x" + Integer.toString(c2bOff, 16))
                        .replace("$NONROUNDTRIP_B2C$", b2cNR)
--- a/make/src/classes/build/tools/charsetmapping/SBCS.java	Tue Nov 10 13:46:45 2015 +0300
+++ b/make/src/classes/build/tools/charsetmapping/SBCS.java	Tue Nov 17 10:29:28 2015 -0800
@@ -175,6 +175,9 @@
                 else
                     line = "        return (cs instanceof " + clzName + ");";
             }
+            if (line.indexOf("$ASCIICOMPATIBLE$") != -1) {
+                line = line.replace("$ASCIICOMPATIBLE$", isASCII ? "true" : "false");
+            }
             if (line.indexOf("$B2CTABLE$") != -1) {
                 line = line.replace("$B2CTABLE$", b2c);
             }
--- a/make/src/classes/build/tools/x11wrappergen/WrapperGenerator.java	Tue Nov 10 13:46:45 2015 +0300
+++ b/make/src/classes/build/tools/x11wrappergen/WrapperGenerator.java	Tue Nov 17 10:29:28 2015 -0800
@@ -841,7 +841,7 @@
                 pw.println("// This file is an automatically generated file, please do not edit this file, modify the WrapperGenerator.java file instead !\n" );
 
                 pw.println("package "+package_name+";\n");
-                pw.println("import sun.misc.*;\n");
+                pw.println("import jdk.internal.misc.Unsafe;\n");
                 pw.println("import sun.util.logging.PlatformLogger;");
                 String baseClass = stp.getBaseClass();
                 if (baseClass == null) {
@@ -941,7 +941,7 @@
             pw.println("// This file is an automatically generated file, please do not edit this file, modify the WrapperGenerator.java file instead !\n" );
 
             pw.println("package "+package_name+";\n");
-            pw.println("import sun.misc.Unsafe;\n");
+            pw.println("import jdk.internal.misc.Unsafe;\n");
             pw.println("class " + ft.getName() + " {");
             pw.println("\tprivate static Unsafe unsafe = XlibWrapper.unsafe;");
             pw.println("\tprivate boolean __executed = false;");
--- a/src/demo/share/jvmti/agent_util/agent_util.h	Tue Nov 10 13:46:45 2015 +0300
+++ b/src/demo/share/jvmti/agent_util/agent_util.h	Tue Nov 17 10:29:28 2015 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2004, 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2004, 2015, Oracle and/or its affiliates. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -65,6 +65,51 @@
 void *allocate(jvmtiEnv *jvmti, jint len);
 void  add_demo_jar_to_bootclasspath(jvmtiEnv *jvmti, char *demo_name);
 
+#ifdef STATIC_BUILD
+/* Macros for handling declaration of static/dynamic
+ * Agent library Load/Attach/Unload functions
+ *
+ * DEF_Agent_OnLoad, DEF_Agent_OnAttach or DEF_Agent_OnUnload
+ * generate the appropriate entrypoint names based on static
+ * versus dynamic builds.
+ *
+ * STATIC_BUILD must be defined to build static versions of these libraries.
+ * LIBRARY_NAME must be set to the name of the library for static builds.
+ */
+#define ADD_LIB_NAME3(name, lib) name ## lib
+#define ADD_LIB_NAME2(name, lib) ADD_LIB_NAME3(name, lib)
+#define ADD_LIB_NAME(entry) ADD_LIB_NAME2(entry, LIBRARY_NAME)
+
+#define DEF_Agent_OnLoad \
+ADD_LIB_NAME(Agent_OnLoad_)(JavaVM *vm, char *options, void *reserved) \
+{ \
+  jint JNICALL ADD_LIB_NAME(Agent_OnLoad_dynamic_)(JavaVM *vm, char *options, void *reserved); \
+  return ADD_LIB_NAME(Agent_OnLoad_dynamic_)(vm, options, reserved); \
+} \
+jint JNICALL ADD_LIB_NAME(Agent_OnLoad_dynamic_)
+
+#define DEF_Agent_OnAttach \
+ADD_LIB_NAME(Agent_OnAttach_)(JavaVM *vm, char *options, void *reserved) \
+{ \
+  jint JNICALL ADD_LIB_NAME(Agent_OnAttach_dynamic_)(JavaVM *vm, char *options, void *reserved); \
+  return ADD_LIB_NAME(Agent_OnAttach_dynamic_)(vm, options, reserved); \
+} \
+jint JNICALL ADD_LIB_NAME(Agent_OnAttach_dynamic_)
+
+#define DEF_Agent_OnUnload \
+ADD_LIB_NAME(Agent_OnUnload_)(JavaVM *vm) \
+{ \
+  void JNICALL ADD_LIB_NAME(Agent_OnUnload_dynamic_)(JavaVM *vm); \
+  ADD_LIB_NAME(Agent_OnUnload_dynamic_)(vm); \
+} \
+void JNICALL ADD_LIB_NAME(Agent_OnUnload_dynamic_)
+
+#else
+#define DEF_Agent_OnLoad Agent_OnLoad
+#define DEF_Agent_OnAttach Agent_OnAttach
+#define DEF_Agent_OnUnload Agent_OnUnload
+#endif
+
 #ifdef __cplusplus
 } /* extern "C" */
 #endif /* __cplusplus */
--- a/src/demo/share/jvmti/compiledMethodLoad/compiledMethodLoad.c	Tue Nov 10 13:46:45 2015 +0300
+++ b/src/demo/share/jvmti/compiledMethodLoad/compiledMethodLoad.c	Tue Nov 17 10:29:28 2015 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2010, 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2010, 2015, Oracle and/or its affiliates. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -225,7 +225,7 @@
  * event here.
  */
 JNIEXPORT jint JNICALL
-Agent_OnLoad(JavaVM *vm, char *options, void *reserved)
+DEF_Agent_OnLoad(JavaVM *vm, char *options, void *reserved)
 {
     jint                rc;
     jvmtiError          err;
@@ -272,6 +272,6 @@
 
 /* Agent_OnUnload() is called last */
 JNIEXPORT void JNICALL
-Agent_OnUnload(JavaVM *vm)
+DEF_Agent_OnUnload(JavaVM *vm)
 {
 }
--- a/src/demo/share/jvmti/gctest/gctest.c	Tue Nov 10 13:46:45 2015 +0300
+++ b/src/demo/share/jvmti/gctest/gctest.c	Tue Nov 17 10:29:28 2015 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2004, 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2004, 2015, Oracle and/or its affiliates. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -148,7 +148,7 @@
 
 /* Agent_OnLoad() is called first, we prepare for a VM_INIT event here. */
 JNIEXPORT jint JNICALL
-Agent_OnLoad(JavaVM *vm, char *options, void *reserved)
+DEF_Agent_OnLoad(JavaVM *vm, char *options, void *reserved)
 {
     jint                rc;
     jvmtiError          err;
@@ -193,6 +193,6 @@
 
 /* Agent_OnUnload() is called last */
 JNIEXPORT void JNICALL
-Agent_OnUnload(JavaVM *vm)
+DEF_Agent_OnUnload(JavaVM *vm)
 {
 }
--- a/src/demo/share/jvmti/heapTracker/heapTracker.c	Tue Nov 10 13:46:45 2015 +0300
+++ b/src/demo/share/jvmti/heapTracker/heapTracker.c	Tue Nov 17 10:29:28 2015 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2004, 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2004, 2015, Oracle and/or its affiliates. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -894,7 +894,7 @@
  *   loaded. This is the first code executed.
  */
 JNIEXPORT jint JNICALL
-Agent_OnLoad(JavaVM *vm, char *options, void *reserved)
+DEF_Agent_OnLoad(JavaVM *vm, char *options, void *reserved)
 {
     static GlobalAgentData data;
     jvmtiEnv              *jvmti;
@@ -1010,7 +1010,7 @@
  *   unloaded. This is the last code executed.
  */
 JNIEXPORT void JNICALL
-Agent_OnUnload(JavaVM *vm)
+DEF_Agent_OnUnload(JavaVM *vm)
 {
     /* Skip any cleanup, VM is about to die anyway */
 }
--- a/src/demo/share/jvmti/heapTracker/heapTracker.h	Tue Nov 10 13:46:45 2015 +0300
+++ b/src/demo/share/jvmti/heapTracker/heapTracker.h	Tue Nov 17 10:29:28 2015 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2004, 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2004, 2015, Oracle and/or its affiliates. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -64,9 +64,4 @@
 
 #include "agent_util.h"
 
-/* Agent library externals to export. */
-
-JNIEXPORT jint JNICALL Agent_OnLoad(JavaVM *vm, char *options, void *reserved);
-JNIEXPORT void JNICALL Agent_OnUnload(JavaVM *vm);
-
 #endif
--- a/src/demo/share/jvmti/heapViewer/heapViewer.c	Tue Nov 10 13:46:45 2015 +0300
+++ b/src/demo/share/jvmti/heapViewer/heapViewer.c	Tue Nov 17 10:29:28 2015 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2004, 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2004, 2015, Oracle and/or its affiliates. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -235,7 +235,7 @@
 
 /* Agent_OnLoad() is called first, we prepare for a VM_INIT event here. */
 JNIEXPORT jint JNICALL
-Agent_OnLoad(JavaVM *vm, char *options, void *reserved)
+DEF_Agent_OnLoad(JavaVM *vm, char *options, void *reserved)
 {
     jint                rc;
     jvmtiError          err;
@@ -283,6 +283,6 @@
 
 /* Agent_OnUnload() is called last */
 JNIEXPORT void JNICALL
-Agent_OnUnload(JavaVM *vm)
+DEF_Agent_OnUnload(JavaVM *vm)
 {
 }
--- a/src/demo/share/jvmti/minst/minst.c	Tue Nov 10 13:46:45 2015 +0300
+++ b/src/demo/share/jvmti/minst/minst.c	Tue Nov 17 10:29:28 2015 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2006, 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2006, 2015, Oracle and/or its affiliates. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -373,7 +373,7 @@
  *   loaded. This is the first code executed.
  */
 JNIEXPORT jint JNICALL
-Agent_OnLoad(JavaVM *vm, char *options, void *reserved)
+DEF_Agent_OnLoad(JavaVM *vm, char *options, void *reserved)
 {
     static GlobalAgentData data;
     jvmtiEnv              *jvmti;
@@ -467,7 +467,7 @@
  *   unloaded. This is the last code executed.
  */
 JNIEXPORT void JNICALL
-Agent_OnUnload(JavaVM *vm)
+DEF_Agent_OnUnload(JavaVM *vm)
 {
     /* Make sure all malloc/calloc/strdup space is freed */
     if ( gdata->include != NULL ) {
--- a/src/demo/share/jvmti/minst/minst.h	Tue Nov 10 13:46:45 2015 +0300
+++ b/src/demo/share/jvmti/minst/minst.h	Tue Nov 17 10:29:28 2015 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2006, 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2006, 2015, Oracle and/or its affiliates. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -64,9 +64,4 @@
 
 #include "agent_util.h"
 
-/* Agent library externals to export. */
-
-JNIEXPORT jint JNICALL Agent_OnLoad(JavaVM *vm, char *options, void *reserved);
-JNIEXPORT void JNICALL Agent_OnUnload(JavaVM *vm);
-
 #endif
--- a/src/demo/share/jvmti/mtrace/mtrace.c	Tue Nov 10 13:46:45 2015 +0300
+++ b/src/demo/share/jvmti/mtrace/mtrace.c	Tue Nov 17 10:29:28 2015 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2004, 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2004, 2015, Oracle and/or its affiliates. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -697,7 +697,7 @@
  *   loaded. This is the first code executed.
  */
 JNIEXPORT jint JNICALL
-Agent_OnLoad(JavaVM *vm, char *options, void *reserved)
+DEF_Agent_OnLoad(JavaVM *vm, char *options, void *reserved)
 {
     static GlobalAgentData data;
     jvmtiEnv              *jvmti;
@@ -795,7 +795,7 @@
  *   unloaded. This is the last code executed.
  */
 JNIEXPORT void JNICALL
-Agent_OnUnload(JavaVM *vm)
+DEF_Agent_OnUnload(JavaVM *vm)
 {
     /* Make sure all malloc/calloc/strdup space is freed */
     if ( gdata->include != NULL ) {
--- a/src/demo/share/jvmti/mtrace/mtrace.h	Tue Nov 10 13:46:45 2015 +0300
+++ b/src/demo/share/jvmti/mtrace/mtrace.h	Tue Nov 17 10:29:28 2015 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2004, 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2004, 2015, Oracle and/or its affiliates. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -64,9 +64,4 @@
 
 #include "agent_util.h"
 
-/* Agent library externals to export. */
-
-JNIEXPORT jint JNICALL Agent_OnLoad(JavaVM *vm, char *options, void *reserved);
-JNIEXPORT void JNICALL Agent_OnUnload(JavaVM *vm);
-
 #endif
--- a/src/demo/share/jvmti/versionCheck/versionCheck.c	Tue Nov 10 13:46:45 2015 +0300
+++ b/src/demo/share/jvmti/versionCheck/versionCheck.c	Tue Nov 17 10:29:28 2015 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2004, 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2004, 2015, Oracle and/or its affiliates. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -89,7 +89,7 @@
 
 /* Agent_OnLoad() is called first, we prepare for a VM_INIT event here. */
 JNIEXPORT jint JNICALL
-Agent_OnLoad(JavaVM *vm, char *options, void *reserved)
+DEF_Agent_OnLoad(JavaVM *vm, char *options, void *reserved)
 {
     jint                rc;
     jvmtiError          err;
@@ -116,6 +116,6 @@
 
 /* Agent_OnUnload() is called last */
 JNIEXPORT void JNICALL
-Agent_OnUnload(JavaVM *vm)
+DEF_Agent_OnUnload(JavaVM *vm)
 {
 }
--- a/src/demo/share/jvmti/waiters/Monitor.hpp	Tue Nov 10 13:46:45 2015 +0300
+++ b/src/demo/share/jvmti/waiters/Monitor.hpp	Tue Nov 17 10:29:28 2015 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2004, 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2004, 2015, Oracle and/or its affiliates. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -37,6 +37,10 @@
  * this sample code.
  */
 
+#ifdef STATIC_BUILD
+#define Monitor WaiterMonitor
+#endif
+
 
 /* C++ Monitor class */
 
--- a/src/demo/share/jvmti/waiters/Thread.cpp	Tue Nov 10 13:46:45 2015 +0300
+++ b/src/demo/share/jvmti/waiters/Thread.cpp	Tue Nov 17 10:29:28 2015 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2004, 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2004, 2015, Oracle and/or its affiliates. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -37,6 +37,9 @@
  * this sample code.
  */
 
+#ifdef STATIC_BUILD
+#define Thread WaiterThread
+#endif
 
 #include <stdio.h>
 #include <stdlib.h>
--- a/src/demo/share/jvmti/waiters/waiters.cpp	Tue Nov 10 13:46:45 2015 +0300
+++ b/src/demo/share/jvmti/waiters/waiters.cpp	Tue Nov 17 10:29:28 2015 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2004, 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2004, 2015, Oracle and/or its affiliates. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -243,7 +243,7 @@
 
     /* Agent_OnLoad() is called first, we prepare for a VM_INIT event here. */
     JNIEXPORT jint JNICALL
-    Agent_OnLoad(JavaVM *vm, char *options, void *reserved)
+    DEF_Agent_OnLoad(JavaVM *vm, char *options, void *reserved)
     {
         jvmtiEnv           *jvmti;
         jint                rc;
@@ -288,7 +288,7 @@
 
     /* Agent_OnUnload() is called last */
     JNIEXPORT void JNICALL
-    Agent_OnUnload(JavaVM *vm)
+    DEF_Agent_OnUnload(JavaVM *vm)
     {
     }
 
--- a/src/java.base/aix/classes/sun/nio/ch/AixPollPort.java	Tue Nov 10 13:46:45 2015 +0300
+++ b/src/java.base/aix/classes/sun/nio/ch/AixPollPort.java	Tue Nov 17 10:29:28 2015 -0800
@@ -34,7 +34,7 @@
 import java.util.concurrent.RejectedExecutionException;
 import java.util.concurrent.atomic.AtomicInteger;
 import java.util.concurrent.locks.ReentrantLock;
-import sun.misc.Unsafe;
+import jdk.internal.misc.Unsafe;
 
 /**
  * AsynchronousChannelGroup implementation based on the AIX pollset framework.
--- a/src/java.base/linux/classes/sun/nio/ch/EPoll.java	Tue Nov 10 13:46:45 2015 +0300
+++ b/src/java.base/linux/classes/sun/nio/ch/EPoll.java	Tue Nov 17 10:29:28 2015 -0800
@@ -26,7 +26,7 @@
 package sun.nio.ch;
 
 import java.io.IOException;
-import sun.misc.Unsafe;
+import jdk.internal.misc.Unsafe;
 
 /**
  * Provides access to the Linux epoll facility.
--- a/src/java.base/linux/classes/sun/nio/fs/LinuxDosFileAttributeView.java	Tue Nov 10 13:46:45 2015 +0300
+++ b/src/java.base/linux/classes/sun/nio/fs/LinuxDosFileAttributeView.java	Tue Nov 17 10:29:28 2015 -0800
@@ -29,7 +29,7 @@
 import java.util.Map;
 import java.util.Set;
 import java.io.IOException;
-import sun.misc.Unsafe;
+import jdk.internal.misc.Unsafe;
 
 import static sun.nio.fs.UnixNativeDispatcher.*;
 import static sun.nio.fs.UnixConstants.*;
--- a/src/java.base/linux/classes/sun/nio/fs/LinuxUserDefinedFileAttributeView.java	Tue Nov 10 13:46:45 2015 +0300
+++ b/src/java.base/linux/classes/sun/nio/fs/LinuxUserDefinedFileAttributeView.java	Tue Nov 17 10:29:28 2015 -0800
@@ -29,7 +29,7 @@
 import java.nio.ByteBuffer;
 import java.io.IOException;
 import java.util.*;
-import sun.misc.Unsafe;
+import jdk.internal.misc.Unsafe;
 
 import static sun.nio.fs.UnixConstants.*;
 import static sun.nio.fs.LinuxNativeDispatcher.*;
--- a/src/java.base/linux/classes/sun/nio/fs/LinuxWatchService.java	Tue Nov 10 13:46:45 2015 +0300
+++ b/src/java.base/linux/classes/sun/nio/fs/LinuxWatchService.java	Tue Nov 17 10:29:28 2015 -0800
@@ -30,7 +30,7 @@
 import java.security.PrivilegedAction;
 import java.util.*;
 import java.io.IOException;
-import sun.misc.Unsafe;
+import jdk.internal.misc.Unsafe;
 
 import static sun.nio.fs.UnixNativeDispatcher.*;
 import static sun.nio.fs.UnixConstants.*;
--- a/src/java.base/macosx/classes/sun/nio/ch/KQueue.java	Tue Nov 10 13:46:45 2015 +0300
+++ b/src/java.base/macosx/classes/sun/nio/ch/KQueue.java	Tue Nov 17 10:29:28 2015 -0800
@@ -26,7 +26,7 @@
 package sun.nio.ch;
 
 import java.io.IOException;
-import sun.misc.Unsafe;
+import jdk.internal.misc.Unsafe;
 
 /**
  * Provides access to the BSD kqueue facility.
--- a/src/java.base/macosx/native/libjava/java_props_macosx.c	Tue Nov 10 13:46:45 2015 +0300
+++ b/src/java.base/macosx/native/libjava/java_props_macosx.c	Tue Nov 17 10:29:28 2015 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1998, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1998, 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
@@ -35,13 +35,15 @@
 
 #include "java_props_macosx.h"
 
-
 // need dlopen/dlsym trick to avoid pulling in JavaRuntimeSupport before libjava.dylib is loaded
 static void *getJRSFramework() {
     static void *jrsFwk = NULL;
+#ifndef STATIC_BUILD
+// JavaRuntimeSupport doesn't support static Java runtimes
     if (jrsFwk == NULL) {
        jrsFwk = dlopen("/System/Library/Frameworks/JavaVM.framework/Frameworks/JavaRuntimeSupport.framework/JavaRuntimeSupport", RTLD_LAZY | RTLD_LOCAL);
     }
+#endif
     return jrsFwk;
 }
 
--- a/src/java.base/macosx/native/libjli/java_md_macosx.c	Tue Nov 10 13:46:45 2015 +0300
+++ b/src/java.base/macosx/native/libjli/java_md_macosx.c	Tue Nov 17 10:29:28 2015 -0800
@@ -245,6 +245,8 @@
     return sExportedJNIFunctions = fxns;
 }
 
+#ifndef STATIC_BUILD
+
 JNIEXPORT jint JNICALL
 JNI_GetDefaultJavaVMInitArgs(void *args) {
     InvocationFunctions *ifn = GetExportedJNIFunctions();
@@ -265,6 +267,7 @@
     if (ifn == NULL) return JNI_ERR;
     return ifn->GetCreatedJavaVMs(vmBuf, bufLen, nVMs);
 }
+#endif
 
 /*
  * Allow JLI-aware launchers to specify a client/server preference
@@ -303,7 +306,12 @@
     objc_registerThreadWithCollector();
 
     if (main_fptr == NULL) {
+#ifdef STATIC_BUILD
+        extern int main(int argc, char **argv);
+        main_fptr = &main;
+#else
         main_fptr = (int (*)())dlsym(RTLD_DEFAULT, "main");
+#endif
         if (main_fptr == NULL) {
             JLI_ReportErrorMessageSys("error locating main entrypoint\n");
             exit(1);
@@ -588,6 +596,9 @@
 
     JLI_TraceLauncher("Does `%s' exist ... ", jvmpath);
 
+#ifdef STATIC_BUILD
+    return JNI_TRUE;
+#else
     if (stat(jvmpath, &s) == 0) {
         JLI_TraceLauncher("yes.\n");
         return JNI_TRUE;
@@ -595,6 +606,7 @@
         JLI_TraceLauncher("no.\n");
         return JNI_FALSE;
     }
+#endif
 }
 
 /*
@@ -607,10 +619,18 @@
 
     if (GetApplicationHome(path, pathsize)) {
         /* Is JRE co-located with the application? */
+#ifdef STATIC_BUILD
+        char jvm_cfg[MAXPATHLEN];
+        JLI_Snprintf(jvm_cfg, sizeof(jvm_cfg), "%s/lib/jvm.cfg", path);
+        if (access(jvm_cfg, F_OK) == 0) {
+            return JNI_TRUE;
+        }
+#else
         JLI_Snprintf(libjava, sizeof(libjava), "%s/lib/" JAVA_DLL, path);
         if (access(libjava, F_OK) == 0) {
             return JNI_TRUE;
         }
+#endif
         /* ensure storage for path + /jre + NULL */
         if ((JLI_StrLen(path) + 4 + 1) > (size_t) pathsize) {
             JLI_TraceLauncher("Insufficient space to store JRE path\n");
@@ -629,6 +649,24 @@
     Dl_info selfInfo;
     dladdr(&GetJREPath, &selfInfo);
 
+#ifdef STATIC_BUILD
+    char jvm_cfg[MAXPATHLEN];
+    char *p = NULL;
+    strncpy(jvm_cfg, selfInfo.dli_fname, MAXPATHLEN);
+    p = strrchr(jvm_cfg, '/'); *p = '\0';
+    p = strrchr(jvm_cfg, '/');
+    if (strcmp(p, "/.") == 0) {
+      *p = '\0';
+      p = strrchr(jvm_cfg, '/'); *p = '\0';
+    }
+    else *p = '\0';
+    strncpy(path, jvm_cfg, pathsize);
+    strncat(jvm_cfg, "/lib/jvm.cfg", MAXPATHLEN);
+    if (access(jvm_cfg, F_OK) == 0) {
+      return JNI_TRUE;
+    }
+#endif
+
     char *realPathToSelf = realpath(selfInfo.dli_fname, path);
     if (realPathToSelf != path) {
         return JNI_FALSE;
@@ -664,7 +702,11 @@
 
     JLI_TraceLauncher("JVM path is %s\n", jvmpath);
 
+#ifndef STATIC_BUILD
     libjvm = dlopen(jvmpath, RTLD_NOW + RTLD_GLOBAL);
+#else
+    libjvm = dlopen(NULL, RTLD_FIRST);
+#endif
     if (libjvm == NULL) {
         JLI_ReportErrorMessage(DLL_ERROR1, __LINE__);
         JLI_ReportErrorMessage(DLL_ERROR2, jvmpath, dlerror());
@@ -714,9 +756,14 @@
     char* exec_path = NULL;
     {
         Dl_info dlinfo;
+
+#ifdef STATIC_BUILD
+        void *fptr;
+        fptr = (void *)&SetExecname;
+#else
         int (*fptr)();
-
         fptr = (int (*)())dlsym(RTLD_DEFAULT, "main");
+#endif
         if (fptr == NULL) {
             JLI_ReportErrorMessage(DLL_ERROR3, dlerror());
             return JNI_FALSE;
--- a/src/java.base/share/classes/java/io/File.java	Tue Nov 10 13:46:45 2015 +0300
+++ b/src/java.base/share/classes/java/io/File.java	Tue Nov 17 10:29:28 2015 -0800
@@ -2184,10 +2184,10 @@
 
     private static final long PATH_OFFSET;
     private static final long PREFIX_LENGTH_OFFSET;
-    private static final sun.misc.Unsafe UNSAFE;
+    private static final jdk.internal.misc.Unsafe UNSAFE;
     static {
         try {
-            sun.misc.Unsafe unsafe = sun.misc.Unsafe.getUnsafe();
+            jdk.internal.misc.Unsafe unsafe = jdk.internal.misc.Unsafe.getUnsafe();
             PATH_OFFSET = unsafe.objectFieldOffset(
                     File.class.getDeclaredField("path"));
             PREFIX_LENGTH_OFFSET = unsafe.objectFieldOffset(
--- a/src/java.base/share/classes/java/io/ObjectInputStream.java	Tue Nov 10 13:46:45 2015 +0300
+++ b/src/java.base/share/classes/java/io/ObjectInputStream.java	Tue Nov 17 10:29:28 2015 -0800
@@ -40,7 +40,7 @@
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.ConcurrentMap;
 import static java.io.ObjectStreamClass.processQueue;
-import sun.misc.Unsafe;
+import jdk.internal.misc.Unsafe;
 import sun.reflect.misc.ReflectUtil;
 
 /**
--- a/src/java.base/share/classes/java/io/ObjectStreamClass.java	Tue Nov 10 13:46:45 2015 +0300
+++ b/src/java.base/share/classes/java/io/ObjectStreamClass.java	Tue Nov 17 10:29:28 2015 -0800
@@ -48,7 +48,7 @@
 import java.util.Set;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.ConcurrentMap;
-import sun.misc.Unsafe;
+import jdk.internal.misc.Unsafe;
 import sun.reflect.CallerSensitive;
 import sun.reflect.Reflection;
 import sun.reflect.ReflectionFactory;
--- a/src/java.base/share/classes/java/lang/AbstractStringBuilder.java	Tue Nov 10 13:46:45 2015 +0300
+++ b/src/java.base/share/classes/java/lang/AbstractStringBuilder.java	Tue Nov 17 10:29:28 2015 -0800
@@ -31,6 +31,12 @@
 import java.util.stream.IntStream;
 import java.util.stream.StreamSupport;
 
+import static java.lang.String.COMPACT_STRINGS;
+import static java.lang.String.UTF16;
+import static java.lang.String.LATIN1;
+import static java.lang.String.checkIndex;
+import static java.lang.String.checkOffset;
+
 /**
  * A mutable sequence of characters.
  * <p>
@@ -51,7 +57,12 @@
     /**
      * The value is used for character storage.
      */
-    char[] value;
+    byte[] value;
+
+    /**
+     * The id of the encoding used to encode the bytes in {@code value}.
+     */
+    byte coder;
 
     /**
      * The count is the number of characters used.
@@ -68,7 +79,13 @@
      * Creates an AbstractStringBuilder of the specified capacity.
      */
     AbstractStringBuilder(int capacity) {
-        value = new char[capacity];
+        if (COMPACT_STRINGS) {
+            value = new byte[capacity];
+            coder = LATIN1;
+        } else {
+            value = StringUTF16.newBytesFor(capacity);
+            coder = UTF16;
+        }
     }
 
     /**
@@ -90,7 +107,7 @@
      * @return  the current capacity
      */
     public int capacity() {
-        return value.length;
+        return value.length >> coder;
     }
 
     /**
@@ -110,8 +127,9 @@
      * @param   minimumCapacity   the minimum desired capacity.
      */
     public void ensureCapacity(int minimumCapacity) {
-        if (minimumCapacity > 0)
+        if (minimumCapacity > 0) {
             ensureCapacityInternal(minimumCapacity);
+        }
     }
 
     /**
@@ -120,24 +138,48 @@
      */
     private void ensureCapacityInternal(int minimumCapacity) {
         // overflow-conscious code
-        if (minimumCapacity - value.length > 0)
+        int capacity = value.length >> coder;
+        if (minimumCapacity - capacity > 0) {
             expandCapacity(minimumCapacity);
+        }
     }
 
     /**
      * This implements the expansion semantics of ensureCapacity with no
      * size check or synchronization.
      */
-    void expandCapacity(int minimumCapacity) {
-        int newCapacity = value.length * 2 + 2;
-        if (newCapacity - minimumCapacity < 0)
+    private void expandCapacity(int minimumCapacity) {
+        int newCapacity = (value.length >> coder) * 2 + 2;
+        if (newCapacity - minimumCapacity < 0) {
             newCapacity = minimumCapacity;
+        }
         if (newCapacity < 0) {
-            if (minimumCapacity < 0) // overflow
+            if (minimumCapacity < 0) {// overflow
                 throw new OutOfMemoryError();
+            }
             newCapacity = Integer.MAX_VALUE;
         }
-        value = Arrays.copyOf(value, newCapacity);
+        if (coder != LATIN1 && newCapacity > StringUTF16.MAX_LENGTH) {
+            if (minimumCapacity >= StringUTF16.MAX_LENGTH) {
+                throw new OutOfMemoryError();
+            }
+            newCapacity = StringUTF16.MAX_LENGTH;
+        }
+        this.value = Arrays.copyOf(value, newCapacity << coder);
+    }
+
+    /**
+     * If the coder is "isLatin1", this inflates the internal 8-bit storage
+     * to 16-bit <hi=0, low> pair storage.
+     */
+    private void inflate() {
+        if (!isLatin1()) {
+            return;
+        }
+        byte[] buf = StringUTF16.newBytesFor(value.length);
+        StringLatin1.inflateSB(value, buf, 0, count);
+        this.value = buf;
+        this.coder = UTF16;
     }
 
     /**
@@ -148,8 +190,9 @@
      * returned by a subsequent call to the {@link #capacity()} method.
      */
     public void trimToSize() {
-        if (count < value.length) {
-            value = Arrays.copyOf(value, count);
+        int length = count << coder;
+        if (length < value.length) {
+            value = Arrays.copyOf(value, length);
         }
     }
 
@@ -179,14 +222,17 @@
      *               {@code newLength} argument is negative.
      */
     public void setLength(int newLength) {
-        if (newLength < 0)
+        if (newLength < 0) {
             throw new StringIndexOutOfBoundsException(newLength);
+        }
         ensureCapacityInternal(newLength);
-
         if (count < newLength) {
-            Arrays.fill(value, count, newLength, '\0');
+            if (isLatin1()) {
+                StringLatin1.fillNull(value, count, newLength);
+            } else {
+                StringUTF16.fillNull(value, count, newLength);
+            }
         }
-
         count = newLength;
     }
 
@@ -209,9 +255,11 @@
      */
     @Override
     public char charAt(int index) {
-        if ((index < 0) || (index >= count))
-            throw new StringIndexOutOfBoundsException(index);
-        return value[index];
+        checkIndex(index, count);
+        if (isLatin1()) {
+            return (char)(value[index] & 0xff);
+        }
+        return StringUTF16.charAt(value, index);
     }
 
     /**
@@ -236,10 +284,11 @@
      *             sequence.
      */
     public int codePointAt(int index) {
-        if ((index < 0) || (index >= count)) {
-            throw new StringIndexOutOfBoundsException(index);
+        checkIndex(index, count);
+        if (isLatin1()) {
+            return value[index] & 0xff;
         }
-        return Character.codePointAtImpl(value, index, count);
+        return StringUTF16.codePointAtSB(value, index, count);
     }
 
     /**
@@ -265,10 +314,13 @@
      */
     public int codePointBefore(int index) {
         int i = index - 1;
-        if ((i < 0) || (i >= count)) {
+        if (i < 0 || i >= count) {
             throw new StringIndexOutOfBoundsException(index);
         }
-        return Character.codePointBeforeImpl(value, index, 0);
+        if (isLatin1()) {
+            return value[i] & 0xff;
+        }
+        return StringUTF16.codePointBeforeSB(value, index);
     }
 
     /**
@@ -295,7 +347,10 @@
         if (beginIndex < 0 || endIndex > count || beginIndex > endIndex) {
             throw new IndexOutOfBoundsException();
         }
-        return Character.codePointCountImpl(value, beginIndex, endIndex - beginIndex);
+        if (isLatin1()) {
+            return endIndex - beginIndex;
+        }
+        return StringUTF16.codePointCountSB(value, beginIndex, endIndex);
     }
 
     /**
@@ -321,8 +376,8 @@
         if (index < 0 || index > count) {
             throw new IndexOutOfBoundsException();
         }
-        return Character.offsetByCodePointsImpl(value, 0, count,
-                                                index, codePointOffset);
+        return Character.offsetByCodePoints(this,
+                                            index, codePointOffset);
     }
 
     /**
@@ -355,13 +410,14 @@
      */
     public void getChars(int srcBegin, int srcEnd, char[] dst, int dstBegin)
     {
-        if (srcBegin < 0)
-            throw new StringIndexOutOfBoundsException(srcBegin);
-        if ((srcEnd < 0) || (srcEnd > count))
-            throw new StringIndexOutOfBoundsException(srcEnd);
-        if (srcBegin > srcEnd)
-            throw new StringIndexOutOfBoundsException("srcBegin > srcEnd");
-        System.arraycopy(value, srcBegin, dst, dstBegin, srcEnd - srcBegin);
+        checkRangeSIOOBE(srcBegin, srcEnd, count);  // compatible to old version
+        int n = srcEnd - srcBegin;
+        checkRange(dstBegin, dstBegin + n, dst.length);
+        if (isLatin1()) {
+            StringLatin1.getCharsSB(value, srcBegin, srcEnd, dst, dstBegin);
+        } else {
+            StringUTF16.getCharsSB(value, srcBegin, srcEnd, dst, dstBegin);
+        }
     }
 
     /**
@@ -379,9 +435,15 @@
      *             negative or greater than or equal to {@code length()}.
      */
     public void setCharAt(int index, char ch) {
-        if ((index < 0) || (index >= count))
-            throw new StringIndexOutOfBoundsException(index);
-        value[index] = ch;
+        checkIndex(index, count);
+        if (isLatin1() && StringLatin1.canEncode(ch)) {
+            value[index] = (byte)ch;
+        } else {
+            if (isLatin1()) {
+                inflate();
+            }
+            StringUTF16.putCharSB(value, index, ch);
+        }
     }
 
     /**
@@ -418,35 +480,34 @@
      * @return  a reference to this object.
      */
     public AbstractStringBuilder append(String str) {
-        if (str == null)
+        if (str == null) {
             return appendNull();
+        }
         int len = str.length();
         ensureCapacityInternal(count + len);
-        str.getChars(0, len, value, count);
+        putStringAt(count, str);
         count += len;
         return this;
     }
 
     // Documentation in subclasses because of synchro difference
     public AbstractStringBuilder append(StringBuffer sb) {
-        if (sb == null)
-            return appendNull();
-        int len = sb.length();
-        ensureCapacityInternal(count + len);
-        sb.getChars(0, len, value, count);
-        count += len;
-        return this;
+        return this.append((AbstractStringBuilder)sb);
     }
 
     /**
      * @since 1.8
      */
     AbstractStringBuilder append(AbstractStringBuilder asb) {
-        if (asb == null)
+        if (asb == null) {
             return appendNull();
+        }
         int len = asb.length();
         ensureCapacityInternal(count + len);
-        asb.getChars(0, len, value, count);
+        if (getCoder() != asb.getCoder()) {
+            inflate();
+        }
+        asb.getBytes(value, count, coder);
         count += len;
         return this;
     }
@@ -454,25 +515,35 @@
     // Documentation in subclasses because of synchro difference
     @Override
     public AbstractStringBuilder append(CharSequence s) {
-        if (s == null)
+        if (s == null) {
             return appendNull();
-        if (s instanceof String)
+        }
+        if (s instanceof String) {
             return this.append((String)s);
-        if (s instanceof AbstractStringBuilder)
+        }
+        if (s instanceof AbstractStringBuilder) {
             return this.append((AbstractStringBuilder)s);
-
+        }
         return this.append(s, 0, s.length());
     }
 
     private AbstractStringBuilder appendNull() {
-        int c = count;
-        ensureCapacityInternal(c + 4);
-        final char[] value = this.value;
-        value[c++] = 'n';
-        value[c++] = 'u';
-        value[c++] = 'l';
-        value[c++] = 'l';
-        count = c;
+        ensureCapacityInternal(count + 4);
+        int count = this.count;
+        byte[] val = this.value;
+        if (isLatin1()) {
+            val[count++] = 'n';
+            val[count++] = 'u';
+            val[count++] = 'l';
+            val[count++] = 'l';
+        } else {
+            checkOffset(count + 4, val.length >> 1);
+            StringUTF16.putChar(val, count++, 'n');
+            StringUTF16.putChar(val, count++, 'u');
+            StringUTF16.putChar(val, count++, 'l');
+            StringUTF16.putChar(val, count++, 'l');
+        }
+        this.count = count;
         return this;
     }
 
@@ -507,21 +578,13 @@
      */
     @Override
     public AbstractStringBuilder append(CharSequence s, int start, int end) {
-        if (s == null)
+        if (s == null) {
             s = "null";
-        if ((start < 0) || (start > end) || (end > s.length()))
-            throw new IndexOutOfBoundsException(
-                "start " + start + ", end " + end + ", s.length() "
-                + s.length());
+        }
+        checkRange(start, end, s.length());
         int len = end - start;
         ensureCapacityInternal(count + len);
-        if (s instanceof String) {
-            ((String)s).getChars(start, end, value, count);
-        } else {
-            for (int i = start, j = count; i < end; i++, j++)
-                value[j] = s.charAt(i);
-        }
-        count += len;
+        appendChars(s, start, end);
         return this;
     }
 
@@ -544,8 +607,7 @@
     public AbstractStringBuilder append(char[] str) {
         int len = str.length;
         ensureCapacityInternal(count + len);
-        System.arraycopy(str, 0, value, count, len);
-        count += len;
+        appendChars(str, 0, len);
         return this;
     }
 
@@ -572,10 +634,10 @@
      *         or {@code offset+len > str.length}
      */
     public AbstractStringBuilder append(char str[], int offset, int len) {
-        if (len > 0)                // let arraycopy report AIOOBE for len < 0
-            ensureCapacityInternal(count + len);
-        System.arraycopy(str, offset, value, count, len);
-        count += len;
+        int end = offset + len;
+        checkRange(offset, end, str.length);
+        ensureCapacityInternal(count + len);
+        appendChars(str, offset, end);
         return this;
     }
 
@@ -592,20 +654,39 @@
      * @return  a reference to this object.
      */
     public AbstractStringBuilder append(boolean b) {
-        if (b) {
-            ensureCapacityInternal(count + 4);
-            value[count++] = 't';
-            value[count++] = 'r';
-            value[count++] = 'u';
-            value[count++] = 'e';
+        ensureCapacityInternal(count + (b ? 4 : 5));
+        int count = this.count;
+        byte[] val = this.value;
+        if (isLatin1()) {
+            if (b) {
+                val[count++] = 't';
+                val[count++] = 'r';
+                val[count++] = 'u';
+                val[count++] = 'e';
+            } else {
+                val[count++] = 'f';
+                val[count++] = 'a';
+                val[count++] = 'l';
+                val[count++] = 's';
+                val[count++] = 'e';
+            }
         } else {
-            ensureCapacityInternal(count + 5);
-            value[count++] = 'f';
-            value[count++] = 'a';
-            value[count++] = 'l';
-            value[count++] = 's';
-            value[count++] = 'e';
+            if (b) {
+                checkOffset(count + 4, val.length >> 1);
+                StringUTF16.putChar(val, count++, 't');
+                StringUTF16.putChar(val, count++, 'r');
+                StringUTF16.putChar(val, count++, 'u');
+                StringUTF16.putChar(val, count++, 'e');
+            } else {
+                checkOffset(count + 5, val.length >> 1);
+                StringUTF16.putChar(val, count++, 'f');
+                StringUTF16.putChar(val, count++, 'a');
+                StringUTF16.putChar(val, count++, 'l');
+                StringUTF16.putChar(val, count++, 's');
+                StringUTF16.putChar(val, count++, 'e');
+            }
         }
+        this.count = count;
         return this;
     }
 
@@ -627,7 +708,14 @@
     @Override
     public AbstractStringBuilder append(char c) {
         ensureCapacityInternal(count + 1);
-        value[count++] = c;
+        if (isLatin1() && StringLatin1.canEncode(c)) {
+            value[count++] = (byte)c;
+        } else {
+            if (isLatin1()) {
+                inflate();
+            }
+            StringUTF16.putCharSB(value, count++, c);
+        }
         return this;
     }
 
@@ -652,7 +740,13 @@
                                      : Integer.stringSize(i);
         int spaceNeeded = count + appendedLength;
         ensureCapacityInternal(spaceNeeded);
-        Integer.getChars(i, spaceNeeded, value);
+        if (isLatin1()) {
+            Integer.getChars(i, spaceNeeded, value);
+        } else {
+            byte[] val = this.value;
+            checkOffset(spaceNeeded, val.length >> 1);
+            Integer.getCharsUTF16(i, spaceNeeded, val);
+        }
         count = spaceNeeded;
         return this;
     }
@@ -678,7 +772,13 @@
                                      : Long.stringSize(l);
         int spaceNeeded = count + appendedLength;
         ensureCapacityInternal(spaceNeeded);
-        Long.getChars(l, spaceNeeded, value);
+        if (isLatin1()) {
+            Long.getChars(l, spaceNeeded, value);
+        } else {
+            byte[] val = this.value;
+            checkOffset(spaceNeeded, val.length >> 1);
+            Long.getCharsUTF16(l, spaceNeeded, val);
+        }
         count = spaceNeeded;
         return this;
     }
@@ -732,15 +832,13 @@
      *             greater than {@code end}.
      */
     public AbstractStringBuilder delete(int start, int end) {
-        if (start < 0)
-            throw new StringIndexOutOfBoundsException(start);
-        if (end > count)
+        if (end > count) {
             end = count;
-        if (start > end)
-            throw new StringIndexOutOfBoundsException();
+        }
+        checkRangeSIOOBE(start, end, count);
         int len = end - start;
         if (len > 0) {
-            System.arraycopy(value, start+len, value, start, count-end);
+            shift(end, -len);
             count -= len;
         }
         return this;
@@ -766,20 +864,10 @@
      * {@code codePoint} isn't a valid Unicode code point
      */
     public AbstractStringBuilder appendCodePoint(int codePoint) {
-        final int count = this.count;
-
         if (Character.isBmpCodePoint(codePoint)) {
-            ensureCapacityInternal(count + 1);
-            value[count] = (char) codePoint;
-            this.count = count + 1;
-        } else if (Character.isValidCodePoint(codePoint)) {
-            ensureCapacityInternal(count + 2);
-            Character.toSurrogates(codePoint, value, count);
-            this.count = count + 2;
-        } else {
-            throw new IllegalArgumentException();
+            return append((char)codePoint);
         }
-        return this;
+        return append(Character.toChars(codePoint));
     }
 
     /**
@@ -800,9 +888,8 @@
      *              {@code length()}.
      */
     public AbstractStringBuilder deleteCharAt(int index) {
-        if ((index < 0) || (index >= count))
-            throw new StringIndexOutOfBoundsException(index);
-        System.arraycopy(value, index+1, value, index, count-index-1);
+        checkIndex(index, count);
+        shift(index + 1, -1);
         count--;
         return this;
     }
@@ -827,22 +914,16 @@
      *             greater than {@code end}.
      */
     public AbstractStringBuilder replace(int start, int end, String str) {
-        if (start < 0)
-            throw new StringIndexOutOfBoundsException(start);
-        if (start > count)
-            throw new StringIndexOutOfBoundsException("start > length()");
-        if (start > end)
-            throw new StringIndexOutOfBoundsException("start > end");
-
-        if (end > count)
+        if (end > count) {
             end = count;
+        }
+        checkRangeSIOOBE(start, end, count);
         int len = str.length();
         int newCount = count + len - (end - start);
         ensureCapacityInternal(newCount);
-
-        System.arraycopy(value, end, value, start + len, count - end);
-        str.getChars(value, start);
+        shift(end, newCount - count);
         count = newCount;
+        putStringAt(start, str);
         return this;
     }
 
@@ -907,13 +988,16 @@
      *             greater than {@code end}.
      */
     public String substring(int start, int end) {
-        if (start < 0)
-            throw new StringIndexOutOfBoundsException(start);
-        if (end > count)
-            throw new StringIndexOutOfBoundsException(end);
-        if (start > end)
-            throw new StringIndexOutOfBoundsException(end - start);
-        return new String(value, start, end - start);
+        checkRangeSIOOBE(start, end, count);
+        if (isLatin1()) {
+            return StringLatin1.newString(value, start, end - start);
+        }
+        return StringUTF16.newStringSB(value, start, end - start);
+    }
+
+    private void shift(int offset, int n) {
+        System.arraycopy(value, offset << coder,
+                         value, (offset + n) << coder, (count - offset) << coder);
     }
 
     /**
@@ -940,16 +1024,12 @@
     public AbstractStringBuilder insert(int index, char[] str, int offset,
                                         int len)
     {
-        if ((index < 0) || (index > length()))
-            throw new StringIndexOutOfBoundsException(index);
-        if ((offset < 0) || (len < 0) || (offset > str.length - len))
-            throw new StringIndexOutOfBoundsException(
-                "offset " + offset + ", len " + len + ", str.length "
-                + str.length);
+        checkOffset(index, count);
+        checkRangeSIOOBE(offset, offset + len, str.length);
         ensureCapacityInternal(count + len);
-        System.arraycopy(value, index, value, index + len, count - index);
-        System.arraycopy(str, offset, value, index, len);
+        shift(index, len);
         count += len;
+        putCharsAt(index, str, offset, offset + len);
         return this;
     }
 
@@ -1008,15 +1088,15 @@
      * @throws     StringIndexOutOfBoundsException  if the offset is invalid.
      */
     public AbstractStringBuilder insert(int offset, String str) {
-        if ((offset < 0) || (offset > length()))
-            throw new StringIndexOutOfBoundsException(offset);
-        if (str == null)
+        checkOffset(offset, count);
+        if (str == null) {
             str = "null";
+        }
         int len = str.length();
         ensureCapacityInternal(count + len);
-        System.arraycopy(value, offset, value, offset + len, count - offset);
-        str.getChars(value, offset);
+        shift(offset, len);
         count += len;
+        putStringAt(offset, str);
         return this;
     }
 
@@ -1045,13 +1125,12 @@
      * @throws     StringIndexOutOfBoundsException  if the offset is invalid.
      */
     public AbstractStringBuilder insert(int offset, char[] str) {
-        if ((offset < 0) || (offset > length()))
-            throw new StringIndexOutOfBoundsException(offset);
+        checkOffset(offset, count);
         int len = str.length;
         ensureCapacityInternal(count + len);
-        System.arraycopy(value, offset, value, offset + len, count - offset);
-        System.arraycopy(str, 0, value, offset, len);
+        shift(offset, len);
         count += len;
+        putCharsAt(offset, str, 0, len);
         return this;
     }
 
@@ -1077,10 +1156,12 @@
      * @throws     IndexOutOfBoundsException  if the offset is invalid.
      */
     public AbstractStringBuilder insert(int dstOffset, CharSequence s) {
-        if (s == null)
+        if (s == null) {
             s = "null";
-        if (s instanceof String)
+        }
+        if (s instanceof String) {
             return this.insert(dstOffset, (String)s);
+        }
         return this.insert(dstOffset, s, 0, s.length());
     }
 
@@ -1128,23 +1209,19 @@
      *              {@code start} is greater than {@code end} or
      *              {@code end} is greater than {@code s.length()}
      */
-     public AbstractStringBuilder insert(int dstOffset, CharSequence s,
-                                         int start, int end) {
-        if (s == null)
+    public AbstractStringBuilder insert(int dstOffset, CharSequence s,
+                                        int start, int end)
+    {
+        if (s == null) {
             s = "null";
-        if ((dstOffset < 0) || (dstOffset > this.length()))
-            throw new IndexOutOfBoundsException("dstOffset "+dstOffset);
-        if ((start < 0) || (end < 0) || (start > end) || (end > s.length()))
-            throw new IndexOutOfBoundsException(
-                "start " + start + ", end " + end + ", s.length() "
-                + s.length());
+        }
+        checkOffset(dstOffset, count);
+        checkRange(start, end, s.length());
         int len = end - start;
         ensureCapacityInternal(count + len);
-        System.arraycopy(value, dstOffset, value, dstOffset + len,
-                         count - dstOffset);
-        for (int i=start; i<end; i++)
-            value[dstOffset++] = s.charAt(i);
+        shift(dstOffset, len);
         count += len;
+        putCharsAt(dstOffset, s, start, end);
         return this;
     }
 
@@ -1191,10 +1268,18 @@
      * @throws     IndexOutOfBoundsException  if the offset is invalid.
      */
     public AbstractStringBuilder insert(int offset, char c) {
+        checkOffset(offset, count);
         ensureCapacityInternal(count + 1);
-        System.arraycopy(value, offset, value, offset + 1, count - offset);
-        value[offset] = c;
+        shift(offset, 1);
         count += 1;
+        if (isLatin1() && StringLatin1.canEncode(c)) {
+            value[offset] = (byte)c;
+        } else {
+            if (isLatin1()) {
+                inflate();
+            }
+            StringUTF16.putCharSB(value, offset, c);
+        }
         return this;
     }
 
@@ -1326,7 +1411,7 @@
      *          or {@code -1} if there is no such occurrence.
      */
     public int indexOf(String str, int fromIndex) {
-        return String.indexOf(value, 0, count, str, fromIndex);
+        return String.indexOf(value, coder, count, str, fromIndex);
     }
 
     /**
@@ -1366,7 +1451,7 @@
      *          or {@code -1} if there is no such occurrence.
      */
     public int lastIndexOf(String str, int fromIndex) {
-        return String.lastIndexOf(value, 0, count, str, fromIndex);
+        return String.lastIndexOf(value, coder, count, str, fromIndex);
     }
 
     /**
@@ -1392,34 +1477,47 @@
      * @return  a reference to this object.
      */
     public AbstractStringBuilder reverse() {
-        boolean hasSurrogates = false;
+        byte[] val = this.value;
+        int count = this.count;
+        int coder = this.coder;
         int n = count - 1;
-        for (int j = (n-1) >> 1; j >= 0; j--) {
-            int k = n - j;
-            char cj = value[j];
-            char ck = value[k];
-            value[j] = ck;
-            value[k] = cj;
-            if (Character.isSurrogate(cj) ||
-                Character.isSurrogate(ck)) {
-                hasSurrogates = true;
+        if (COMPACT_STRINGS && coder == LATIN1) {
+            for (int j = (n-1) >> 1; j >= 0; j--) {
+                int k = n - j;
+                byte cj = val[j];
+                val[j] = val[k];
+                val[k] = cj;
             }
-        }
-        if (hasSurrogates) {
-            reverseAllValidSurrogatePairs();
+        } else {
+            checkOffset(count, val.length >> 1);
+            boolean hasSurrogates = false;
+            for (int j = (n-1) >> 1; j >= 0; j--) {
+                int k = n - j;
+                char cj = StringUTF16.getChar(val, j);
+                char ck = StringUTF16.getChar(val, k);
+                StringUTF16.putChar(val, j, ck);
+                StringUTF16.putChar(val, k, cj);
+                if (Character.isSurrogate(cj) ||
+                    Character.isSurrogate(ck)) {
+                    hasSurrogates = true;
+                }
+            }
+            if (hasSurrogates) {
+                reverseAllValidSurrogatePairs(val, count);
+            }
         }
         return this;
     }
 
     /** Outlined helper method for reverse() */
-    private void reverseAllValidSurrogatePairs() {
+    private void reverseAllValidSurrogatePairs(byte[] val, int count) {
         for (int i = 0; i < count - 1; i++) {
-            char c2 = value[i];
+            char c2 = StringUTF16.getChar(val, i);
             if (Character.isLowSurrogate(c2)) {
-                char c1 = value[i + 1];
+                char c1 = StringUTF16.getChar(val, i + 1);
                 if (Character.isHighSurrogate(c1)) {
-                    value[i++] = c1;
-                    value[i] = c2;
+                    StringUTF16.putChar(val, i++, c1);
+                    StringUTF16.putChar(val, i, c2);
                 }
             }
         }
@@ -1444,10 +1542,13 @@
      */
     @Override
     public IntStream chars() {
+        byte[] val = this.value; int count = this.count; byte coder = this.coder;
+        checkOffset(count, val.length >> coder);
         // Reuse String-based spliterator. This requires a supplier to
         // capture the value and count when the terminal operation is executed
         return StreamSupport.intStream(
-                () -> new String.IntCharArraySpliterator(value, 0, count, 0),
+                () -> coder == LATIN1 ? new StringLatin1.CharsSpliterator(val, 0, count, 0)
+                                      : new StringUTF16.CharsSpliterator(val, 0, count, 0),
                 Spliterator.ORDERED | Spliterator.SIZED | Spliterator.SUBSIZED,
                 false);
     }
@@ -1458,10 +1559,13 @@
      */
     @Override
     public IntStream codePoints() {
+        byte[] val = this.value; int count = this.count; byte coder = this.coder;
+        checkOffset(count, val.length >> coder);
         // Reuse String-based spliterator. This requires a supplier to
         // capture the value and count when the terminal operation is executed
         return StreamSupport.intStream(
-                () -> new String.CodePointsSpliterator(value, 0, count, 0),
+                () -> coder == LATIN1 ? new StringLatin1.CharsSpliterator(val, 0, count, 0)
+                                      : new StringUTF16.CodePointsSpliterator(val, 0, count, 0),
                 Spliterator.ORDERED,
                 false);
     }
@@ -1469,8 +1573,147 @@
     /**
      * Needed by {@code String} for the contentEquals method.
      */
-    final char[] getValue() {
+    final byte[] getValue() {
         return value;
     }
 
+    /*
+     * Invoker guarantees it is in UTF16 (inflate itself for asb), if two
+     * coders are different and the dstBegin has enough space
+     *
+     * @param dstBegin  the char index, not offset of byte[]
+     * @param coder     the coder of dst[]
+     */
+    protected void getBytes(byte dst[], int dstBegin, byte coder) {
+        if (this.coder == coder) {
+            System.arraycopy(value, 0, dst, dstBegin << coder, count << coder);
+        } else {        // this.coder == LATIN && coder == UTF16
+            StringLatin1.inflateSB(value, dst, dstBegin, count);
+        }
+    }
+
+    /* for readObject() */
+    protected void initBytes(char[] value, int off, int len) {
+        if (String.COMPACT_STRINGS) {
+            this.value = StringUTF16.compress(value, off, len);
+            if (this.value != null) {
+                this.coder = LATIN1;
+                return;
+            }
+        }
+        this.coder = UTF16;
+        this.value = StringUTF16.toBytes(value, off, len);
+    }
+
+    final byte getCoder() {
+        return COMPACT_STRINGS ? coder : UTF16;
+    }
+
+    final boolean isLatin1() {
+        return COMPACT_STRINGS && coder == LATIN1;
+    }
+
+    private final void putCharsAt(int index, char[] s, int off, int end) {
+        if (isLatin1()) {
+            byte[] val = this.value;
+            for (int i = off, j = index; i < end; i++) {
+                char c = s[i];
+                if (StringLatin1.canEncode(c)) {
+                    val[j++] = (byte)c;
+                } else {
+                    inflate();
+                    StringUTF16.putCharsSB(this.value, j, s, i, end);
+                    return;
+                }
+            }
+        } else {
+            StringUTF16.putCharsSB(this.value, index, s, off, end);
+        }
+    }
+
+    private final void putCharsAt(int index, CharSequence s, int off, int end) {
+        if (isLatin1()) {
+            byte[] val = this.value;
+            for (int i = off, j = index; i < end; i++) {
+                char c = s.charAt(i);
+                if (StringLatin1.canEncode(c)) {
+                    val[j++] = (byte)c;
+                } else {
+                    inflate();
+                    StringUTF16.putCharsSB(this.value, j, s, i, end);
+                    return;
+                }
+            }
+        } else {
+            StringUTF16.putCharsSB(this.value, index, s, off, end);
+        }
+    }
+
+    private final void putStringAt(int index, String str) {
+        if (getCoder() != str.coder()) {
+            inflate();
+        }
+        byte[] val = this.value;
+        byte coder = this.coder;
+        checkOffset(index + str.length(), val.length >> coder);
+        str.getBytes(val, index, coder);
+    }
+
+    private final void appendChars(char[] s, int off, int end) {
+        if (isLatin1()) {
+            byte[] val = this.value;
+            for (int i = off, j = count; i < end; i++) {
+                char c = s[i];
+                if (StringLatin1.canEncode(c)) {
+                    val[j++] = (byte)c;
+                } else {
+                    count = j;
+                    inflate();
+                    StringUTF16.putCharsSB(this.value, j, s, i, end);
+                    count += end - i;
+                    return;
+                }
+            }
+        } else {
+            StringUTF16.putCharsSB(this.value, count, s, off, end);
+        }
+        count += end - off;
+    }
+
+    private final void appendChars(CharSequence s, int off, int end) {
+        if (isLatin1()) {
+            byte[] val = this.value;
+            for (int i = off, j = count; i < end; i++) {
+                char c = s.charAt(i);
+                if (StringLatin1.canEncode(c)) {
+                    val[j++] = (byte)c;
+                } else {
+                    count = j;
+                    inflate();
+                    StringUTF16.putCharsSB(this.value, j, s, i, end);
+                    count += end - i;
+                    return;
+                }
+            }
+        } else {
+            StringUTF16.putCharsSB(this.value, count, s, off, end);
+        }
+        count += end - off;
+    }
+
+    /* IndexOutOfBoundsException, if out of bounds */
+    private static void checkRange(int start, int end, int len) {
+        if (start < 0 || start > end || end > len) {
+            throw new IndexOutOfBoundsException(
+                "start " + start + ", end " + end + ", length " + len);
+        }
+    }
+
+    /* StringIndexOutOfBoundsException, if out of bounds */
+    private static void checkRangeSIOOBE(int start, int end, int len) {
+        if (start < 0 || start > end || end > len) {
+            throw new StringIndexOutOfBoundsException(
+                "start " + start + ", end " + end + ", length " + len);
+        }
+    }
 }
--- a/src/java.base/share/classes/java/lang/Class.java	Tue Nov 10 13:46:45 2015 +0300
+++ b/src/java.base/share/classes/java/lang/Class.java	Tue Nov 17 10:29:28 2015 -0800
@@ -55,7 +55,7 @@
 import java.util.HashMap;
 import java.util.Objects;
 import java.util.StringJoiner;
-import sun.misc.Unsafe;
+import jdk.internal.misc.Unsafe;
 import jdk.internal.HotSpotIntrinsicCandidate;
 import sun.reflect.CallerSensitive;
 import sun.reflect.ConstantPool;
--- a/src/java.base/share/classes/java/lang/Integer.java	Tue Nov 10 13:46:45 2015 +0300
+++ b/src/java.base/share/classes/java/lang/Integer.java	Tue Nov 17 10:29:28 2015 -0800
@@ -29,6 +29,10 @@
 import java.util.Objects;
 import jdk.internal.HotSpotIntrinsicCandidate;
 
+import static java.lang.String.COMPACT_STRINGS;
+import static java.lang.String.LATIN1;
+import static java.lang.String.UTF16;
+
 /**
  * The {@code Integer} class wraps a value of the primitive type
  * {@code int} in an object. An object of type {@code Integer}
@@ -138,25 +142,47 @@
             return toString(i);
         }
 
-        char buf[] = new char[33];
+        if (COMPACT_STRINGS) {
+            byte[] buf = new byte[33];
+            boolean negative = (i < 0);
+            int charPos = 32;
+
+            if (!negative) {
+                i = -i;
+            }
+
+            while (i <= -radix) {
+                buf[charPos--] = (byte)digits[-(i % radix)];
+                i = i / radix;
+            }
+            buf[charPos] = (byte)digits[-i];
+
+            if (negative) {
+                buf[--charPos] = '-';
+            }
+
+            return StringLatin1.newString(buf, charPos, (33 - charPos));
+        }
+        return toStringUTF16(i, radix);
+    }
+
+    private static String toStringUTF16(int i, int radix) {
+        byte[] buf = new byte[33 * 2];
         boolean negative = (i < 0);
         int charPos = 32;
-
         if (!negative) {
             i = -i;
         }
-
         while (i <= -radix) {
-            buf[charPos--] = digits[-(i % radix)];
+            StringUTF16.putChar(buf, charPos--, digits[-(i % radix)]);
             i = i / radix;
         }
-        buf[charPos] = digits[-i];
+        StringUTF16.putChar(buf, charPos, digits[-i]);
 
         if (negative) {
-            buf[--charPos] = '-';
+            StringUTF16.putChar(buf, --charPos, '-');
         }
-
-        return new String(buf, charPos, (33 - charPos));
+        return StringUTF16.newString(buf, charPos, (33 - charPos));
     }
 
     /**
@@ -312,12 +338,16 @@
         // assert shift > 0 && shift <=5 : "Illegal shift value";
         int mag = Integer.SIZE - Integer.numberOfLeadingZeros(val);
         int chars = Math.max(((mag + (shift - 1)) / shift), 1);
-        char[] buf = new char[chars];
 
-        formatUnsignedInt(val, shift, buf, 0, chars);
-
-        // Use special constructor which takes over "buf".
-        return new String(buf, true);
+        if (COMPACT_STRINGS) {
+            byte[] buf = new byte[chars];
+            formatUnsignedInt(val, shift, buf, 0, chars);
+            return new String(buf, LATIN1);
+        } else {
+            byte[] buf = new byte[chars * 2];
+            formatUnsignedIntUTF16(val, shift, buf, 0, chars);
+            return new String(buf, UTF16);
+        }
     }
 
     /**
@@ -331,7 +361,7 @@
      * @param offset the offset in the destination buffer to start at
      * @param len the number of characters to write
      */
-     static void formatUnsignedInt(int val, int shift, char[] buf, int offset, int len) {
+    static void formatUnsignedInt(int val, int shift, char[] buf, int offset, int len) {
         // assert shift > 0 && shift <=5 : "Illegal shift value";
         // assert offset >= 0 && offset < buf.length : "illegal offset";
         // assert len > 0 && (offset + len) <= buf.length : "illegal length";
@@ -344,6 +374,28 @@
         } while (charPos > offset);
     }
 
+    /** byte[]/LATIN1 version    */
+    static void formatUnsignedInt(int val, int shift, byte[] buf, int offset, int len) {
+        int charPos = offset + len;
+        int radix = 1 << shift;
+        int mask = radix - 1;
+        do {
+            buf[--charPos] = (byte)Integer.digits[val & mask];
+            val >>>= shift;
+        } while (charPos > offset);
+    }
+
+    /** byte[]/UTF16 version    */
+    static void formatUnsignedIntUTF16(int val, int shift, byte[] buf, int offset, int len) {
+        int charPos = offset + len;
+        int radix = 1 << shift;
+        int mask = radix - 1;
+        do {
+            StringUTF16.putChar(buf, --charPos, Integer.digits[val & mask]);
+            val >>>= shift;
+        } while (charPos > offset);
+    }
+
     static final char [] DigitTens = {
         '0', '0', '0', '0', '0', '0', '0', '0', '0', '0',
         '1', '1', '1', '1', '1', '1', '1', '1', '1', '1',
@@ -401,9 +453,15 @@
         if (i == Integer.MIN_VALUE)
             return "-2147483648";
         int size = (i < 0) ? stringSize(-i) + 1 : stringSize(i);
-        char[] buf = new char[size];
-        getChars(i, size, buf);
-        return new String(buf, true);
+        if (COMPACT_STRINGS) {
+            byte[] buf = new byte[size];
+            getChars(i, size, buf);
+            return new String(buf, LATIN1);
+        } else {
+            byte[] buf = new byte[size * 2];
+            getCharsUTF16(i, size, buf);
+            return new String(buf, UTF16);
+        }
     }
 
     /**
@@ -433,7 +491,7 @@
      *
      * Will fail if i == Integer.MIN_VALUE
      */
-    static void getChars(int i, int index, char[] buf) {
+    static void getChars(int i, int index, byte[] buf) {
         int q, r;
         int charPos = index;
         char sign = 0;
@@ -449,8 +507,8 @@
         // really: r = i - (q * 100);
             r = i - ((q << 6) + (q << 5) + (q << 2));
             i = q;
-            buf [--charPos] = DigitOnes[r];
-            buf [--charPos] = DigitTens[r];
+            buf [--charPos] = (byte)DigitOnes[r];
+            buf [--charPos] = (byte)DigitTens[r];
         }
 
         // Fall thru to fast mode for smaller numbers
@@ -458,12 +516,46 @@
         for (;;) {
             q = (i * 52429) >>> (16+3);
             r = i - ((q << 3) + (q << 1));  // r = i-(q*10) ...
-            buf [--charPos] = digits [r];
+            buf [--charPos] = (byte)digits [r];
             i = q;
             if (i == 0) break;
         }
         if (sign != 0) {
-            buf [--charPos] = sign;
+            buf [--charPos] = (byte)sign;
+        }
+    }
+
+    static void getCharsUTF16(int i, int index, byte[] buf) {
+        int q, r;
+        int charPos = index;
+        char sign = 0;
+
+        if (i < 0) {
+            sign = '-';
+            i = -i;
+        }
+
+        // Generate two digits per iteration
+        while (i >= 65536) {
+            q = i / 100;
+        // really: r = i - (q * 100);
+            r = i - ((q << 6) + (q << 5) + (q << 2));
+            i = q;
+            StringUTF16.putChar(buf, --charPos, DigitOnes[r]);
+            StringUTF16.putChar(buf, --charPos, DigitTens[r]);
+        }
+
+        // Fall thru to fast mode for smaller numbers
+        // assert(i <= 65536, i);
+        for (;;) {
+            q = (i * 52429) >>> (16+3);
+            r = i - ((q << 3) + (q << 1));  // r = i-(q*10) ...
+            StringUTF16.putChar(buf, --charPos, Integer.digits[r]);
+            i = q;
+            if (i == 0) break;
+        }
+        if (sign != 0) {
+            StringUTF16.putChar(buf, --charPos, sign);
         }
     }
 
--- a/src/java.base/share/classes/java/lang/Long.java	Tue Nov 10 13:46:45 2015 +0300
+++ b/src/java.base/share/classes/java/lang/Long.java	Tue Nov 17 10:29:28 2015 -0800
@@ -30,6 +30,9 @@
 import java.util.Objects;
 import jdk.internal.HotSpotIntrinsicCandidate;
 
+import static java.lang.String.COMPACT_STRINGS;
+import static java.lang.String.LATIN1;
+import static java.lang.String.UTF16;
 
 /**
  * The {@code Long} class wraps a value of the primitive type {@code
@@ -124,25 +127,46 @@
             radix = 10;
         if (radix == 10)
             return toString(i);
-        char[] buf = new char[65];
+
+        if (COMPACT_STRINGS) {
+            byte[] buf = new byte[65];
+            int charPos = 64;
+            boolean negative = (i < 0);
+
+            if (!negative) {
+                i = -i;
+            }
+
+            while (i <= -radix) {
+                buf[charPos--] = (byte)Integer.digits[(int)(-(i % radix))];
+                i = i / radix;
+            }
+            buf[charPos] = (byte)Integer.digits[(int)(-i)];
+
+            if (negative) {
+                buf[--charPos] = '-';
+            }
+            return StringLatin1.newString(buf, charPos, (65 - charPos));
+        }
+        return toStringUTF16(i, radix);
+    }
+
+    private static String toStringUTF16(long i, int radix) {
+        byte[] buf = new byte[65 * 2];
         int charPos = 64;
         boolean negative = (i < 0);
-
         if (!negative) {
             i = -i;
         }
-
         while (i <= -radix) {
-            buf[charPos--] = Integer.digits[(int)(-(i % radix))];
+            StringUTF16.putChar(buf, charPos--, Integer.digits[(int)(-(i % radix))]);
             i = i / radix;
         }
-        buf[charPos] = Integer.digits[(int)(-i)];
-
+        StringUTF16.putChar(buf, charPos, Integer.digits[(int)(-i)]);
         if (negative) {
-            buf[--charPos] = '-';
+            StringUTF16.putChar(buf, --charPos, '-');
         }
-
-        return new String(buf, charPos, (65 - charPos));
+        return StringUTF16.newString(buf, charPos, (65 - charPos));
     }
 
     /**
@@ -355,10 +379,16 @@
         // assert shift > 0 && shift <=5 : "Illegal shift value";
         int mag = Long.SIZE - Long.numberOfLeadingZeros(val);
         int chars = Math.max(((mag + (shift - 1)) / shift), 1);
-        char[] buf = new char[chars];
 
-        formatUnsignedLong(val, shift, buf, 0, chars);
-        return new String(buf, true);
+        if (COMPACT_STRINGS) {
+            byte[] buf = new byte[chars];
+            formatUnsignedLong0(val, shift, buf, 0, chars);
+            return new String(buf, LATIN1);
+        } else {
+            byte[] buf = new byte[chars * 2];
+            formatUnsignedLong0UTF16(val, shift, buf, 0, chars);
+            return new String(buf, UTF16);
+        }
     }
 
     /**
@@ -385,6 +415,28 @@
         } while (charPos > offset);
     }
 
+    /** byte[]/LATIN1 version    */
+    static void formatUnsignedLong0(long val, int shift, byte[] buf, int offset, int len) {
+        int charPos = offset + len;
+        int radix = 1 << shift;
+        int mask = radix - 1;
+        do {
+            buf[--charPos] = (byte)Integer.digits[((int) val) & mask];
+            val >>>= shift;
+        } while (charPos > offset);
+    }
+
+    /** byte[]/UTF16 version    */
+    static void formatUnsignedLong0UTF16(long val, int shift, byte[] buf, int offset, int len) {
+        int charPos = offset + len;
+        int radix = 1 << shift;
+        int mask = radix - 1;
+        do {
+            StringUTF16.putChar(buf, --charPos, Integer.digits[((int) val) & mask]);
+            val >>>= shift;
+        } while (charPos > offset);
+    }
+
     /**
      * Returns a {@code String} object representing the specified
      * {@code long}.  The argument is converted to signed decimal
@@ -399,9 +451,15 @@
         if (i == Long.MIN_VALUE)
             return "-9223372036854775808";
         int size = (i < 0) ? stringSize(-i) + 1 : stringSize(i);
-        char[] buf = new char[size];
-        getChars(i, size, buf);
-        return new String(buf, true);
+        if (COMPACT_STRINGS) {
+            byte[] buf = new byte[size];
+            getChars(i, size, buf);
+            return new String(buf, LATIN1);
+        } else {
+            byte[] buf = new byte[size * 2];
+            getCharsUTF16(i, size, buf);
+            return new String(buf, UTF16);
+        }
     }
 
     /**
@@ -431,7 +489,7 @@
      *
      * Will fail if i == Long.MIN_VALUE
      */
-    static void getChars(long i, int index, char[] buf) {
+    static void getChars(long i, int index, byte[] buf) {
         long q;
         int r;
         int charPos = index;
@@ -448,8 +506,8 @@
             // really: r = i - (q * 100);
             r = (int)(i - ((q << 6) + (q << 5) + (q << 2)));
             i = q;
-            buf[--charPos] = Integer.DigitOnes[r];
-            buf[--charPos] = Integer.DigitTens[r];
+            buf[--charPos] = (byte)Integer.DigitOnes[r];
+            buf[--charPos] = (byte)Integer.DigitTens[r];
         }
 
         // Get 2 digits/iteration using ints
@@ -460,8 +518,8 @@
             // really: r = i2 - (q * 100);
             r = i2 - ((q2 << 6) + (q2 << 5) + (q2 << 2));
             i2 = q2;
-            buf[--charPos] = Integer.DigitOnes[r];
-            buf[--charPos] = Integer.DigitTens[r];
+            buf[--charPos] = (byte)Integer.DigitOnes[r];
+            buf[--charPos] = (byte)Integer.DigitTens[r];
         }
 
         // Fall thru to fast mode for smaller numbers
@@ -469,12 +527,59 @@
         for (;;) {
             q2 = (i2 * 52429) >>> (16+3);
             r = i2 - ((q2 << 3) + (q2 << 1));  // r = i2-(q2*10) ...
-            buf[--charPos] = Integer.digits[r];
+            buf[--charPos] = (byte)Integer.digits[r];
             i2 = q2;
             if (i2 == 0) break;
         }
         if (sign != 0) {
-            buf[--charPos] = sign;
+            buf[--charPos] = (byte)sign;
+        }
+    }
+
+    static void getCharsUTF16(long i, int index, byte[] buf) {
+        long q;
+        int r;
+        int charPos = index;
+        char sign = 0;
+
+        if (i < 0) {
+            sign = '-';
+            i = -i;
+        }
+
+        // Get 2 digits/iteration using longs until quotient fits into an int
+        while (i > Integer.MAX_VALUE) {
+            q = i / 100;
+            // really: r = i - (q * 100);
+            r = (int)(i - ((q << 6) + (q << 5) + (q << 2)));
+            i = q;
+            StringUTF16.putChar(buf, --charPos, Integer.DigitOnes[r]);
+            StringUTF16.putChar(buf, --charPos, Integer.DigitTens[r]);
+        }
+
+        // Get 2 digits/iteration using ints
+        int q2;
+        int i2 = (int)i;
+        while (i2 >= 65536) {
+            q2 = i2 / 100;
+            // really: r = i2 - (q * 100);
+            r = i2 - ((q2 << 6) + (q2 << 5) + (q2 << 2));
+            i2 = q2;
+            StringUTF16.putChar(buf, --charPos, Integer.DigitOnes[r]);
+            StringUTF16.putChar(buf, --charPos, Integer.DigitTens[r]);
+        }
+
+        // Fall thru to fast mode for smaller numbers
+        // assert(i2 <= 65536, i2);
+        for (;;) {
+            q2 = (i2 * 52429) >>> (16+3);
+            r = i2 - ((q2 << 3) + (q2 << 1));  // r = i2-(q2*10) ...
+            StringUTF16.putChar(buf, --charPos, Integer.digits[r]);
+            i2 = q2;
+            if (i2 == 0) break;
+        }
+        if (sign != 0) {
+            StringUTF16.putChar(buf, --charPos, sign);
         }
     }
 
--- a/src/java.base/share/classes/java/lang/ProcessBuilder.java	Tue Nov 10 13:46:45 2015 +0300
+++ b/src/java.base/share/classes/java/lang/ProcessBuilder.java	Tue Nov 17 10:29:28 2015 -0800
@@ -26,9 +26,11 @@
 package java.lang;
 
 import java.io.File;
+import java.io.FileDescriptor;
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.OutputStream;
+import java.nio.channels.Pipe;
 import java.util.Arrays;
 import java.util.ArrayList;
 import java.util.List;
@@ -43,6 +45,11 @@
  * {@link Process} instance with those attributes.  The {@link
  * #start()} method can be invoked repeatedly from the same instance
  * to create new subprocesses with identical or related attributes.
+ * <p>
+ * The {@link #startPipeline startPipeline} method can be invoked to create
+ * a pipeline of new processes that send the output of each process
+ * directly to the next process.  Each process has the attributes of
+ * its respective ProcessBuilder.
  *
  * <p>Each process builder manages these process attributes:
  *
@@ -696,11 +703,37 @@
         private Redirect() {}
     }
 
+    /**
+     * Private implementation subclass of Redirect that holds a FileDescriptor for the
+     * output of a previously started Process.
+     * The FileDescriptor is used as the standard input of the next Process
+     * to be started.
+     */
+    static class RedirectPipeImpl extends Redirect {
+        final FileDescriptor fd;
+
+        RedirectPipeImpl() {
+            this.fd = new FileDescriptor();
+        }
+        @Override
+        public Type type() { return Type.PIPE; }
+
+        @Override
+        public String toString() { return type().toString();}
+
+        FileDescriptor getFd() { return fd; }
+    }
+
+    /**
+     * Return the array of redirects, creating the default as needed.
+     * @return the array of redirects
+     */
     private Redirect[] redirects() {
-        if (redirects == null)
+        if (redirects == null) {
             redirects = new Redirect[] {
-                Redirect.PIPE, Redirect.PIPE, Redirect.PIPE
+                    Redirect.PIPE, Redirect.PIPE, Redirect.PIPE
             };
+        }
         return redirects;
     }
 
@@ -1039,6 +1072,18 @@
      * @see Runtime#exec(String[], String[], java.io.File)
      */
     public Process start() throws IOException {
+        return start(redirects);
+    }
+
+    /**
+     * Start a new Process using an explicit array of redirects.
+     * See {@link #start} for details of starting each Process.
+     *
+     * @param redirect array of redirects for stdin, stdout, stderr
+     * @return the new Process
+     * @throws IOException if an I/O error occurs
+     */
+    private Process start(Redirect[] redirects) throws IOException {
         // Must convert to array first -- a malicious user-supplied
         // list might try to circumvent the security check.
         String[] cmdarray = command.toArray(new String[command.size()]);
@@ -1089,4 +1134,171 @@
                 cause);
         }
     }
+
+    /**
+     * Starts a Process for each ProcessBuilder, creating a pipeline of
+     * processes linked by their standard output and standard input streams.
+     * The attributes of each ProcessBuilder are used to start the respective
+     * process except that as each process is started, its standard output
+     * is directed to the standard input of the next.  The redirects for standard
+     * input of the first process and standard output of the last process are
+     * initialized using the redirect settings of the respective ProcessBuilder.
+     * All other {@code ProcessBuilder} redirects should be
+     * {@link Redirect#PIPE Redirect.PIPE}.
+     * <p>
+     * All input and output streams between the intermediate processes are
+     * not accessible.
+     * The {@link Process#getOutputStream standard input} of all processes
+     * except the first process are <i>null output streams</i>
+     * The {@link Process#getInputStream standard output} of all processes
+     * except the last process are <i>null input streams</i>.
+     * <p>
+     * The {@link #redirectErrorStream} of each ProcessBuilder applies to the
+     * respective process.  If set to {@code true}, the error stream is written
+     * to the same stream as standard output.
+     * <p>
+     * If starting any of the processes throws an Exception, all processes
+     * are forcibly destroyed.
+     * <p>
+     * The {@code startPipeline} method performs the same checks on
+     * each ProcessBuilder as does the {@link #start} method. The new process
+     * will invoke the command and arguments given by {@link #command()},
+     * in a working directory as given by {@link #directory()},
+     * with a process environment as given by {@link #environment()}.
+     * <p>
+     * This method checks that the command is a valid operating
+     * system command.  Which commands are valid is system-dependent,
+     * but at the very least the command must be a non-empty list of
+     * non-null strings.
+     * <p>
+     * A minimal set of system dependent environment variables may
+     * be required to start a process on some operating systems.
+     * As a result, the subprocess may inherit additional environment variable
+     * settings beyond those in the process builder's {@link #environment()}.
+     * <p>
+     * If there is a security manager, its
+     * {@link SecurityManager#checkExec checkExec}
+     * method is called with the first component of this object's
+     * {@code command} array as its argument. This may result in
+     * a {@link SecurityException} being thrown.
+     * <p>
+     * Starting an operating system process is highly system-dependent.
+     * Among the many things that can go wrong are:
+     * <ul>
+     * <li>The operating system program file was not found.
+     * <li>Access to the program file was denied.
+     * <li>The working directory does not exist.
+     * <li>Invalid character in command argument, such as NUL.
+     * </ul>
+     * <p>
+     * In such cases an exception will be thrown.  The exact nature
+     * of the exception is system-dependent, but it will always be a
+     * subclass of {@link IOException}.
+     * <p>
+     * If the operating system does not support the creation of
+     * processes, an {@link UnsupportedOperationException} will be thrown.
+     * <p>
+     * Subsequent modifications to this process builder will not
+     * affect the returned {@link Process}.
+     * @apiNote
+     * For example to count the unique imports for all the files in a file hierarchy
+     * on a Unix compatible platform:
+     * <pre>{@code
+     * String directory = "/home/duke/src";
+     * ProcessBuilder[] builders = {
+     *              new ProcessBuilder("find", directory, "-type", "f"),
+                    new ProcessBuilder("xargs", "grep", "-h", "^import "),
+                    new ProcessBuilder("awk", "{print $2;}"),
+                    new ProcessBuilder("sort", "-u")};
+     * List<Process> processes = ProcessBuilder.startPipeline(
+     *         Arrays.asList(builders));
+     * Process last = processes.get(processes.size()-1);
+     * try (InputStream is = last.getInputStream();
+     *         Reader isr = new InputStreamReader(is);
+     *         BufferedReader r = new BufferedReader(isr)) {
+     *     long count = r.lines().count();
+     * }
+     * }</pre>
+     *
+     * @param builders a List of ProcessBuilders
+     * @return a {@code List<Process>}es started from the corresponding
+     *         ProcessBuilder
+     * @throws IllegalArgumentException any of the redirects except the
+     *          standard input of the first builder and the standard output of
+     *          the last builder are not {@link Redirect#PIPE}.
+     * @throws NullPointerException
+     *         if an element of the command list is null or
+     *         if an element of the ProcessBuilder list is null or
+     *         the builders argument is null
+     * @throws IndexOutOfBoundsException
+     *         if the command is an empty list (has size {@code 0})
+     * @throws SecurityException
+     *         if a security manager exists and
+     *         <ul>
+     *         <li>its
+     *         {@link SecurityManager#checkExec checkExec}
+     *         method doesn't allow creation of the subprocess, or
+     *         <li>the standard input to the subprocess was
+     *         {@linkplain #redirectInput redirected from a file}
+     *         and the security manager's
+     *         {@link SecurityManager#checkRead(String) checkRead} method
+     *         denies read access to the file, or
+     *         <li>the standard output or standard error of the
+     *         subprocess was
+     *         {@linkplain #redirectOutput redirected to a file}
+     *         and the security manager's
+     *         {@link SecurityManager#checkWrite(String) checkWrite} method
+     *         denies write access to the file
+     *         </ul>
+     *
+     * @throws  UnsupportedOperationException
+     *          If the operating system does not support the creation of processes
+     *
+     * @throws IOException if an I/O error occurs
+     */
+    public static List<Process> startPipeline(List<ProcessBuilder> builders) throws IOException {
+        // Accumulate and check the builders
+        final int numBuilders = builders.size();
+        List<Process> processes = new ArrayList<>(numBuilders);
+        try {
+            Redirect prevOutput = null;
+            for (int index = 0; index < builders.size(); index++) {
+                ProcessBuilder builder = builders.get(index);
+                Redirect[] redirects = builder.redirects();
+                if (index > 0) {
+                    // check the current Builder to see if it can take input from the previous
+                    if (builder.redirectInput() != Redirect.PIPE) {
+                        throw new IllegalArgumentException("builder redirectInput()" +
+                                " must be PIPE except for the first builder: "
+                                + builder.redirectInput());
+                    }
+                    redirects[0] = prevOutput;
+                }
+                if (index < numBuilders - 1) {
+                    // check all but the last stage has output = PIPE
+                    if (builder.redirectOutput() != Redirect.PIPE) {
+                        throw new IllegalArgumentException("builder redirectOutput()" +
+                                " must be PIPE except for the last builder: "
+                                + builder.redirectOutput());
+                    }
+                    redirects[1] = new RedirectPipeImpl();  // placeholder for new output
+                }
+                processes.add(builder.start(redirects));
+                prevOutput = redirects[1];
+            }
+        } catch (Exception ex) {
+            // Cleanup processes already started
+            processes.forEach(Process::destroyForcibly);
+            processes.forEach(p -> {
+                try {
+                    p.waitFor();        // Wait for it to exit
+                } catch (InterruptedException ie) {
+                    // If interrupted; continue with next Process
+                    Thread.currentThread().interrupt();
+                }
+            });
+            throw ex;
+        }
+        return processes;
+    }
 }
--- a/src/java.base/share/classes/java/lang/String.java	Tue Nov 10 13:46:45 2015 +0300
+++ b/src/java.base/share/classes/java/lang/String.java	Tue Nov 17 10:29:28 2015 -0800
@@ -36,7 +36,6 @@
 import java.util.Objects;
 import java.util.Spliterator;
 import java.util.StringJoiner;
-import java.util.function.IntConsumer;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 import java.util.regex.PatternSyntaxException;
@@ -119,8 +118,19 @@
 
 public final class String
     implements java.io.Serializable, Comparable<String>, CharSequence {
+
     /** The value is used for character storage. */
-    private final char value[];
+    private final byte[] value;
+
+    /**
+     * The identifier of the encoding used to encode the bytes in
+     * {@code value}. The supported values in this implementation are
+     *
+     * LATIN1
+     * UTF16
+     *
+     */
+    private final byte coder;
 
     /** Cache the hash code for the string */
     private int hash; // Default to 0
@@ -129,6 +139,49 @@
     private static final long serialVersionUID = -6849794470754667710L;
 
     /**
+     * If String compaction is disabled, the bytes in {@code value} are
+     * always encoded in UTF16.
+     *
+     * For methods with several possible implementation paths, when String
+     * compaction is disabled, only one code path is taken.
+     *
+     * The instance field value is generally opaque to optimizing JIT
+     * compilers. Therefore, in performance-sensitive place, an explicit
+     * check of the static boolean {@code COMPACT_STRINGS} is done first
+     * before checking the {@code coder} field since the static boolean
+     * {@code COMPACT_STRINGS} would be constant folded away by an
+     * optimizing JIT compiler. The idioms for these cases are as follows.
+     *
+     * For code such as:
+     *
+     *    if (coder == LATIN1) { ... }
+     *
+     * can be written more optimally as
+     *
+     *    if (coder() == LATIN1) { ... }
+     *
+     * or:
+     *
+     *    if (COMPACT_STRINGS && coder == LATIN1) { ... }
+     *
+     * An optimizing JIT compiler can fold the above conditional as:
+     *
+     *    COMPACT_STRINGS == true  => if (coder == LATIN1) { ... }
+     *    COMPACT_STRINGS == false => if (false)           { ... }
+     *
+     * @implNote
+     * The actual value for this field is injected by JVM. The static
+     * initialization block is used to set the value here to communicate
+     * that this static final field is not statically foldable, and to
+     * avoid any possible circular dependency during vm initialization.
+     */
+    static final boolean COMPACT_STRINGS;
+
+    static {
+        COMPACT_STRINGS = true;
+    }
+
+    /**
      * Class String is special cased within the Serialization Stream Protocol.
      *
      * A String instance is written into an ObjectOutputStream according to
@@ -145,6 +198,7 @@
      */
     public String() {
         this.value = "".value;
+        this.coder = "".coder;
     }
 
     /**
@@ -160,6 +214,7 @@
     @HotSpotIntrinsicCandidate
     public String(String original) {
         this.value = original.value;
+        this.coder = original.coder;
         this.hash = original.hash;
     }
 
@@ -173,7 +228,7 @@
      *         The initial value of the string
      */
     public String(char value[]) {
-        this.value = Arrays.copyOf(value, value.length);
+        this(value, 0, value.length, null);
     }
 
     /**
@@ -198,23 +253,12 @@
      *          {@code offset} is greater than {@code value.length - count}
      */
     public String(char value[], int offset, int count) {
-        if (offset < 0) {
-            throw new StringIndexOutOfBoundsException(offset);
-        }
-        if (count <= 0) {
-            if (count < 0) {
-                throw new StringIndexOutOfBoundsException(count);
-            }
-            if (offset <= value.length) {
-                this.value = "".value;
-                return;
-            }
-        }
-        // Note: offset or count might be near -1>>>1.
-        if (offset > value.length - count) {
-            throw new StringIndexOutOfBoundsException(offset + count);
-        }
-        this.value = Arrays.copyOfRange(value, offset, offset + count);
+        this(value, offset, count, rangeCheck(value, offset, count));
+    }
+
+    private static Void rangeCheck(char[] value, int offset, int count) {
+        checkBoundsOffCount(offset, count, value.length);
+        return null;
     }
 
     /**
@@ -246,48 +290,22 @@
      * @since  1.5
      */
     public String(int[] codePoints, int offset, int count) {
-        if (offset < 0) {
-            throw new StringIndexOutOfBoundsException(offset);
+        checkBoundsOffCount(offset, count, codePoints.length);
+        if (count == 0) {
+            this.value = "".value;
+            this.coder = "".coder;
+            return;
         }
-        if (count <= 0) {
-            if (count < 0) {
-                throw new StringIndexOutOfBoundsException(count);
-            }
-            if (offset <= codePoints.length) {
-                this.value = "".value;
+        if (COMPACT_STRINGS) {
+            byte[] val = StringLatin1.toBytes(codePoints, offset, count);
+            if (val != null) {
+                this.coder = LATIN1;
+                this.value = val;
                 return;
             }
         }
-        // Note: offset or count might be near -1>>>1.
-        if (offset > codePoints.length - count) {
-            throw new StringIndexOutOfBoundsException(offset + count);
-        }
-
-        final int end = offset + count;
-
-        // Pass 1: Compute precise size of char[]
-        int n = count;
-        for (int i = offset; i < end; i++) {
-            int c = codePoints[i];
-            if (Character.isBmpCodePoint(c))
-                continue;
-            else if (Character.isValidCodePoint(c))
-                n++;
-            else throw new IllegalArgumentException(Integer.toString(c));
-        }
-
-        // Pass 2: Allocate and fill in char[]
-        final char[] v = new char[n];
-
-        for (int i = offset, j = 0; i < end; i++, j++) {
-            int c = codePoints[i];
-            if (Character.isBmpCodePoint(c))
-                v[j] = (char)c;
-            else
-                Character.toSurrogates(c, v, j++);
-        }
-
-        this.value = v;
+        this.coder = UTF16;
+        this.value = StringUTF16.toBytes(codePoints, offset, count);
     }
 
     /**
@@ -332,20 +350,24 @@
      */
     @Deprecated
     public String(byte ascii[], int hibyte, int offset, int count) {
-        checkBounds(ascii, offset, count);
-        char[] value = new char[count];
-
-        if (hibyte == 0) {
-            for (int i = count; i-- > 0;) {
-                value[i] = (char)(ascii[i + offset] & 0xff);
-            }
+        checkBoundsOffCount(offset, count, ascii.length);
+        if (count == 0) {
+            this.value = "".value;
+            this.coder = "".coder;
+            return;
+        }
+        if (COMPACT_STRINGS && (byte)hibyte == 0) {
+            this.value = Arrays.copyOfRange(ascii, offset, offset + count);
+            this.coder = LATIN1;
         } else {
             hibyte <<= 8;
-            for (int i = count; i-- > 0;) {
-                value[i] = (char)(hibyte | (ascii[i + offset] & 0xff));
+            byte[] val = StringUTF16.newBytesFor(count);
+            for (int i = 0; i < count; i++) {
+                StringUTF16.putChar(val, i, hibyte | (ascii[offset++] & 0xff));
             }
+            this.value = val;
+            this.coder = UTF16;
         }
-        this.value = value;
     }
 
     /**
@@ -383,19 +405,6 @@
         this(ascii, hibyte, 0, ascii.length);
     }
 
-    /* Common private utility method used to bounds check the byte array
-     * and requested offset & length values used by the String(byte[],..)
-     * constructors.
-     */
-    private static void checkBounds(byte[] bytes, int offset, int length) {
-        if (length < 0)
-            throw new StringIndexOutOfBoundsException(length);
-        if (offset < 0)
-            throw new StringIndexOutOfBoundsException(offset);
-        if (offset > bytes.length - length)
-            throw new StringIndexOutOfBoundsException(offset + length);
-    }
-
     /**
      * Constructs a new {@code String} by decoding the specified subarray of
      * bytes using the specified charset.  The length of the new {@code String}
@@ -433,8 +442,11 @@
             throws UnsupportedEncodingException {
         if (charsetName == null)
             throw new NullPointerException("charsetName");
-        checkBounds(bytes, offset, length);
-        this.value = StringCoding.decode(charsetName, bytes, offset, length);
+        checkBoundsOffCount(offset, length, bytes.length);
+        StringCoding.Result ret =
+            StringCoding.decode(charsetName, bytes, offset, length);
+        this.value = ret.value;
+        this.coder = ret.coder;
     }
 
     /**
@@ -470,8 +482,11 @@
     public String(byte bytes[], int offset, int length, Charset charset) {
         if (charset == null)
             throw new NullPointerException("charset");
-        checkBounds(bytes, offset, length);
-        this.value = StringCoding.decode(charset, bytes, offset, length);
+        checkBoundsOffCount(offset, length, bytes.length);
+        StringCoding.Result ret =
+            StringCoding.decode(charset, bytes, offset, length);
+        this.value = ret.value;
+        this.coder = ret.coder;
     }
 
     /**
@@ -553,8 +568,10 @@
      * @since  1.1
      */
     public String(byte bytes[], int offset, int length) {
-        checkBounds(bytes, offset, length);
-        this.value = StringCoding.decode(bytes, offset, length);
+        checkBoundsOffCount(offset, length, bytes.length);
+        StringCoding.Result ret = StringCoding.decode(bytes, offset, length);
+        this.value = ret.value;
+        this.coder = ret.coder;
     }
 
     /**
@@ -587,9 +604,7 @@
      *         A {@code StringBuffer}
      */
     public String(StringBuffer buffer) {
-        synchronized(buffer) {
-            this.value = Arrays.copyOf(buffer.getValue(), buffer.length());
-        }
+        this(buffer.toString());
     }
 
     /**
@@ -608,18 +623,20 @@
      * @since  1.5
      */
     public String(StringBuilder builder) {
-        this.value = Arrays.copyOf(builder.getValue(), builder.length());
+        this(builder, null);
     }
 
-    /*
+   /*
     * Package private constructor which shares value array for speed.
     * this constructor is always expected to be called with share==true.
     * a separate constructor is needed because we already have a public
     * String(char[]) constructor that makes a copy of the given char[].
     */
-    String(char[] value, boolean share) {
+    // TBD: this is kept for package internal use (Thread/System),
+    // should be removed if they all have a byte[] version
+    String(char[] val, boolean share) {
         // assert share : "unshared not supported";
-        this.value = value;
+        this(val, 0, val.length, null);
     }
 
     /**
@@ -631,7 +648,7 @@
      *          object.
      */
     public int length() {
-        return value.length;
+        return value.length >> coder();
     }
 
     /**
@@ -665,10 +682,11 @@
      *             string.
      */
     public char charAt(int index) {
-        if ((index < 0) || (index >= value.length)) {
-            throw new StringIndexOutOfBoundsException(index);
+        if (isLatin1()) {
+            return StringLatin1.charAt(value, index);
+        } else {
+            return StringUTF16.charAt(value, index);
         }
-        return value[index];
     }
 
     /**
@@ -694,10 +712,13 @@
      * @since      1.5
      */
     public int codePointAt(int index) {
-        if ((index < 0) || (index >= value.length)) {
-            throw new StringIndexOutOfBoundsException(index);
+        if (isLatin1()) {
+            checkIndex(index, value.length);
+            return value[index] & 0xff;
         }
-        return Character.codePointAtImpl(value, index, value.length);
+        int length = value.length >> 1;
+        checkIndex(index, length);
+        return StringUTF16.codePointAt(value, index, length);
     }
 
     /**
@@ -724,10 +745,13 @@
      */
     public int codePointBefore(int index) {
         int i = index - 1;
-        if ((i < 0) || (i >= value.length)) {
+        if (i < 0 || i >= length()) {
             throw new StringIndexOutOfBoundsException(index);
         }
-        return Character.codePointBeforeImpl(value, index, 0);
+        if (isLatin1()) {
+            return (value[i] & 0xff);
+        }
+        return StringUTF16.codePointBefore(value, index);
     }
 
     /**
@@ -752,10 +776,14 @@
      * @since  1.5
      */
     public int codePointCount(int beginIndex, int endIndex) {
-        if (beginIndex < 0 || endIndex > value.length || beginIndex > endIndex) {
+        if (beginIndex < 0 || beginIndex > endIndex ||
+            endIndex > length()) {
             throw new IndexOutOfBoundsException();
         }
-        return Character.codePointCountImpl(value, beginIndex, endIndex - beginIndex);
+        if (isLatin1()) {
+            return endIndex - beginIndex;
+        }
+        return StringUTF16.codePointCount(value, beginIndex, endIndex);
     }
 
     /**
@@ -779,19 +807,10 @@
      * @since 1.5
      */
     public int offsetByCodePoints(int index, int codePointOffset) {
-        if (index < 0 || index > value.length) {
+        if (index < 0 || index > length()) {
             throw new IndexOutOfBoundsException();
         }
-        return Character.offsetByCodePointsImpl(value, 0, value.length,
-                index, codePointOffset);
-    }
-
-    /**
-     * Copy characters from this string into dst starting at dstBegin.
-     * This method doesn't perform any range checking.
-     */
-    void getChars(char dst[], int dstBegin) {
-        System.arraycopy(value, 0, dst, dstBegin, value.length);
+        return Character.offsetByCodePoints(this, index, codePointOffset);
     }
 
     /**
@@ -825,16 +844,13 @@
      *                {@code dst.length}</ul>
      */
     public void getChars(int srcBegin, int srcEnd, char dst[], int dstBegin) {
-        if (srcBegin < 0) {
-            throw new StringIndexOutOfBoundsException(srcBegin);
+        checkBoundsBeginEnd(srcBegin, srcEnd, length());
+        checkBoundsOffCount(dstBegin, srcEnd - srcBegin, dst.length);
+        if (isLatin1()) {
+            StringLatin1.getChars(value, srcBegin, srcEnd, dst, dstBegin);
+        } else {
+            StringUTF16.getChars(value, srcBegin, srcEnd, dst, dstBegin);
         }
-        if (srcEnd > value.length) {
-            throw new StringIndexOutOfBoundsException(srcEnd);
-        }
-        if (srcBegin > srcEnd) {
-            throw new StringIndexOutOfBoundsException(srcEnd - srcBegin);
-        }
-        System.arraycopy(value, srcBegin, dst, dstBegin, srcEnd - srcBegin);
     }
 
     /**
@@ -882,24 +898,13 @@
      */
     @Deprecated
     public void getBytes(int srcBegin, int srcEnd, byte dst[], int dstBegin) {
-        if (srcBegin < 0) {
-            throw new StringIndexOutOfBoundsException(srcBegin);
-        }
-        if (srcEnd > value.length) {
-            throw new StringIndexOutOfBoundsException(srcEnd);
-        }
-        if (srcBegin > srcEnd) {
-            throw new StringIndexOutOfBoundsException(srcEnd - srcBegin);
-        }
+        checkBoundsBeginEnd(srcBegin, srcEnd, length());
         Objects.requireNonNull(dst);
-
-        int j = dstBegin;
-        int n = srcEnd;
-        int i = srcBegin;
-        char[] val = value;   /* avoid getfield opcode */
-
-        while (i < n) {
-            dst[j++] = (byte)val[i++];
+        checkBoundsOffCount(dstBegin, srcEnd - srcBegin, dst.length);
+        if (isLatin1()) {
+            StringLatin1.getBytes(value, srcBegin, srcEnd, dst, dstBegin);
+        } else {
+            StringUTF16.getBytes(value, srcBegin, srcEnd, dst, dstBegin);
         }
     }
 
@@ -926,7 +931,7 @@
     public byte[] getBytes(String charsetName)
             throws UnsupportedEncodingException {
         if (charsetName == null) throw new NullPointerException();
-        return StringCoding.encode(charsetName, value, 0, value.length);
+        return StringCoding.encode(charsetName, coder(), value);
     }
 
     /**
@@ -949,8 +954,8 @@
      */
     public byte[] getBytes(Charset charset) {
         if (charset == null) throw new NullPointerException();
-        return StringCoding.encode(charset, value, 0, value.length);
-    }
+        return StringCoding.encode(charset, coder(), value);
+     }
 
     /**
      * Encodes this {@code String} into a sequence of bytes using the
@@ -966,7 +971,7 @@
      * @since      1.1
      */
     public byte[] getBytes() {
-        return StringCoding.encode(value, 0, value.length);
+        return StringCoding.encode(coder(), value);
     }
 
     /**
@@ -987,23 +992,15 @@
      * @see  #compareTo(String)
      * @see  #equalsIgnoreCase(String)
      */
-    @HotSpotIntrinsicCandidate
     public boolean equals(Object anObject) {
         if (this == anObject) {
             return true;
         }
         if (anObject instanceof String) {
-            char[] v1 = value;
-            char[] v2 = ((String)anObject).value;
-            int n = v1.length;
-            if (n == v2.length) {
-                int i = 0;
-                while (n-- != 0) {
-                    if (v1[i] != v2[i])
-                        return false;
-                    i++;
-                }
-                return true;
+            String aString = (String)anObject;
+            if (coder() == aString.coder()) {
+                return isLatin1() ? StringLatin1.equals(value, aString.value)
+                                  : StringUTF16.equals(value, aString.value);
             }
         }
         return false;
@@ -1032,16 +1029,28 @@
     }
 
     private boolean nonSyncContentEquals(AbstractStringBuilder sb) {
-        char[] v1 = value;
-        char[] v2 = sb.getValue();
-        int n = v1.length;
-        if (n != sb.length()) {
+        int len = length();
+        if (len != sb.length()) {
             return false;
         }
-        for (int i = 0; i < n; i++) {
-            if (v1[i] != v2[i]) {
+        byte v1[] = value;
+        byte v2[] = sb.getValue();
+        if (coder() == sb.getCoder()) {
+            int n = v1.length;
+            for (int i = 0; i < n; i++) {
+                if (v1[i] != v2[i]) {
+                    return false;
+                }
+            }
+        } else {
+            if (!isLatin1()) {  // utf16 str and latin1 abs can never be "equal"
                 return false;
             }
+            for (int i = 0; i < len; i++) {
+                if ((char)(v1[i] & 0xff) != StringUTF16.getChar(v2, i)) {
+                    return false;
+                }
+            }
         }
         return true;
     }
@@ -1081,14 +1090,22 @@
             return equals(cs);
         }
         // Argument is a generic CharSequence
-        char[] v1 = value;
-        int n = v1.length;
-        if (n != cs.length()) {
+        int n = cs.length();
+        if (n != length()) {
             return false;
         }
-        for (int i = 0; i < n; i++) {
-            if (v1[i] != cs.charAt(i)) {
-                return false;
+        byte[] val = this.value;
+        if (isLatin1()) {
+            for (int i = 0; i < n; i++) {
+                if ((val[i] & 0xff) != cs.charAt(i)) {
+                    return false;
+                }
+            }
+        } else {
+            for (int i = 0; i < n; i++) {
+                if (StringUTF16.getChar(val, i) != cs.charAt(i)) {
+                    return false;
+                }
             }
         }
         return true;
@@ -1125,8 +1142,8 @@
     public boolean equalsIgnoreCase(String anotherString) {
         return (this == anotherString) ? true
                 : (anotherString != null)
-                && (anotherString.value.length == value.length)
-                && regionMatches(true, 0, anotherString, 0, value.length);
+                && (anotherString.length() == length())
+                && regionMatches(true, 0, anotherString, 0, length());
     }
 
     /**
@@ -1173,23 +1190,16 @@
      *          value greater than {@code 0} if this string is
      *          lexicographically greater than the string argument.
      */
-    @HotSpotIntrinsicCandidate
     public int compareTo(String anotherString) {
-        char[] v1 = value;
-        char[] v2 = anotherString.value;
-        int len1 = v1.length;
-        int len2 = v2.length;
-        int lim = Math.min(len1, len2);
-
-        for (int k = 0; k < lim; k++) {
-            char c1 = v1[k];
-            char c2 = v2[k];
-            if (c1 != c2) {
-                return c1 - c2;
-            }
+        byte v1[] = value;
+        byte v2[] = anotherString.value;
+        if (coder() == anotherString.coder()) {
+            return isLatin1() ? StringLatin1.compareTo(v1, v2)
+                              : StringUTF16.compareTo(v1, v2);
         }
-        return len1 - len2;
-    }
+        return isLatin1() ? StringLatin1.compareToUTF16(v1, v2)
+                          : StringUTF16.compareToLatin1(v1, v2);
+     }
 
     /**
      * A Comparator that orders {@code String} objects as by
@@ -1210,12 +1220,18 @@
         private static final long serialVersionUID = 8575799808933029326L;
 
         public int compare(String s1, String s2) {
+            byte v1[] = s1.value;
+            byte v2[] = s2.value;
             int n1 = s1.length();
             int n2 = s2.length();
+            boolean s1IsLatin1 = s1.isLatin1();
+            boolean s2IsLatin1 = s2.isLatin1();
             int min = Math.min(n1, n2);
             for (int i = 0; i < min; i++) {
-                char c1 = s1.charAt(i);
-                char c2 = s2.charAt(i);
+                char c1 = s1IsLatin1 ? StringLatin1.getChar(v1, i)
+                                     : StringUTF16.getChar(v1, i);
+                char c2 = s2IsLatin1 ? StringLatin1.getChar(v2, i)
+                                     : StringUTF16.getChar(v2, i);
                 if (c1 != c2) {
                     c1 = Character.toUpperCase(c1);
                     c2 = Character.toUpperCase(c2);
@@ -1294,21 +1310,41 @@
      *          exactly matches the specified subregion of the string argument;
      *          {@code false} otherwise.
      */
-    public boolean regionMatches(int toffset, String other, int ooffset,
-            int len) {
-        char[] ta = value;
-        int to = toffset;
-        char[] pa = other.value;
-        int po = ooffset;
+    public boolean regionMatches(int toffset, String other, int ooffset, int len) {
+        byte tv[] = value;
+        byte ov[] = other.value;
         // Note: toffset, ooffset, or len might be near -1>>>1.
-        if ((ooffset < 0) || (toffset < 0)
-                || (toffset > (long)ta.length - len)
-                || (ooffset > (long)pa.length - len)) {
+        if ((ooffset < 0) || (toffset < 0) ||
+             (toffset > (long)length() - len) ||
+             (ooffset > (long)other.length() - len)) {
             return false;
         }
-        while (len-- > 0) {
-            if (ta[to++] != pa[po++]) {
-                return false;
+        if (coder() == other.coder()) {
+            if (!isLatin1() && (len > 0)) {
+                toffset = toffset << 1;
+                ooffset = ooffset << 1;
+                len = len << 1;
+            }
+            while (len-- > 0) {
+                if (tv[toffset++] != ov[ooffset++]) {
+                    return false;
+                }
+            }
+        } else {
+            if (coder() == LATIN1) {
+                while (len-- > 0) {
+                    if (StringLatin1.getChar(tv, toffset++) !=
+                        StringUTF16.getChar(ov, ooffset++)) {
+                        return false;
+                    }
+                }
+            } else {
+                while (len-- > 0) {
+                    if (StringUTF16.getChar(tv, toffset++) !=
+                        StringLatin1.getChar(ov, ooffset++)) {
+                        return false;
+                    }
+                }
             }
         }
         return true;
@@ -1366,43 +1402,25 @@
      */
     public boolean regionMatches(boolean ignoreCase, int toffset,
             String other, int ooffset, int len) {
-        char[] ta = value;
-        int to = toffset;
-        char[] pa = other.value;
-        int po = ooffset;
+        if (!ignoreCase) {
+            return regionMatches(toffset, other, ooffset, len);
+        }
         // Note: toffset, ooffset, or len might be near -1>>>1.
         if ((ooffset < 0) || (toffset < 0)
-                || (toffset > (long)ta.length - len)
-                || (ooffset > (long)pa.length - len)) {
+                || (toffset > (long)length() - len)
+                || (ooffset > (long)other.length() - len)) {
             return false;
         }
-        while (len-- > 0) {
-            char c1 = ta[to++];
-            char c2 = pa[po++];
-            if (c1 == c2) {
-                continue;
-            }
-            if (ignoreCase) {
-                // If characters don't match but case may be ignored,
-                // try converting both characters to uppercase.
-                // If the results match, then the comparison scan should
-                // continue.
-                char u1 = Character.toUpperCase(c1);
-                char u2 = Character.toUpperCase(c2);
-                if (u1 == u2) {
-                    continue;
-                }
-                // Unfortunately, conversion to uppercase does not work properly
-                // for the Georgian alphabet, which has strange rules about case
-                // conversion.  So we need to make one last check before
-                // exiting.
-                if (Character.toLowerCase(u1) == Character.toLowerCase(u2)) {
-                    continue;
-                }
-            }
-            return false;
+        byte tv[] = value;
+        byte ov[] = other.value;
+        if (coder() == other.coder()) {
+            return isLatin1()
+              ? StringLatin1.regionMatchesCI(tv, toffset, ov, ooffset, len)
+              : StringUTF16.regionMatchesCI(tv, toffset, ov, ooffset, len);
         }
-        return true;
+        return isLatin1()
+              ? StringLatin1.regionMatchesCI_UTF16(tv, toffset, ov, ooffset, len)
+              : StringUTF16.regionMatchesCI_Latin1(tv, toffset, ov, ooffset, len);
     }
 
     /**
@@ -1423,19 +1441,31 @@
      *          </pre>
      */
     public boolean startsWith(String prefix, int toffset) {
-        char[] ta = value;
-        int to = toffset;
-        char[] pa = prefix.value;
+        // Note: toffset might be near -1>>>1.
+        if (toffset < 0 || toffset > length() - prefix.length()) {
+            return false;
+        }
+        byte ta[] = value;
+        byte pa[] = prefix.value;
         int po = 0;
         int pc = pa.length;
-        // Note: toffset might be near -1>>>1.
-        if ((toffset < 0) || (toffset > ta.length - pc)) {
-            return false;
-        }
-        while (--pc >= 0) {
-            if (ta[to++] != pa[po++]) {
+        if (coder() == prefix.coder()) {
+            int to = isLatin1() ? toffset : toffset << 1;
+            while (po < pc) {
+                if (ta[to++] != pa[po++]) {
+                    return false;
+                }
+            }
+        } else {
+            if (isLatin1()) {  // && pcoder == UTF16
                 return false;
             }
+            // coder == UTF16 && pcoder == LATIN1)
+            while (po < pc) {
+                if (StringUTF16.getChar(ta, toffset++) != (pa[po++] & 0xff)) {
+                    return false;
+               }
+            }
         }
         return true;
     }
@@ -1469,7 +1499,7 @@
      *          as determined by the {@link #equals(Object)} method.
      */
     public boolean endsWith(String suffix) {
-        return startsWith(suffix, value.length - suffix.value.length);
+        return startsWith(suffix, length() - suffix.length());
     }
 
     /**
@@ -1486,16 +1516,11 @@
      * @return  a hash code value for this object.
      */
     public int hashCode() {
-        int h = hash;
-        if (h == 0) {
-            for (char v : value) {
-                h = 31 * h + v;
-            }
-            if (h != 0) {
-                hash = h;
-            }
+        if (hash == 0 && value.length > 0) {
+            hash = isLatin1() ? StringLatin1.hashCode(value)
+                              : StringUTF16.hashCode(value);
         }
-        return h;
+        return hash;
     }
 
     /**
@@ -1566,45 +1591,8 @@
      *          if the character does not occur.
      */
     public int indexOf(int ch, int fromIndex) {
-        final int max = value.length;
-        if (fromIndex < 0) {
-            fromIndex = 0;
-        } else if (fromIndex >= max) {
-            // Note: fromIndex might be near -1>>>1.
-            return -1;
-        }
-
-        if (ch < Character.MIN_SUPPLEMENTARY_CODE_POINT) {
-            // handle most cases here (ch is a BMP code point or a
-            // negative value (invalid code point))
-            final char[] value = this.value;
-            for (int i = fromIndex; i < max; i++) {
-                if (value[i] == ch) {
-                    return i;
-                }
-            }
-            return -1;
-        } else {
-            return indexOfSupplementary(ch, fromIndex);
-        }
-    }
-
-    /**
-     * Handles (rare) calls of indexOf with a supplementary character.
-     */
-    private int indexOfSupplementary(int ch, int fromIndex) {
-        if (Character.isValidCodePoint(ch)) {
-            final char[] value = this.value;
-            final char hi = Character.highSurrogate(ch);
-            final char lo = Character.lowSurrogate(ch);
-            final int max = value.length - 1;
-            for (int i = fromIndex; i < max; i++) {
-                if (value[i] == hi && value[i + 1] == lo) {
-                    return i;
-                }
-            }
-        }
-        return -1;
+        return isLatin1() ? StringLatin1.indexOf(value, ch, fromIndex)
+                          : StringUTF16.indexOf(value, ch, fromIndex);
     }
 
     /**
@@ -1631,7 +1619,7 @@
      *          {@code -1} if the character does not occur.
      */
     public int lastIndexOf(int ch) {
-        return lastIndexOf(ch, value.length - 1);
+        return lastIndexOf(ch, length() - 1);
     }
 
     /**
@@ -1669,38 +1657,8 @@
      *          if the character does not occur before that point.
      */
     public int lastIndexOf(int ch, int fromIndex) {
-        if (ch < Character.MIN_SUPPLEMENTARY_CODE_POINT) {
-            // handle most cases here (ch is a BMP code point or a
-            // negative value (invalid code point))
-            final char[] value = this.value;
-            int i = Math.min(fromIndex, value.length - 1);
-            for (; i >= 0; i--) {
-                if (value[i] == ch) {
-                    return i;
-                }
-            }
-            return -1;
-        } else {
-            return lastIndexOfSupplementary(ch, fromIndex);
-        }
-    }
-
-    /**
-     * Handles (rare) calls of lastIndexOf with a supplementary character.
-     */
-    private int lastIndexOfSupplementary(int ch, int fromIndex) {
-        if (Character.isValidCodePoint(ch)) {
-            final char[] value = this.value;
-            char hi = Character.highSurrogate(ch);
-            char lo = Character.lowSurrogate(ch);
-            int i = Math.min(fromIndex, value.length - 2);
-            for (; i >= 0; i--) {
-                if (value[i] == hi && value[i + 1] == lo) {
-                    return i;
-                }
-            }
-        }
-        return -1;
+        return isLatin1() ? StringLatin1.lastIndexOf(value, ch, fromIndex)
+                          : StringUTF16.lastIndexOf(value, ch, fromIndex);
     }
 
     /**
@@ -1717,9 +1675,15 @@
      * @return  the index of the first occurrence of the specified substring,
      *          or {@code -1} if there is no such occurrence.
      */
-    @HotSpotIntrinsicCandidate
     public int indexOf(String str) {
-        return indexOf(str, 0);
+        if (coder() == str.coder()) {
+            return isLatin1() ? StringLatin1.indexOf(value, str.value)
+                              : StringUTF16.indexOf(value, str.value);
+        }
+        if (coder() == LATIN1) {  // str.coder == UTF16
+            return -1;
+        }
+        return StringUTF16.indexOfLatin1(value, str.value);
     }
 
     /**
@@ -1740,8 +1704,7 @@
      *          or {@code -1} if there is no such occurrence.
      */
     public int indexOf(String str, int fromIndex) {
-        return indexOf(value, 0, value.length,
-                str.value, 0, str.value.length, fromIndex);
+        return indexOf(value, coder(), length(), str, fromIndex);
     }
 
     /**
@@ -1749,68 +1712,38 @@
      * source is the character array being searched, and the target
      * is the string being searched for.
      *
-     * @param   source       the characters being searched.
-     * @param   sourceOffset offset of the source string.
-     * @param   sourceCount  count of the source string.
-     * @param   target       the characters being searched for.
-     * @param   fromIndex    the index to begin searching from.
+     * @param   src       the characters being searched.
+     * @param   srcCoder  the coder of the source string.
+     * @param   srcCount  length of the source string.
+     * @param   tgtStr    the characters being searched for.
+     * @param   fromIndex the index to begin searching from.
      */
-    static int indexOf(char[] source, int sourceOffset, int sourceCount,
-            String target, int fromIndex) {
-        return indexOf(source, sourceOffset, sourceCount,
-                       target.value, 0, target.value.length,
-                       fromIndex);
-    }
+    static int indexOf(byte[] src, byte srcCoder, int srcCount,
+                       String tgtStr, int fromIndex) {
 
-    /**
-     * Code shared by String and StringBuffer to do searches. The
-     * source is the character array being searched, and the target
-     * is the string being searched for.
-     *
-     * @param   source       the characters being searched.
-     * @param   sourceOffset offset of the source string.
-     * @param   sourceCount  count of the source string.
-     * @param   target       the characters being searched for.
-     * @param   targetOffset offset of the target string.
-     * @param   targetCount  count of the target string.
-     * @param   fromIndex    the index to begin searching from.
-     */
-    static int indexOf(char[] source, int sourceOffset, int sourceCount,
-            char[] target, int targetOffset, int targetCount,
-            int fromIndex) {
-        if (fromIndex >= sourceCount) {
-            return (targetCount == 0 ? sourceCount : -1);
+        byte[] tgt    = tgtStr.value;
+        byte tgtCoder = tgtStr.coder();
+        int tgtCount  = tgtStr.length();
+
+        if (fromIndex >= srcCount) {
+            return (tgtCount == 0 ? srcCount : -1);
         }
         if (fromIndex < 0) {
             fromIndex = 0;
         }
-        if (targetCount == 0) {
+        if (tgtCount == 0) {
             return fromIndex;
         }
-
-        char first = target[targetOffset];
-        int max = sourceOffset + (sourceCount - targetCount);
-
-        for (int i = sourceOffset + fromIndex; i <= max; i++) {
-            /* Look for first character. */
-            if (source[i] != first) {
-                while (++i <= max && source[i] != first);
-            }
-
-            /* Found first character, now look at the rest of v2 */
-            if (i <= max) {
-                int j = i + 1;
-                int end = j + targetCount - 1;
-                for (int k = targetOffset + 1; j < end && source[j]
-                        == target[k]; j++, k++);
-
-                if (j == end) {
-                    /* Found whole string. */
-                    return i - sourceOffset;
-                }
-            }
+        if (srcCoder == tgtCoder) {
+            return srcCoder == LATIN1
+                ? StringLatin1.indexOf(src, srcCount, tgt, tgtCount, fromIndex)
+                : StringUTF16.indexOf(src, srcCount, tgt, tgtCount, fromIndex);
         }
-        return -1;
+        if (srcCoder == LATIN1) {    //  && tgtCoder == UTF16
+            return -1;
+        }
+        // srcCoder == UTF16 && tgtCoder == LATIN1) {
+        return StringUTF16.indexOfLatin1(src, srcCount, tgt, tgtCount, fromIndex);
     }
 
     /**
@@ -1829,7 +1762,7 @@
      *          or {@code -1} if there is no such occurrence.
      */
     public int lastIndexOf(String str) {
-        return lastIndexOf(str, value.length);
+        return lastIndexOf(str, length());
     }
 
     /**
@@ -1850,8 +1783,7 @@
      *          or {@code -1} if there is no such occurrence.
      */
     public int lastIndexOf(String str, int fromIndex) {
-        return lastIndexOf(value, 0, value.length,
-                str.value, 0, str.value.length, fromIndex);
+        return lastIndexOf(value, coder(), length(), str, fromIndex);
     }
 
     /**
@@ -1859,40 +1791,22 @@
      * source is the character array being searched, and the target
      * is the string being searched for.
      *
-     * @param   source       the characters being searched.
-     * @param   sourceOffset offset of the source string.
-     * @param   sourceCount  count of the source string.
-     * @param   target       the characters being searched for.
-     * @param   fromIndex    the index to begin searching from.
+     * @param   src         the characters being searched.
+     * @param   srcCoder  coder handles the mapping between bytes/chars
+     * @param   srcCount    count of the source string.
+     * @param   tgt         the characters being searched for.
+     * @param   fromIndex   the index to begin searching from.
      */
-    static int lastIndexOf(char[] source, int sourceOffset, int sourceCount,
-            String target, int fromIndex) {
-        return lastIndexOf(source, sourceOffset, sourceCount,
-                       target.value, 0, target.value.length,
-                       fromIndex);
-    }
-
-    /**
-     * Code shared by String and StringBuffer to do searches. The
-     * source is the character array being searched, and the target
-     * is the string being searched for.
-     *
-     * @param   source       the characters being searched.
-     * @param   sourceOffset offset of the source string.
-     * @param   sourceCount  count of the source string.
-     * @param   target       the characters being searched for.
-     * @param   targetOffset offset of the target string.
-     * @param   targetCount  count of the target string.
-     * @param   fromIndex    the index to begin searching from.
-     */
-    static int lastIndexOf(char[] source, int sourceOffset, int sourceCount,
-            char[] target, int targetOffset, int targetCount,
-            int fromIndex) {
+    static int lastIndexOf(byte[] src, byte srcCoder, int srcCount,
+                           String tgtStr, int fromIndex) {
+        byte[] tgt = tgtStr.value;
+        byte tgtCoder = tgtStr.coder();
+        int tgtCount = tgtStr.length();
         /*
          * Check arguments; return immediately where possible. For
          * consistency, don't check for null str.
          */
-        int rightIndex = sourceCount - targetCount;
+        int rightIndex = srcCount - tgtCount;
         if (fromIndex < 0) {
             return -1;
         }
@@ -1900,34 +1814,41 @@
             fromIndex = rightIndex;
         }
         /* Empty string always matches. */
-        if (targetCount == 0) {
+        if (tgtCount == 0) {
             return fromIndex;
         }
+        if (srcCoder == tgtCoder) {
+            return srcCoder == LATIN1
+                ? StringLatin1.lastIndexOf(src, srcCount, tgt, tgtCount, fromIndex)
+                : StringUTF16.lastIndexOf(src, srcCount, tgt, tgtCount, fromIndex);
+        }
+        if (srcCoder == LATIN1) {    // && tgtCoder == UTF16
+            return -1;
+        }
+                                     // srcCoder == UTF16 && tgtCoder == LATIN1
+        int min = tgtCount - 1;
+        int i = min + fromIndex;
+        int strLastIndex = tgtCount - 1;
 
-        int strLastIndex = targetOffset + targetCount - 1;
-        char strLastChar = target[strLastIndex];
-        int min = sourceOffset + targetCount - 1;
-        int i = min + fromIndex;
-
+        char strLastChar = (char)(tgt[strLastIndex] & 0xff);
     startSearchForLastChar:
         while (true) {
-            while (i >= min && source[i] != strLastChar) {
+            while (i >= min && StringUTF16.getChar(src, i) != strLastChar) {
                 i--;
             }
             if (i < min) {
                 return -1;
             }
             int j = i - 1;
-            int start = j - (targetCount - 1);
+            int start = j - strLastIndex;
             int k = strLastIndex - 1;
-
             while (j > start) {
-                if (source[j--] != target[k--]) {
+                if (StringUTF16.getChar(src, j--) != (tgt[k--] & 0xff)) {
                     i--;
                     continue startSearchForLastChar;
                 }
             }
-            return start - sourceOffset + 1;
+            return start + 1;
         }
     }
 
@@ -1949,17 +1870,18 @@
      *             length of this {@code String} object.
      */
     public String substring(int beginIndex) {
-        if (beginIndex <= 0) {
-            if (beginIndex < 0) {
-                throw new StringIndexOutOfBoundsException(beginIndex);
-            }
-            return this;
+        if (beginIndex < 0) {
+            throw new StringIndexOutOfBoundsException(beginIndex);
         }
-        int subLen = value.length - beginIndex;
+        int subLen = length() - beginIndex;
         if (subLen < 0) {
             throw new StringIndexOutOfBoundsException(subLen);
         }
-        return new String(value, beginIndex, subLen);
+        if (beginIndex == 0) {
+            return this;
+        }
+        return isLatin1() ? StringLatin1.newString(value, beginIndex, subLen)
+                          : StringUTF16.newString(value, beginIndex, subLen);
     }
 
     /**
@@ -1985,22 +1907,14 @@
      *             {@code endIndex}.
      */
     public String substring(int beginIndex, int endIndex) {
-        if (beginIndex <= 0) {
-            if (beginIndex < 0) {
-                throw new StringIndexOutOfBoundsException(beginIndex);
-            }
-            if (endIndex == value.length) {
-                return this;
-            }
+        int length = length();
+        checkBoundsBeginEnd(beginIndex, endIndex, length);
+        int subLen = endIndex - beginIndex;
+        if (beginIndex == 0 && endIndex == length) {
+            return this;
         }
-        if (endIndex > value.length) {
-            throw new StringIndexOutOfBoundsException(endIndex);
-        }
-        int subLen = endIndex - beginIndex;
-        if (subLen < 0) {
-            throw new StringIndexOutOfBoundsException(subLen);
-        }
-        return new String(value, beginIndex, subLen);
+        return isLatin1() ? StringLatin1.newString(value, beginIndex, subLen)
+                          : StringUTF16.newString(value, beginIndex, subLen);
     }
 
     /**
@@ -2057,14 +1971,23 @@
      *          characters followed by the string argument's characters.
      */
     public String concat(String str) {
-        int otherLen = str.length();
-        if (otherLen == 0) {
+        int olen = str.length();
+        if (olen == 0) {
             return this;
         }
-        int len = value.length;
-        char[] buf = Arrays.copyOf(value, len + otherLen);
-        str.getChars(buf, len);
-        return new String(buf, true);
+        if (coder() == str.coder()) {
+            byte[] val = this.value;
+            byte[] oval = str.value;
+            int len = val.length + oval.length;
+            byte[] buf = Arrays.copyOf(val, len);
+            System.arraycopy(oval, 0, buf, val.length, oval.length);
+            return new String(buf, coder);
+        }
+        int len = length();
+        byte[] buf = StringUTF16.newBytesFor(len + olen);
+        getBytes(buf, 0, UTF16);
+        str.getBytes(buf, len, UTF16);
+        return new String(buf, UTF16);
     }
 
     /**
@@ -2098,26 +2021,10 @@
      */
     public String replace(char oldChar, char newChar) {
         if (oldChar != newChar) {
-            char[] val = value; /* avoid getfield opcode */
-            int len = val.length;
-            int i = -1;
-
-            while (++i < len) {
-                if (val[i] == oldChar) {
-                    break;
-                }
-            }
-            if (i < len) {
-                char[] buf = new char[len];
-                for (int j = 0; j < i; j++) {
-                    buf[j] = val[j];
-                }
-                while (i < len) {
-                    char c = val[i];
-                    buf[i] = (c == oldChar) ? newChar : c;
-                    i++;
-                }
-                return new String(buf, true);
+            String ret = isLatin1() ? StringLatin1.replace(value, oldChar, newChar)
+                                    : StringUTF16.replace(value, oldChar, newChar);
+            if (ret != null) {
+                return ret;
             }
         }
         return this;
@@ -2269,29 +2176,27 @@
      * @since 1.5
      */
     public String replace(CharSequence target, CharSequence replacement) {
-        String starget = target.toString();
-        String srepl = replacement.toString();
-        int j = indexOf(starget);
+        String tgtStr = target.toString();
+        String replStr = replacement.toString();
+        int j = indexOf(tgtStr);
         if (j < 0) {
             return this;
         }
-        int targLen = starget.length();
-        int targLen1 = Math.max(targLen, 1);
-        final char[] value = this.value;
-        final char[] replValue = srepl.value;
-        int newLenHint = value.length - targLen + replValue.length;
+        int tgtLen = tgtStr.length();
+        int tgtLen1 = Math.max(tgtLen, 1);
+        int thisLen = length();
+
+        int newLenHint = thisLen - tgtLen + replStr.length();
         if (newLenHint < 0) {
             throw new OutOfMemoryError();
         }
         StringBuilder sb = new StringBuilder(newLenHint);
         int i = 0;
         do {
-            sb.append(value, i, j - i)
-                    .append(replValue);
-            i = j + targLen;
-        } while (j < value.length && (j = indexOf(starget, j + targLen1)) > 0);
-
-        return sb.append(value, i, value.length - i).toString();
+            sb.append(this, i, j).append(replStr);
+            i = j + tgtLen;
+        } while (j < thisLen && (j = indexOf(tgtStr, j + tgtLen1)) > 0);
+        return sb.append(this, i, thisLen).toString();
     }
 
     /**
@@ -2388,7 +2293,7 @@
             the second is not the ascii digit or ascii letter.
          */
         char ch = 0;
-        if (((regex.value.length == 1 &&
+        if (((regex.length() == 1 &&
              ".$|()[{^?*+\\".indexOf(ch = regex.charAt(0)) == -1) ||
              (regex.length() == 2 &&
               regex.charAt(0) == '\\' &&
@@ -2408,8 +2313,9 @@
                     off = next + 1;
                 } else {    // last one
                     //assert (list.size() == limit - 1);
-                    list.add(substring(off, value.length));
-                    off = value.length;
+                    int last = length();
+                    list.add(substring(off, last));
+                    off = last;
                     break;
                 }
             }
@@ -2419,7 +2325,7 @@
 
             // Add remaining segment
             if (!limited || list.size() < limit)
-                list.add(substring(off, value.length));
+                list.add(substring(off, length()));
 
             // Construct result
             int resultSize = list.size();
@@ -2613,95 +2519,8 @@
      * @since   1.1
      */
     public String toLowerCase(Locale locale) {
-        if (locale == null) {
-            throw new NullPointerException();
-        }
-        int first;
-        boolean hasSurr = false;
-        final int len = value.length;
-
-        // Now check if there are any characters that need to be changed, or are surrogate
-        for (first = 0 ; first < len; first++) {
-            int cp = (int)value[first];
-            if (Character.isSurrogate((char)cp)) {
-                hasSurr = true;
-                break;
-            }
-            if (cp != Character.toLowerCase(cp)) {  // no need to check Character.ERROR
-                break;
-            }
-        }
-        if (first == len)
-            return this;
-        char[] result = new char[len];
-        System.arraycopy(value, 0, result, 0, first);  // Just copy the first few
-                                                       // lowerCase characters.
-        String lang = locale.getLanguage();
-        if (lang == "tr" || lang == "az" || lang == "lt") {
-            return toLowerCaseEx(result, first, locale, true);
-        }
-        if (hasSurr) {
-            return toLowerCaseEx(result, first, locale, false);
-        }
-        for (int i = first; i < len; i++) {
-            int cp = (int)value[i];
-            if (cp == '\u03A3' ||                       // GREEK CAPITAL LETTER SIGMA
-                Character.isSurrogate((char)cp)) {
-                return toLowerCaseEx(result, i, locale, false);
-            }
-            if (cp == '\u0130') {                       // LATIN CAPITAL LETTER I WITH DOT ABOVE
-                return toLowerCaseEx(result, i, locale, true);
-            }
-            cp = Character.toLowerCase(cp);
-            if (!Character.isBmpCodePoint(cp)) {
-                return toLowerCaseEx(result, i, locale, false);
-            }
-            result[i] = (char)cp;
-        }
-        return new String(result, true);
-    }
-
-    private String toLowerCaseEx(char[] result, int first, Locale locale, boolean localeDependent) {
-        int resultOffset = first;
-        int srcCount;
-        for (int i = first; i < value.length; i += srcCount) {
-            int srcChar = (int)value[i];
-            int lowerChar;
-            char[] lowerCharArray;
-            srcCount = 1;
-            if (Character.isSurrogate((char)srcChar)) {
-                srcChar = codePointAt(i);
-                srcCount = Character.charCount(srcChar);
-            }
-            if (localeDependent || srcChar == '\u03A3') { // GREEK CAPITAL LETTER SIGMA
-                lowerChar = ConditionalSpecialCasing.toLowerCaseEx(this, i, locale);
-            } else {
-                lowerChar = Character.toLowerCase(srcChar);
-            }
-            if (Character.isBmpCodePoint(lowerChar)) {    // Character.ERROR is not a bmp
-                result[resultOffset++] = (char)lowerChar;
-            } else {
-                if (lowerChar == Character.ERROR) {
-                    lowerCharArray = ConditionalSpecialCasing.toLowerCaseCharArray(this, i, locale);
-                } else if (srcCount == 2) {
-                    resultOffset += Character.toChars(lowerChar, result, resultOffset);
-                    continue;
-                } else {
-                    lowerCharArray = Character.toChars(lowerChar);
-                }
-                /* Grow result if needed */
-                int mapLen = lowerCharArray.length;
-                if (mapLen > srcCount) {
-                    char[] result2 = new char[result.length + mapLen - srcCount];
-                    System.arraycopy(result, 0, result2, 0, resultOffset);
-                    result = result2;
-                }
-                for (int x = 0; x < mapLen; ++x) {
-                    result[resultOffset++] = lowerCharArray[x];
-                }
-            }
-        }
-        return new String(result, 0, resultOffset);
+        return isLatin1() ? StringLatin1.toLowerCase(this, value, locale)
+                          : StringUTF16.toLowerCase(this, value, locale);
     }
 
     /**
@@ -2776,98 +2595,8 @@
      * @since   1.1
      */
     public String toUpperCase(Locale locale) {
-        if (locale == null) {
-            throw new NullPointerException();
-        }
-        int first;
-        boolean hasSurr = false;
-        final int len = value.length;
-
-        // Now check if there are any characters that need to be changed, or are surrogate
-        for (first = 0 ; first < len; first++ ) {
-            int cp = (int)value[first];
-            if (Character.isSurrogate((char)cp)) {
-                hasSurr = true;
-                break;
-            }
-            if (cp != Character.toUpperCaseEx(cp)) {   // no need to check Character.ERROR
-                break;
-            }
-        }
-        if (first == len) {
-            return this;
-        }
-        char[] result = new char[len];
-        System.arraycopy(value, 0, result, 0, first);  // Just copy the first few
-                                                       // upperCase characters.
-        String lang = locale.getLanguage();
-        if (lang == "tr" || lang == "az" || lang == "lt") {
-            return toUpperCaseEx(result, first, locale, true);
-        }
-        if (hasSurr) {
-            return toUpperCaseEx(result, first, locale, false);
-        }
-        for (int i = first; i < len; i++) {
-            int cp = (int)value[i];
-            if (Character.isSurrogate((char)cp)) {
-                return toUpperCaseEx(result, i, locale, false);
-            }
-            cp = Character.toUpperCaseEx(cp);
-            if (!Character.isBmpCodePoint(cp)) {    // Character.ERROR is not bmp
-                return toUpperCaseEx(result, i, locale, false);
-            }
-            result[i] = (char)cp;
-        }
-        return new String(result, true);
-    }
-
-    private String toUpperCaseEx(char[] result, int first, Locale locale,
-                                 boolean localeDependent) {
-        int resultOffset = first;
-        int srcCount;
-        for (int i = first; i < value.length; i += srcCount) {
-            int srcChar = (int)value[i];
-            int upperChar;
-            char[] upperCharArray;
-            srcCount = 1;
-            if (Character.isSurrogate((char)srcChar)) {
-                srcChar = codePointAt(i);
-                srcCount = Character.charCount(srcChar);
-            }
-            if (localeDependent) {
-                upperChar = ConditionalSpecialCasing.toUpperCaseEx(this, i, locale);
-            } else {
-                upperChar = Character.toUpperCaseEx(srcChar);
-            }
-            if (Character.isBmpCodePoint(upperChar)) {
-                result[resultOffset++] = (char)upperChar;
-            } else {
-                if (upperChar == Character.ERROR) {
-                    if (localeDependent) {
-                        upperCharArray =
-                            ConditionalSpecialCasing.toUpperCaseCharArray(this, i, locale);
-                    } else {
-                        upperCharArray = Character.toUpperCaseCharArray(srcChar);
-                    }
-                } else if (srcCount == 2) {
-                    resultOffset += Character.toChars(upperChar, result, resultOffset);
-                    continue;
-                } else {
-                    upperCharArray = Character.toChars(upperChar);
-                }
-                /* Grow result if needed */
-                int mapLen = upperCharArray.length;
-                if (mapLen > srcCount) {
-                    char[] result2 = new char[result.length + mapLen - srcCount];
-                    System.arraycopy(result, 0, result2, 0, resultOffset);
-                    result = result2;
-                 }
-                 for (int x = 0; x < mapLen; ++x) {
-                    result[resultOffset++] = upperCharArray[x];
-                 }
-            }
-        }
-        return new String(result, 0, resultOffset);
+        return isLatin1() ? StringLatin1.toUpperCase(this, value, locale)
+                          : StringUTF16.toUpperCase(this, value, locale);
     }
 
     /**
@@ -2925,17 +2654,9 @@
      *          trailing white space.
      */
     public String trim() {
-        char[] val = value;    /* avoid getfield opcode */
-        int end = val.length;
-        int beg = 0;
-
-        while ((beg < end) && (val[beg] <= ' ')) {
-            beg++;
-        }
-        while ((beg < end) && (val[end - 1] <= ' ')) {
-            end--;
-        }
-        return substring(beg, end);
+        String ret = isLatin1() ? StringLatin1.trim(value)
+                                : StringUTF16.trim(value);
+        return ret == null ? this : ret;
     }
 
     /**
@@ -2947,63 +2668,6 @@
         return this;
     }
 
-    static class IntCharArraySpliterator implements Spliterator.OfInt {
-        private final char[] array;
-        private int index;        // current index, modified on advance/split
-        private final int fence;  // one past last index
-        private final int cs;
-
-        IntCharArraySpliterator(char[] array, int acs) {
-            this(array, 0, array.length, acs);
-        }
-
-        IntCharArraySpliterator(char[] array, int origin, int fence, int acs) {
-            this.array = array;
-            this.index = origin;
-            this.fence = fence;
-            this.cs = acs | Spliterator.ORDERED | Spliterator.SIZED
-                      | Spliterator.SUBSIZED;
-        }
-
-        @Override
-        public OfInt trySplit() {
-            int lo = index, mid = (lo + fence) >>> 1;
-            return (lo >= mid)
-                   ? null
-                   : new IntCharArraySpliterator(array, lo, index = mid, cs);
-        }
-
-        @Override
-        public void forEachRemaining(IntConsumer action) {
-            char[] a; int i, hi; // hoist accesses and checks from loop
-            if (action == null)
-                throw new NullPointerException();
-            if ((a = array).length >= (hi = fence) &&
-                (i = index) >= 0 && i < (index = hi)) {
-                do { action.accept(a[i]); } while (++i < hi);
-            }
-        }
-
-        @Override
-        public boolean tryAdvance(IntConsumer action) {
-            if (action == null)
-                throw new NullPointerException();
-            if (index >= 0 && index < fence) {
-                action.accept(array[index++]);
-                return true;
-            }
-            return false;
-        }
-
-        @Override
-        public long estimateSize() { return (long)(fence - index); }
-
-        @Override
-        public int characteristics() {
-            return cs;
-        }
-    }
-
     /**
      * Returns a stream of {@code int} zero-extending the {@code char} values
      * from this sequence.  Any char which maps to a <a
@@ -3016,93 +2680,11 @@
     @Override
     public IntStream chars() {
         return StreamSupport.intStream(
-                new IntCharArraySpliterator(value, Spliterator.IMMUTABLE), false);
+            isLatin1() ? new StringLatin1.CharsSpliterator(value, Spliterator.IMMUTABLE)
+                       : new StringUTF16.CharsSpliterator(value, Spliterator.IMMUTABLE),
+            false);
     }
 
-    static class CodePointsSpliterator implements Spliterator.OfInt {
-        private final char[] array;
-        private int index;        // current index, modified on advance/split
-        private final int fence;  // one past last index
-        private final int cs;
-
-        CodePointsSpliterator(char[] array, int acs) {
-            this(array, 0, array.length, acs);
-        }
-
-        CodePointsSpliterator(char[] array, int origin, int fence, int acs) {
-            this.array = array;
-            this.index = origin;
-            this.fence = fence;
-            this.cs = acs | Spliterator.ORDERED;
-        }
-
-        @Override
-        public OfInt trySplit() {
-            int lo = index, mid = (lo + fence) >>> 1;
-            if (lo >= mid)
-                return null;
-
-            int midOneLess;
-            // If the mid-point intersects a surrogate pair
-            if (Character.isLowSurrogate(array[mid]) &&
-                Character.isHighSurrogate(array[midOneLess = (mid -1)])) {
-                // If there is only one pair it cannot be split
-                if (lo >= midOneLess)
-                    return null;
-                // Shift the mid-point to align with the surrogate pair
-                return new CodePointsSpliterator(array, lo, index = midOneLess, cs);
-            }
-            return new CodePointsSpliterator(array, lo, index = mid, cs);
-        }
-
-        @Override
-        public void forEachRemaining(IntConsumer action) {
-            char[] a; int i, hi; // hoist accesses and checks from loop
-            if (action == null)
-                throw new NullPointerException();
-            if ((a = array).length >= (hi = fence) &&
-                (i = index) >= 0 && i < (index = hi)) {
-                do {
-                    i = advance(a, i, hi, action);
-                } while (i < hi);
-            }
-        }
-
-        @Override
-        public boolean tryAdvance(IntConsumer action) {
-            if (action == null)
-                throw new NullPointerException();
-            if (index >= 0 && index < fence) {
-                index = advance(array, index, fence, action);
-                return true;
-            }
-            return false;
-        }
-
-        // Advance one code point from the index, i, and return the next
-        // index to advance from
-        private static int advance(char[] a, int i, int hi, IntConsumer action) {
-            char c1 = a[i++];
-            int cp = c1;
-            if (Character.isHighSurrogate(c1) && i < hi) {
-                char c2 = a[i];
-                if (Character.isLowSurrogate(c2)) {
-                    i++;
-                    cp = Character.toCodePoint(c1, c2);
-                }
-            }
-            action.accept(cp);
-            return i;
-        }
-
-        @Override
-        public long estimateSize() { return (long)(fence - index); }
-
-        @Override
-        public int characteristics() {
-            return cs;
-        }
-    }
 
     /**
      * Returns a stream of code point values from this sequence.  Any surrogate
@@ -3118,7 +2700,9 @@
     @Override
     public IntStream codePoints() {
         return StreamSupport.intStream(
-                new CodePointsSpliterator(value, Spliterator.IMMUTABLE), false);
+            isLatin1() ? new StringLatin1.CharsSpliterator(value, Spliterator.IMMUTABLE)
+                       : new StringUTF16.CodePointsSpliterator(value, Spliterator.IMMUTABLE),
+            false);
     }
 
     /**
@@ -3129,10 +2713,8 @@
      *          the character sequence represented by this string.
      */
     public char[] toCharArray() {
-        // Cannot use Arrays.copyOf because of class initialization order issues
-        char[] result = new char[value.length];
-        System.arraycopy(value, 0, result, 0, value.length);
-        return result;
+        return isLatin1() ? StringLatin1.toChars(value)
+                          : StringUTF16.toChars(value);
     }
 
     /**
@@ -3315,7 +2897,10 @@
      *          as its single character the argument {@code c}.
      */
     public static String valueOf(char c) {
-        return new String(new char[]{c}, true);
+        if (COMPACT_STRINGS && StringLatin1.canEncode(c)) {
+            return new String(StringLatin1.toBytes(c), LATIN1);
+        }
+        return new String(StringUTF16.toBytes(c), UTF16);
     }
 
     /**
@@ -3398,4 +2983,145 @@
      *          guaranteed to be from a pool of unique strings.
      */
     public native String intern();
+
+    ////////////////////////////////////////////////////////////////
+
+    /**
+     * Copy character bytes from this string into dst starting at dstBegin.
+     * This method doesn't perform any range checking.
+     *
+     * Invoker guarantees: dst is in UTF16 (inflate itself for asb), if two
+     * coders are different, and dst is big enough (range check)
+     *
+     * @param dstBegin  the char index, not offset of byte[]
+     * @param coder     the coder of dst[]
+     */
+    void getBytes(byte dst[], int dstBegin, byte coder) {
+        if (coder() == coder) {
+            System.arraycopy(value, 0, dst, dstBegin << coder, value.length);
+        } else {    // this.coder == LATIN && coder == UTF16
+            StringLatin1.inflate(value, 0, dst, dstBegin, value.length);
+        }
+    }
+
+    /*
+     * Package private constructor. Trailing Void argument is there for
+     * disambiguating it against other (public) constructors.
+     *
+     * Stores the char[] value into a byte[] that each byte represents
+     * the8 low-order bits of the corresponding character, if the char[]
+     * contains only latin1 character. Or a byte[] that stores all
+     * characters in their byte sequences defined by the {@code StringUTF16}.
+     */
+    String(char[] value, int off, int len, Void sig) {
+        if (len == 0) {
+            this.value = "".value;
+            this.coder = "".coder;
+            return;
+        }
+        if (COMPACT_STRINGS) {
+            byte[] val = StringUTF16.compress(value, off, len);
+            if (val != null) {
+                this.value = val;
+                this.coder = LATIN1;
+                return;
+            }
+        }
+        this.coder = UTF16;
+        this.value = StringUTF16.toBytes(value, off, len);
+    }
+
+    /*
+     * Package private constructor. Trailing Void argument is there for
+     * disambiguating it against other (public) constructors.
+     */
+    String(AbstractStringBuilder asb, Void sig) {
+        byte[] val = asb.getValue();
+        int length = asb.length();
+        if (asb.isLatin1()) {
+            this.coder = LATIN1;
+            this.value = Arrays.copyOfRange(val, 0, length);
+        } else {
+            if (COMPACT_STRINGS) {
+                byte[] buf = StringUTF16.compress(val, 0, length);
+                if (buf != null) {
+                    this.coder = LATIN1;
+                    this.value = buf;
+                    return;
+                }
+            }
+            this.coder = UTF16;
+            this.value = Arrays.copyOfRange(val, 0, length << 1);
+        }
+    }
+
+   /*
+    * Package private constructor which shares value array for speed.
+    */
+    String(byte[] value, byte coder) {
+        this.value = value;
+        this.coder = coder;
+    }
+
+    byte coder() {
+        return COMPACT_STRINGS ? coder : UTF16;
+    }
+
+    private boolean isLatin1() {
+        return COMPACT_STRINGS && coder == LATIN1;
+    }
+
+    static final byte LATIN1 = 0;
+    static final byte UTF16  = 1;
+
+    /*
+     * StringIndexOutOfBoundsException  if {@code index} is
+     * negative or greater than or equal to {@code length}.
+     */
+    static void checkIndex(int index, int length) {
+        if (index < 0 || index >= length) {
+            throw new StringIndexOutOfBoundsException("index " + index);
+        }
+    }
+
+    /*
+     * StringIndexOutOfBoundsException  if {@code offset}
+     * is negative or greater than {@code length}.
+     */
+    static void checkOffset(int offset, int length) {
+        if (offset < 0 || offset > length) {
+            throw new StringIndexOutOfBoundsException("offset " + offset +
+                                                      ",length " + length);
+        }
+    }
+
+    /*
+     * Check {@code offset}, {@code count} against {@code 0} and {@code length}
+     * bounds.
+     *
+     * @throws  StringIndexOutOfBoundsException
+     *          If {@code offset} is negative, {@code count} is negative,
+     *          or {@code offset} is greater than {@code length - count}
+     */
+    private static void checkBoundsOffCount(int offset, int count, int length) {
+        if (offset < 0 || count < 0 || offset > length - count) {
+            throw new StringIndexOutOfBoundsException(
+                "offset " + offset + ", count " + count + ", length " + length);
+        }
+    }
+
+    /*
+     * Check {@code begin}, {@code end} against {@code 0} and {@code length}
+     * bounds.
+     *
+     * @throws  StringIndexOutOfBoundsException
+     *          If {@code begin} is negative, {@code begin} is greater than
+     *          {@code end}, or {@code end} is greater than {@code length}.
+     */
+    private static void checkBoundsBeginEnd(int begin, int end, int length) {
+        if (begin < 0 || begin > end || end > length) {
+            throw new StringIndexOutOfBoundsException(
+                "begin " + begin + ", end " + end + ", length " + length);
+        }
+    }
 }
--- a/src/java.base/share/classes/java/lang/StringBuffer.java	Tue Nov 10 13:46:45 2015 +0300
+++ b/src/java.base/share/classes/java/lang/StringBuffer.java	Tue Nov 17 10:29:28 2015 -0800
@@ -104,7 +104,7 @@
      * A cache of the last value returned by toString. Cleared
      * whenever the StringBuffer is modified.
      */
-    private transient char[] toStringCache;
+    private transient String toStringCache;
 
     /** use serialVersionUID from JDK 1.0.2 for interoperability */
     static final long serialVersionUID = 3388685877147921107L;
@@ -169,15 +169,13 @@
 
     @Override
     public synchronized int capacity() {
-        return value.length;
+        return super.capacity();
     }
 
 
     @Override
     public synchronized void ensureCapacity(int minimumCapacity) {
-        if (minimumCapacity > value.length) {
-            expandCapacity(minimumCapacity);
-        }
+        super.ensureCapacity(minimumCapacity);
     }
 
     /**
@@ -204,9 +202,7 @@
      */
     @Override
     public synchronized char charAt(int index) {
-        if ((index < 0) || (index >= count))
-            throw new StringIndexOutOfBoundsException(index);
-        return value[index];
+        return super.charAt(index);
     }
 
     /**
@@ -261,10 +257,8 @@
      */
     @Override
     public synchronized void setCharAt(int index, char ch) {
-        if ((index < 0) || (index >= count))
-            throw new StringIndexOutOfBoundsException(index);
         toStringCache = null;
-        value[index] = ch;
+        super.setCharAt(index, ch);
     }
 
     @Override
@@ -680,9 +674,11 @@
     @HotSpotIntrinsicCandidate
     public synchronized String toString() {
         if (toStringCache == null) {
-            toStringCache = Arrays.copyOfRange(value, 0, count);
+            return toStringCache =
+                    isLatin1() ? StringLatin1.newString(value, 0, count)
+                               : StringUTF16.newString(value, 0, count);
         }
-        return new String(toStringCache, true);
+        return new String(toStringCache);
     }
 
     /**
@@ -710,7 +706,13 @@
     private synchronized void writeObject(java.io.ObjectOutputStream s)
         throws java.io.IOException {
         java.io.ObjectOutputStream.PutField fields = s.putFields();
-        fields.put("value", value);
+        char[] val = new char[capacity()];
+        if (isLatin1()) {
+            StringLatin1.getChars(value, 0, count, val, 0);
+        } else {
+            StringUTF16.getChars(value, 0, count, val, 0);
+        }
+        fields.put("value", val);
         fields.put("count", count);
         fields.put("shared", false);
         s.writeFields();
@@ -723,7 +725,12 @@
     private void readObject(java.io.ObjectInputStream s)
         throws java.io.IOException, ClassNotFoundException {
         java.io.ObjectInputStream.GetField fields = s.readFields();
-        value = (char[])fields.get("value", null);
+        char[] val = (char[])fields.get("value", null);
+        initBytes(val, 0, val.length);
         count = fields.get("count", 0);
     }
+
+    protected synchronized void getBytes(byte dst[], int dstBegin, byte coder) {
+        super.getBytes(dst, dstBegin, coder);
+    }
 }
--- a/src/java.base/share/classes/java/lang/StringBuilder.java	Tue Nov 10 13:46:45 2015 +0300
+++ b/src/java.base/share/classes/java/lang/StringBuilder.java	Tue Nov 17 10:29:28 2015 -0800
@@ -412,7 +412,8 @@
     @HotSpotIntrinsicCandidate
     public String toString() {
         // Create a copy, don't share the array
-        return new String(value, 0, count);
+        return isLatin1() ? StringLatin1.newString(value, 0, count)
+                          : StringUTF16.newStringSB(value, 0, count);
     }
 
     /**
@@ -430,7 +431,13 @@
         throws java.io.IOException {
         s.defaultWriteObject();
         s.writeInt(count);
-        s.writeObject(value);
+        char[] val = new char[capacity()];
+        if (isLatin1()) {
+            StringLatin1.getChars(value, 0, count, val, 0);
+        } else {
+            StringUTF16.getChars(value, 0, count, val, 0);
+        }
+        s.writeObject(val);
     }
 
     /**
@@ -441,7 +448,8 @@
         throws java.io.IOException, ClassNotFoundException {
         s.defaultReadObject();
         count = s.readInt();
-        value = (char[]) s.readObject();
+        char[] val = (char[]) s.readObject();
+        initBytes(val, 0, val.length);
     }
 
 }
--- a/src/java.base/share/classes/java/lang/StringCoding.java	Tue Nov 10 13:46:45 2015 +0300
+++ b/src/java.base/share/classes/java/lang/StringCoding.java	Tue Nov 17 10:29:28 2015 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2000, 2012, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2000, 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
@@ -38,11 +38,19 @@
 import java.nio.charset.IllegalCharsetNameException;
 import java.nio.charset.UnsupportedCharsetException;
 import java.util.Arrays;
+import jdk.internal.HotSpotIntrinsicCandidate;
 import sun.misc.MessageUtils;
 import sun.nio.cs.HistoricallyNamedCharset;
 import sun.nio.cs.ArrayDecoder;
 import sun.nio.cs.ArrayEncoder;
 
+import static java.lang.String.LATIN1;
+import static java.lang.String.UTF16;
+import static java.lang.String.COMPACT_STRINGS;
+import static java.nio.charset.StandardCharsets.ISO_8859_1;
+import static java.nio.charset.StandardCharsets.US_ASCII;
+import static java.nio.charset.StandardCharsets.UTF_8;
+
 /**
  * Utility class for string encoding and decoding.
  */
@@ -72,23 +80,13 @@
 
     // Trim the given byte array to the given length
     //
-    private static byte[] safeTrim(byte[] ba, int len, Charset cs, boolean isTrusted) {
+    private static byte[] safeTrim(byte[] ba, int len, boolean isTrusted) {
         if (len == ba.length && (isTrusted || System.getSecurityManager() == null))
             return ba;
         else
             return Arrays.copyOf(ba, len);
     }
 
-    // Trim the given char array to the given length
-    //
-    private static char[] safeTrim(char[] ca, int len,
-                                   Charset cs, boolean isTrusted) {
-        if (len == ca.length && (isTrusted || System.getSecurityManager() == null))
-            return ca;
-        else
-            return Arrays.copyOf(ca, len);
-    }
-
     private static int scale(int len, float expansionFactor) {
         // We need to perform double, not float, arithmetic; otherwise
         // we lose low order bits when len is larger than 2**24.
@@ -117,21 +115,64 @@
         }
     }
 
+    static class Result {
+        byte[] value;
+        byte coder;
+
+        Result with() {
+            coder = COMPACT_STRINGS ? LATIN1 : UTF16;
+            value = new byte[0];
+            return this;
+        }
+
+        Result with(char[] val, int off, int len) {
+            if (String.COMPACT_STRINGS) {
+                byte[] bs = StringUTF16.compress(val, off, len);
+                if (bs != null) {
+                    value = bs;
+                    coder = LATIN1;
+                    return this;
+                }
+            }
+            coder = UTF16;
+            value = StringUTF16.toBytes(val, off, len);
+            return this;
+        }
+
+        Result with(byte[] val, byte coder) {
+            this.coder = coder;
+            value = val;
+            return this;
+        }
+    }
+
+    @HotSpotIntrinsicCandidate
+    private static boolean hasNegatives(byte[] ba, int off, int len) {
+        for (int i = off; i < off + len; i++) {
+            if (ba[i] < 0) {
+                return true;
+            }
+        }
+        return false;
+    }
 
     // -- Decoding --
-    private static class StringDecoder {
+    static class StringDecoder {
         private final String requestedCharsetName;
         private final Charset cs;
+        private final boolean isASCIICompatible;
         private final CharsetDecoder cd;
-        private final boolean isTrusted;
+        protected final Result result;
 
-        private StringDecoder(Charset cs, String rcn) {
+        StringDecoder(Charset cs, String rcn) {
             this.requestedCharsetName = rcn;
             this.cs = cs;
             this.cd = cs.newDecoder()
                 .onMalformedInput(CodingErrorAction.REPLACE)
                 .onUnmappableCharacter(CodingErrorAction.REPLACE);
-            this.isTrusted = (cs.getClass().getClassLoader0() == null);
+            this.result = new Result();
+            this.isASCIICompatible = (cd instanceof ArrayDecoder) &&
+                    ((ArrayDecoder)cd).isASCIICompatible();
         }
 
         String charsetName() {
@@ -144,36 +185,58 @@
             return requestedCharsetName;
         }
 
-        char[] decode(byte[] ba, int off, int len) {
+        Result decode(byte[] ba, int off, int len) {
+            if (len == 0) {
+                return result.with();
+            }
+            // fastpath for ascii compatible
+            if (isASCIICompatible && !hasNegatives(ba, off, len)) {
+                if (COMPACT_STRINGS) {
+                    return result.with(Arrays.copyOfRange(ba, off, off + len),
+                                      LATIN1);
+                } else {
+                    return result.with(StringLatin1.inflate(ba, off, len), UTF16);
+                }
+            }
             int en = scale(len, cd.maxCharsPerByte());
             char[] ca = new char[en];
-            if (len == 0)
-                return ca;
             if (cd instanceof ArrayDecoder) {
                 int clen = ((ArrayDecoder)cd).decode(ba, off, len, ca);
-                return safeTrim(ca, clen, cs, isTrusted);
+                return result.with(ca, 0, clen);
+            }
+            cd.reset();
+            ByteBuffer bb = ByteBuffer.wrap(ba, off, len);
+            CharBuffer cb = CharBuffer.wrap(ca);
+            try {
+                CoderResult cr = cd.decode(bb, cb, true);
+                if (!cr.isUnderflow())
+                    cr.throwException();
+                cr = cd.flush(cb);
+                if (!cr.isUnderflow())
+                    cr.throwException();
+            } catch (CharacterCodingException x) {
+                // Substitution is always enabled,
+                // so this shouldn't happen
+                throw new Error(x);
+            }
+            return result.with(ca, 0, cb.position());
+        }
+    }
+
+    private static class StringDecoder8859_1 extends StringDecoder {
+        StringDecoder8859_1(Charset cs, String rcn) {
+            super(cs, rcn);
+        }
+        Result decode(byte[] ba, int off, int len) {
+            if (COMPACT_STRINGS) {
+                return result.with(Arrays.copyOfRange(ba, off, off + len), LATIN1);
             } else {
-                cd.reset();
-                ByteBuffer bb = ByteBuffer.wrap(ba, off, len);
-                CharBuffer cb = CharBuffer.wrap(ca);
-                try {
-                    CoderResult cr = cd.decode(bb, cb, true);
-                    if (!cr.isUnderflow())
-                        cr.throwException();
-                    cr = cd.flush(cb);
-                    if (!cr.isUnderflow())
-                        cr.throwException();
-                } catch (CharacterCodingException x) {
-                    // Substitution is always enabled,
-                    // so this shouldn't happen
-                    throw new Error(x);
-                }
-                return safeTrim(ca, cb.position(), cs, isTrusted);
+                return result.with(StringLatin1.inflate(ba, off, len), UTF16);
             }
         }
     }
 
-    static char[] decode(String charsetName, byte[] ba, int off, int len)
+    static Result decode(String charsetName, byte[] ba, int off, int len)
         throws UnsupportedEncodingException
     {
         StringDecoder sd = deref(decoder);
@@ -183,8 +246,15 @@
             sd = null;
             try {
                 Charset cs = lookupCharset(csn);
-                if (cs != null)
-                    sd = new StringDecoder(cs, csn);
+                if (cs != null) {
+                    if (cs == UTF_8) {
+                        sd = new StringDecoderUTF8(cs, csn);
+                    } else if (cs == ISO_8859_1) {
+                        sd = new StringDecoder8859_1(cs, csn);
+                    } else {
+                        sd = new StringDecoder(cs, csn);
+                    }
+                }
             } catch (IllegalCharsetNameException x) {}
             if (sd == null)
                 throw new UnsupportedEncodingException(csn);
@@ -193,7 +263,7 @@
         return sd.decode(ba, off, len);
     }
 
-    static char[] decode(Charset cs, byte[] ba, int off, int len) {
+    static Result decode(Charset cs, byte[] ba, int off, int len) {
         // (1)We never cache the "external" cs, the only benefit of creating
         // an additional StringDe/Encoder object to wrap it is to share the
         // de/encode() method. These SD/E objects are short-lived, the young-gen
@@ -210,44 +280,57 @@
         // check (... && (isTrusted || SM == null || getClassLoader0())) in trim
         // but it then can be argued that the SM is null when the operation
         // is started...
+        if (cs == UTF_8) {
+            return StringDecoderUTF8.decode(ba, off, len, new Result());
+        }
         CharsetDecoder cd = cs.newDecoder();
+        // ascii fastpath
+        if (cs == ISO_8859_1 || ((cd instanceof ArrayDecoder) &&
+                                 ((ArrayDecoder)cd).isASCIICompatible() &&
+                                 !hasNegatives(ba, off, len))) {
+             if (COMPACT_STRINGS) {
+                 return new Result().with(Arrays.copyOfRange(ba, off, off + len),
+                                          LATIN1);
+             } else {
+                 return new Result().with(StringLatin1.inflate(ba, off, len), UTF16);
+             }
+        }
         int en = scale(len, cd.maxCharsPerByte());
-        char[] ca = new char[en];
-        if (len == 0)
-            return ca;
-        boolean isTrusted = false;
-        if (System.getSecurityManager() != null) {
-            if (!(isTrusted = (cs.getClass().getClassLoader0() == null))) {
-                ba =  Arrays.copyOfRange(ba, off, off + len);
-                off = 0;
-            }
+        if (len == 0) {
+            return new Result().with();
+        }
+        if (System.getSecurityManager() != null &&
+            cs.getClass().getClassLoader0() != null) {
+            ba =  Arrays.copyOfRange(ba, off, off + len);
+            off = 0;
         }
         cd.onMalformedInput(CodingErrorAction.REPLACE)
           .onUnmappableCharacter(CodingErrorAction.REPLACE)
           .reset();
+
+        char[] ca = new char[en];
         if (cd instanceof ArrayDecoder) {
             int clen = ((ArrayDecoder)cd).decode(ba, off, len, ca);
-            return safeTrim(ca, clen, cs, isTrusted);
-        } else {
-            ByteBuffer bb = ByteBuffer.wrap(ba, off, len);
-            CharBuffer cb = CharBuffer.wrap(ca);
-            try {
-                CoderResult cr = cd.decode(bb, cb, true);
-                if (!cr.isUnderflow())
-                    cr.throwException();
-                cr = cd.flush(cb);
-                if (!cr.isUnderflow())
-                    cr.throwException();
-            } catch (CharacterCodingException x) {
-                // Substitution is always enabled,
-                // so this shouldn't happen
-                throw new Error(x);
-            }
-            return safeTrim(ca, cb.position(), cs, isTrusted);
+            return new Result().with(ca, 0, clen);
         }
+        ByteBuffer bb = ByteBuffer.wrap(ba, off, len);
+        CharBuffer cb = CharBuffer.wrap(ca);
+        try {
+            CoderResult cr = cd.decode(bb, cb, true);
+            if (!cr.isUnderflow())
+                cr.throwException();
+            cr = cd.flush(cb);
+            if (!cr.isUnderflow())
+                cr.throwException();
+        } catch (CharacterCodingException x) {
+            // Substitution is always enabled,
+            // so this shouldn't happen
+            throw new Error(x);
+        }
+        return new Result().with(ca, 0, cb.position());
     }
 
-    static char[] decode(byte[] ba, int off, int len) {
+    static Result decode(byte[] ba, int off, int len) {
         String csn = Charset.defaultCharset().name();
         try {
             // use charset name decode() variant which provides caching.
@@ -273,6 +356,7 @@
     private static class StringEncoder {
         private Charset cs;
         private CharsetEncoder ce;
+        private final boolean isASCIICompatible;
         private final String requestedCharsetName;
         private final boolean isTrusted;
 
@@ -283,6 +367,8 @@
                 .onMalformedInput(CodingErrorAction.REPLACE)
                 .onUnmappableCharacter(CodingErrorAction.REPLACE);
             this.isTrusted = (cs.getClass().getClassLoader0() == null);
+            this.isASCIICompatible = (ce instanceof ArrayEncoder) &&
+                    ((ArrayEncoder)ce).isASCIICompatible();
         }
 
         String charsetName() {
@@ -295,36 +381,186 @@
             return requestedCharsetName;
         }
 
-        byte[] encode(char[] ca, int off, int len) {
+        byte[] encode(byte coder, byte[] val) {
+            // fastpath for ascii compatible
+            if (coder == LATIN1 && isASCIICompatible &&
+                !hasNegatives(val, 0, val.length)) {
+                return Arrays.copyOf(val, val.length);
+            }
+            int len = val.length >> coder;  // assume LATIN1=0/UTF16=1;
             int en = scale(len, ce.maxBytesPerChar());
             byte[] ba = new byte[en];
-            if (len == 0)
+            if (len == 0) {
                 return ba;
+            }
             if (ce instanceof ArrayEncoder) {
-                int blen = ((ArrayEncoder)ce).encode(ca, off, len, ba);
-                return safeTrim(ba, blen, cs, isTrusted);
-            } else {
-                ce.reset();
-                ByteBuffer bb = ByteBuffer.wrap(ba);
-                CharBuffer cb = CharBuffer.wrap(ca, off, len);
-                try {
-                    CoderResult cr = ce.encode(cb, bb, true);
-                    if (!cr.isUnderflow())
-                        cr.throwException();
-                    cr = ce.flush(bb);
-                    if (!cr.isUnderflow())
-                        cr.throwException();
-                } catch (CharacterCodingException x) {
-                    // Substitution is always enabled,
-                    // so this shouldn't happen
-                    throw new Error(x);
+                if (!isTrusted) {
+                    val = Arrays.copyOf(val, val.length);
                 }
-                return safeTrim(ba, bb.position(), cs, isTrusted);
+                int blen = (coder == LATIN1 ) ? ((ArrayEncoder)ce).encodeFromLatin1(val, 0, len, ba)
+                                              : ((ArrayEncoder)ce).encodeFromUTF16(val, 0, len, ba);
+                if (blen != -1) {
+                    return safeTrim(ba, blen, isTrusted);
+                }
             }
+            char[] ca = (coder == LATIN1 ) ? StringLatin1.toChars(val)
+                                           : StringUTF16.toChars(val);
+            ce.reset();
+            ByteBuffer bb = ByteBuffer.wrap(ba);
+            CharBuffer cb = CharBuffer.wrap(ca, 0, len);
+            try {
+                CoderResult cr = ce.encode(cb, bb, true);
+                if (!cr.isUnderflow())
+                    cr.throwException();
+                cr = ce.flush(bb);
+                if (!cr.isUnderflow())
+                    cr.throwException();
+            } catch (CharacterCodingException x) {
+                // Substitution is always enabled,
+                // so this shouldn't happen
+                throw new Error(x);
+            }
+            return safeTrim(ba, bb.position(), isTrusted);
         }
     }
 
-    static byte[] encode(String charsetName, char[] ca, int off, int len)
+    @HotSpotIntrinsicCandidate
+    private static int implEncodeISOArray(byte[] sa, int sp,
+                                          byte[] da, int dp, int len) {
+        int i = 0;
+        for (; i < len; i++) {
+            char c = StringUTF16.getChar(sa, sp++);
+            if (c > '\u00FF')
+                break;
+            da[dp++] = (byte)c;
+        }
+        return i;
+    }
+
+    static byte[] encode8859_1(byte coder, byte[] val) {
+        if (coder == LATIN1) {
+            return Arrays.copyOf(val, val.length);
+        }
+        int len = val.length >> 1;
+        byte[] dst = new byte[len];
+        int dp = 0;
+        int sp = 0;
+        int sl = len;
+        while (sp < sl) {
+            int ret = implEncodeISOArray(val, sp, dst, dp, len);
+            sp = sp + ret;
+            dp = dp + ret;
+            if (ret != len) {
+                char c = StringUTF16.getChar(val, sp++);
+                if (Character.isHighSurrogate(c) && sp < sl &&
+                    Character.isLowSurrogate(StringUTF16.getChar(val, sp))) {
+                    sp++;
+                }
+                dst[dp++] = '?';
+                len = sl - sp;
+            }
+        }
+        if (dp == dst.length) {
+            return dst;
+        }
+        return Arrays.copyOf(dst, dp);
+    }
+
+    static byte[] encodeASCII(byte coder, byte[] val) {
+        if (coder == LATIN1) {
+            byte[] dst = new byte[val.length];
+            for (int i = 0; i < val.length; i++) {
+                if (val[i] < 0) {
+                    dst[i] = '?';
+                } else {
+                    dst[i] = val[i];
+                }
+            }
+            return dst;
+        }
+        int len = val.length >> 1;
+        byte[] dst = new byte[len];
+        int dp = 0;
+        for (int i = 0; i < len; i++) {
+            char c = StringUTF16.getChar(val, i);
+            if (c < 0x80) {
+                dst[dp++] = (byte)c;
+                continue;
+            }
+            if (Character.isHighSurrogate(c) && i + 1 < len &&
+                Character.isLowSurrogate(StringUTF16.getChar(val, i + 1))) {
+                i++;
+            }
+            dst[dp++] = '?';
+        }
+        if (len == dp) {
+            return dst;
+        }
+        return Arrays.copyOf(dst, dp);
+    }
+
+   static byte[] encodeUTF8(byte coder, byte[] val) {
+        int dp = 0;
+        byte[] dst;
+        if (coder == LATIN1) {
+            dst = new byte[val.length << 1];
+            for (int sp = 0; sp < val.length; sp++) {
+                byte c = val[sp];
+                if (c < 0) {
+                    dst[dp++] = (byte)(0xc0 | ((c & 0xff) >> 6));
+                    dst[dp++] = (byte)(0x80 | (c & 0x3f));
+                } else {
+                    dst[dp++] = c;
+                }
+            }
+        } else {
+            int sp = 0;
+            int sl = val.length >> 1;
+            dst = new byte[sl * 3];
+            char c;
+            while (sp < sl && (c = StringUTF16.getChar(val, sp)) < '\u0080') {
+                // ascii fast loop;
+                dst[dp++] = (byte)c;
+                sp++;
+            }
+            while (sp < sl) {
+                c = StringUTF16.getChar(val, sp++);
+                if (c < 0x80) {
+                    dst[dp++] = (byte)c;
+                } else if (c < 0x800) {
+                    dst[dp++] = (byte)(0xc0 | (c >> 6));
+                    dst[dp++] = (byte)(0x80 | (c & 0x3f));
+                } else if (Character.isSurrogate(c)) {
+                    int uc = -1;
+                    char c2;
+                    if (Character.isHighSurrogate(c) && sp < sl &&
+                        Character.isLowSurrogate(c2 = StringUTF16.getChar(val, sp))) {
+                        uc = Character.toCodePoint(c, c2);
+                    }
+                    if (uc < 0) {
+                        dst[dp++] = '?';
+                    } else {
+                        dst[dp++] = (byte)(0xf0 | ((uc >> 18)));
+                        dst[dp++] = (byte)(0x80 | ((uc >> 12) & 0x3f));
+                        dst[dp++] = (byte)(0x80 | ((uc >>  6) & 0x3f));
+                        dst[dp++] = (byte)(0x80 | (uc & 0x3f));
+                        sp++;  // 2 chars
+                    }
+                } else {
+                    // 3 bytes, 16 bits
+                    dst[dp++] = (byte)(0xe0 | ((c >> 12)));
+                    dst[dp++] = (byte)(0x80 | ((c >>  6) & 0x3f));
+                    dst[dp++] = (byte)(0x80 | (c & 0x3f));
+                }
+            }
+        }
+        if (dp == dst.length) {
+            return dst;
+        }
+        return Arrays.copyOf(dst, dp);
+    }
+
+    static byte[] encode(String charsetName, byte coder, byte[] val)
         throws UnsupportedEncodingException
     {
         StringEncoder se = deref(encoder);
@@ -334,62 +570,88 @@
             se = null;
             try {
                 Charset cs = lookupCharset(csn);
-                if (cs != null)
+                if (cs != null) {
+                    if (cs == UTF_8) {
+                        return encodeUTF8(coder, val);
+                    } else if (cs == ISO_8859_1) {
+                        return encode8859_1(coder, val);
+                    } else if (cs == US_ASCII) {
+                        return encodeASCII(coder, val);
+                    }
                     se = new StringEncoder(cs, csn);
+                }
             } catch (IllegalCharsetNameException x) {}
-            if (se == null)
+            if (se == null) {
                 throw new UnsupportedEncodingException (csn);
+            }
             set(encoder, se);
         }
-        return se.encode(ca, off, len);
+        return se.encode(coder, val);
     }
 
-    static byte[] encode(Charset cs, char[] ca, int off, int len) {
+    static byte[] encode(Charset cs, byte coder, byte[] val) {
+        if (cs == UTF_8) {
+            return encodeUTF8(coder, val);
+        } else if (cs == ISO_8859_1) {
+            return encode8859_1(coder, val);
+        } else if (cs == US_ASCII) {
+            return encodeASCII(coder, val);
+        }
         CharsetEncoder ce = cs.newEncoder();
+        // fastpath for ascii compatible
+        if (coder == LATIN1 && (((ce instanceof ArrayEncoder) &&
+                                 ((ArrayEncoder)ce).isASCIICompatible() &&
+                                 !hasNegatives(val, 0, val.length)))) {
+            return Arrays.copyOf(val, val.length);
+        }
+        int len = val.length >> coder;  // assume LATIN1=0/UTF16=1;
         int en = scale(len, ce.maxBytesPerChar());
         byte[] ba = new byte[en];
-        if (len == 0)
+        if (len == 0) {
             return ba;
-        boolean isTrusted = false;
-        if (System.getSecurityManager() != null) {
-            if (!(isTrusted = (cs.getClass().getClassLoader0() == null))) {
-                ca =  Arrays.copyOfRange(ca, off, off + len);
-                off = 0;
-            }
         }
+        boolean isTrusted = System.getSecurityManager() == null ||
+                            cs.getClass().getClassLoader0() == null;
         ce.onMalformedInput(CodingErrorAction.REPLACE)
           .onUnmappableCharacter(CodingErrorAction.REPLACE)
           .reset();
         if (ce instanceof ArrayEncoder) {
-            int blen = ((ArrayEncoder)ce).encode(ca, off, len, ba);
-            return safeTrim(ba, blen, cs, isTrusted);
-        } else {
-            ByteBuffer bb = ByteBuffer.wrap(ba);
-            CharBuffer cb = CharBuffer.wrap(ca, off, len);
-            try {
-                CoderResult cr = ce.encode(cb, bb, true);
-                if (!cr.isUnderflow())
-                    cr.throwException();
-                cr = ce.flush(bb);
-                if (!cr.isUnderflow())
-                    cr.throwException();
-            } catch (CharacterCodingException x) {
-                throw new Error(x);
+            if (!isTrusted) {
+                val = Arrays.copyOf(val, val.length);
             }
-            return safeTrim(ba, bb.position(), cs, isTrusted);
+            int blen = (coder == LATIN1 ) ? ((ArrayEncoder)ce).encodeFromLatin1(val, 0, len, ba)
+                                          : ((ArrayEncoder)ce).encodeFromUTF16(val, 0, len, ba);
+            if (blen != -1) {
+                return safeTrim(ba, blen, isTrusted);
+            }
         }
+        char[] ca = (coder == LATIN1 ) ? StringLatin1.toChars(val)
+                                       : StringUTF16.toChars(val);
+        ByteBuffer bb = ByteBuffer.wrap(ba);
+        CharBuffer cb = CharBuffer.wrap(ca, 0, len);
+        try {
+            CoderResult cr = ce.encode(cb, bb, true);
+            if (!cr.isUnderflow())
+                cr.throwException();
+            cr = ce.flush(bb);
+            if (!cr.isUnderflow())
+                cr.throwException();
+        } catch (CharacterCodingException x) {
+            throw new Error(x);
+        }
+        return safeTrim(ba, bb.position(), isTrusted);
     }
 
-    static byte[] encode(char[] ca, int off, int len) {
+    static byte[] encode(byte coder, byte[] val) {
         String csn = Charset.defaultCharset().name();
         try {
             // use charset name encode() variant which provides caching.
-            return encode(csn, ca, off, len);
+            return encode(csn, coder, val);
         } catch (UnsupportedEncodingException x) {
             warnUnsupportedCharset(csn);
         }
         try {
-            return encode("ISO-8859-1", ca, off, len);
+            return encode("ISO-8859-1", coder, val);
         } catch (UnsupportedEncodingException x) {
             // If this code is hit during VM initialization, MessageUtils is
             // the only way we will be able to get any kind of error message.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/java.base/share/classes/java/lang/StringDecoderUTF8.java	Tue Nov 17 10:29:28 2015 -0800
@@ -0,0 +1,235 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.lang;
+
+import java.nio.charset.Charset;
+import java.util.Arrays;
+
+import static java.lang.String.LATIN1;
+import static java.lang.String.UTF16;
+import static java.lang.String.COMPACT_STRINGS;
+import static java.lang.Character.isSurrogate;
+import static java.lang.Character.highSurrogate;
+import static java.lang.Character.lowSurrogate;
+import static java.lang.Character.isSupplementaryCodePoint;
+import static java.lang.StringUTF16.putChar;
+
+class StringDecoderUTF8 extends StringCoding.StringDecoder {
+
+    StringDecoderUTF8(Charset cs, String rcn) {
+        super(cs, rcn);
+    }
+
+    private static boolean isNotContinuation(int b) {
+        return (b & 0xc0) != 0x80;
+    }
+
+    private static boolean isMalformed3(int b1, int b2, int b3) {
+        return (b1 == (byte)0xe0 && (b2 & 0xe0) == 0x80) ||
+               (b2 & 0xc0) != 0x80 || (b3 & 0xc0) != 0x80;
+    }
+
+    private static boolean isMalformed3_2(int b1, int b2) {
+        return (b1 == (byte)0xe0 && (b2 & 0xe0) == 0x80) ||
+               (b2 & 0xc0) != 0x80;
+    }
+
+    private static boolean isMalformed4(int b2, int b3, int b4) {
+        return (b2 & 0xc0) != 0x80 || (b3 & 0xc0) != 0x80 ||
+               (b4 & 0xc0) != 0x80;
+    }
+
+    private static boolean isMalformed4_2(int b1, int b2) {
+        return (b1 == 0xf0 && (b2  < 0x90 || b2 > 0xbf)) ||
+               (b1 == 0xf4 && (b2 & 0xf0) != 0x80) ||
+               (b2 & 0xc0) != 0x80;
+    }
+
+    private static boolean isMalformed4_3(int b3) {
+        return (b3 & 0xc0) != 0x80;
+    }
+
+    // for nb == 3/4
+    private static int malformedN(byte[] src, int sp, int nb) {
+        if (nb == 3) {
+            int b1 = src[sp++];
+            int b2 = src[sp++];    // no need to lookup b3
+            return ((b1 == (byte)0xe0 && (b2 & 0xe0) == 0x80) ||
+                    isNotContinuation(b2)) ? 1 : 2;
+        } else if (nb == 4) { // we don't care the speed here
+            int b1 = src[sp++] & 0xff;
+            int b2 = src[sp++] & 0xff;
+            if (b1 > 0xf4 ||
+                (b1 == 0xf0 && (b2 < 0x90 || b2 > 0xbf)) ||
+                (b1 == 0xf4 && (b2 & 0xf0) != 0x80) ||
+                isNotContinuation(b2))
+                return 1;
+            if (isNotContinuation(src[sp++]))
+                return 2;
+            return 3;
+        }
+        assert false;
+        return -1;
+    }
+
+    private static char repl = '\ufffd';
+
+    StringCoding.Result decode(byte[] src, int sp, int len) {
+        return decode(src, sp, len, result);
+    }
+
+    static StringCoding.Result decode(byte[] src, int sp, int len,
+                                      StringCoding.Result ret) {
+        int sl = sp + len;
+        byte[] dst = new byte[len];
+        int dp = 0;
+        if (COMPACT_STRINGS) {   // Latin1 only loop
+            while (sp < sl) {
+                int b1 = src[sp];
+                if (b1 >= 0) {
+                    dst[dp++] = (byte)b1;
+                    sp++;
+                    continue;
+                }
+                if ((b1 == (byte)0xc2 || b1 == (byte)0xc3) &&
+                    sp + 1 < sl) {
+                    int b2 = src[sp + 1];
+                    if (!isNotContinuation(b2)) {
+                        dst[dp++] = (byte)(((b1 << 6) ^ b2)^
+                                           (((byte) 0xC0 << 6) ^
+                                           ((byte) 0x80 << 0)));
+                        sp += 2;
+                        continue;
+                    }
+                }
+                // anything not a latin1, including the repl
+                // we have to go with the utf16
+                break;
+            }
+            if (sp == sl) {
+                if (dp != dst.length) {
+                    dst = Arrays.copyOf(dst, dp);
+                }
+                return ret.with(dst, LATIN1);
+            }
+        }
+        if (dp == 0) {
+            dst = new byte[len << 1];
+        } else {
+            byte[] buf = new byte[len << 1];
+            StringLatin1.inflate(dst, 0, buf, 0, dp);
+            dst = buf;
+        }
+        while (sp < sl) {
+            int b1 = src[sp++];
+            if (b1 >= 0) {
+                putChar(dst, dp++, (char) b1);
+            } else if ((b1 >> 5) == -2 && (b1 & 0x1e) != 0) {
+                if (sp < sl) {
+                    int b2 = src[sp++];
+                    if (isNotContinuation(b2)) {
+                        putChar(dst, dp++, repl);
+                        sp--;
+                    } else {
+                        putChar(dst, dp++, (char)(((b1 << 6) ^ b2)^
+                                                  (((byte) 0xC0 << 6) ^
+                                                  ((byte) 0x80 << 0))));
+                    }
+                    continue;
+                }
+                putChar(dst, dp++, repl);
+                break;
+            } else if ((b1 >> 4) == -2) {
+                if (sp + 1 < sl) {
+                    int b2 = src[sp++];
+                    int b3 = src[sp++];
+                    if (isMalformed3(b1, b2, b3)) {
+                        putChar(dst, dp++, repl);
+                        sp -= 3;
+                        sp += malformedN(src, sp, 3);
+                    } else {
+                        char c = (char)((b1 << 12) ^
+                                        (b2 <<  6) ^
+                                        (b3 ^
+                                         (((byte) 0xE0 << 12) ^
+                                         ((byte) 0x80 <<  6) ^
+                                         ((byte) 0x80 <<  0))));
+                        putChar(dst, dp++, isSurrogate(c) ?  repl : c);
+                    }
+                    continue;
+                }
+                if (sp  < sl && isMalformed3_2(b1, src[sp])) {
+                    putChar(dst, dp++, repl);
+                    continue;
+                }
+                putChar(dst, dp++, repl);
+                break;
+            } else if ((b1 >> 3) == -2) {
+                if (sp + 2 < sl) {
+                    int b2 = src[sp++];
+                    int b3 = src[sp++];
+                    int b4 = src[sp++];
+                    int uc = ((b1 << 18) ^
+                              (b2 << 12) ^
+                              (b3 <<  6) ^
+                              (b4 ^
+                               (((byte) 0xF0 << 18) ^
+                               ((byte) 0x80 << 12) ^
+                               ((byte) 0x80 <<  6) ^
+                               ((byte) 0x80 <<  0))));
+                    if (isMalformed4(b2, b3, b4) ||
+                        !isSupplementaryCodePoint(uc)) { // shortest form check
+                        putChar(dst, dp++, repl);
+                        sp -= 4;
+                        sp += malformedN(src, sp, 4);
+                    } else {
+                        putChar(dst, dp++, highSurrogate(uc));
+                        putChar(dst, dp++, lowSurrogate(uc));
+                    }
+                    continue;
+                }
+                b1 &= 0xff;
+                if (b1 > 0xf4 ||
+                    sp  < sl && isMalformed4_2(b1, src[sp] & 0xff)) {
+                    putChar(dst, dp++, repl);
+                    continue;
+                }
+                sp++;
+                putChar(dst, dp++, repl);
+                if (sp  < sl && isMalformed4_3(src[sp])) {
+                    continue;
+                }
+                break;
+            } else {
+                putChar(dst, dp++, repl);
+            }
+        }
+        if (dp != len) {
+            dst = Arrays.copyOf(dst, dp << 1);
+        }
+        return ret.with(dst, UTF16);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/java.base/share/classes/java/lang/StringLatin1.java	Tue Nov 17 10:29:28 2015 -0800
@@ -0,0 +1,600 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.lang;
+
+import java.util.Arrays;
+import java.util.Locale;
+import java.util.Objects;
+import java.util.Spliterator;
+import java.util.function.IntConsumer;
+import java.util.stream.IntStream;
+import jdk.internal.HotSpotIntrinsicCandidate;
+
+import static java.lang.String.LATIN1;
+import static java.lang.String.UTF16;
+import static java.lang.String.checkOffset;
+
+final class StringLatin1 {
+
+    public static char charAt(byte[] value, int index) {
+        if (index < 0 || index >= value.length) {
+            throw new StringIndexOutOfBoundsException(index);
+        }
+        return (char)(value[index] & 0xff);
+    }
+
+    public static boolean canEncode(int cp) {
+        return cp >>> 8 == 0;
+    }
+
+    public static int length(byte[] value) {
+        return value.length;
+    }
+
+    public static int codePointAt(byte[] value, int index, int end) {
+        return value[index] & 0xff;
+    }
+
+    public static int codePointBefore(byte[] value, int index) {
+        return value[index - 1] & 0xff;
+    }
+
+    public static int codePointCount(byte[] value, int beginIndex, int endIndex) {
+        return endIndex - beginIndex;
+    }
+
+    public static char[] toChars(byte[] value) {
+        char[] dst = new char[value.length];
+        inflate(value, 0, dst, 0, value.length);
+        return dst;
+    }
+
+    public static byte[] inflate(byte[] value, int off, int len) {
+        byte[] ret = StringUTF16.newBytesFor(len);
+        inflate(value, off, ret, 0, len);
+        return ret;
+    }
+
+    public static void getChars(byte[] value, int srcBegin, int srcEnd, char dst[], int dstBegin) {
+        inflate(value, srcBegin, dst, dstBegin, srcEnd - srcBegin);
+    }
+
+    public static void getBytes(byte[] value, int srcBegin, int srcEnd, byte dst[], int dstBegin) {
+        System.arraycopy(value, srcBegin, dst, dstBegin, srcEnd - srcBegin);
+    }
+
+    @HotSpotIntrinsicCandidate
+    public static boolean equals(byte[] value, byte[] other) {
+        if (value.length == other.length) {
+            for (int i = 0; i < value.length; i++) {
+                if (value[i] != other[i]) {
+                    return false;
+                }
+            }
+            return true;
+        }
+        return false;
+    }
+
+    @HotSpotIntrinsicCandidate
+    public static int compareTo(byte[] value, byte[] other) {
+        int len1 = value.length;
+        int len2 = other.length;
+        int lim = Math.min(len1, len2);
+        for (int k = 0; k < lim; k++) {
+            if (value[k] != other[k]) {
+                return getChar(value, k) - getChar(other, k);
+            }
+        }
+        return len1 - len2;
+    }
+
+    @HotSpotIntrinsicCandidate
+    public static int compareToUTF16(byte[] value, byte[] other) {
+        int len1 = length(value);
+        int len2 = StringUTF16.length(other);
+        int lim = Math.min(len1, len2);
+        for (int k = 0; k < lim; k++) {
+            char c1 = getChar(value, k);
+            char c2 = StringUTF16.getChar(other, k);
+            if (c1 != c2) {
+                return c1 - c2;
+            }
+        }
+        return len1 - len2;
+    }
+
+    public static int hashCode(byte[] value) {
+        int h = 0;
+        for (byte v : value) {
+            h = 31 * h + (v & 0xff);
+        }
+        return h;
+    }
+
+    public static int indexOf(byte[] value, int ch, int fromIndex) {
+        if (!canEncode(ch)) {
+            return -1;
+        }
+        int max = value.length;
+        if (fromIndex < 0) {
+            fromIndex = 0;
+        } else if (fromIndex >= max) {
+            // Note: fromIndex might be near -1>>>1.
+            return -1;
+        }
+        byte c = (byte)ch;
+        for (int i = fromIndex; i < max; i++) {
+            if (value[i] == c) {
+               return i;
+            }
+        }
+        return -1;
+    }
+
+    @HotSpotIntrinsicCandidate
+    public static int indexOf(byte[] value, byte[] str) {
+        if (str.length == 0) {
+            return 0;
+        }
+        if (value.length == 0) {
+            return -1;
+        }
+        return indexOf(value, value.length, str, str.length, 0);
+    }
+
+    @HotSpotIntrinsicCandidate
+    public static int indexOf(byte[] value, int valueCount, byte[] str, int strCount, int fromIndex) {
+        byte first = str[0];
+        int max = (valueCount - strCount);
+        for (int i = fromIndex; i <= max; i++) {
+            // Look for first character.
+            if (value[i] != first) {
+                while (++i <= max && value[i] != first);
+            }
+            // Found first character, now look at the rest of value
+            if (i <= max) {
+                int j = i + 1;
+                int end = j + strCount - 1;
+                for (int k = 1; j < end && value[j] == str[k]; j++, k++);
+                if (j == end) {
+                    // Found whole string.
+                    return i;
+                }
+            }
+        }
+        return -1;
+    }
+
+    public static int lastIndexOf(byte[] src, int srcCount,
+                                  byte[] tgt, int tgtCount, int fromIndex) {
+        int min = tgtCount - 1;
+        int i = min + fromIndex;
+        int strLastIndex = tgtCount - 1;
+        char strLastChar = (char)(tgt[strLastIndex] & 0xff);
+
+  startSearchForLastChar:
+        while (true) {
+            while (i >= min && (src[i] & 0xff) != strLastChar) {
+                i--;
+            }
+            if (i < min) {
+                return -1;
+            }
+            int j = i - 1;
+            int start = j - strLastIndex;
+            int k = strLastIndex - 1;
+            while (j > start) {
+                if ((src[j--] & 0xff) != (tgt[k--] & 0xff)) {
+                    i--;
+                    continue startSearchForLastChar;
+                }
+            }
+            return start + 1;
+        }
+    }
+
+    public static int lastIndexOf(final byte[] value, int ch, int fromIndex) {
+        if (!canEncode(ch)) {
+            return -1;
+        }
+        int off  = Math.min(fromIndex, value.length - 1);
+        for (; off >= 0; off--) {
+            if (value[off] == (byte)ch) {
+                return off;
+            }
+        }
+        return -1;
+    }
+
+    public static String replace(byte[] value, char oldChar, char newChar) {
+        if (canEncode(oldChar)) {
+            int len = value.length;
+            int i = -1;
+            while (++i < len) {
+                if (value[i] == (byte)oldChar) {
+                    break;
+                }
+            }
+            if (i < len) {
+                if (canEncode(newChar)) {
+                    byte buf[] = new byte[len];
+                    for (int j = 0; j < i; j++) {    // TBD arraycopy?
+                        buf[j] = value[j];
+                    }
+                    while (i < len) {
+                        byte c = value[i];
+                        buf[i] = (c == (byte)oldChar) ? (byte)newChar : c;
+                        i++;
+                    }
+                    return new String(buf, LATIN1);
+                } else {
+                    byte[] buf = StringUTF16.newBytesFor(len);
+                    // inflate from latin1 to UTF16
+                    inflate(value, 0, buf, 0, i);
+                    while (i < len) {
+                        char c = (char)(value[i] & 0xff);
+                        StringUTF16.putChar(buf, i, (c == oldChar) ? newChar : c);
+                        i++;
+                    }
+                    return new String(buf, UTF16);
+                }
+            }
+        }
+        return null; // for string to return this;
+    }
+
+    // case insensitive
+    public static boolean regionMatchesCI(byte[] value, int toffset,
+                                          byte[] other, int ooffset, int len) {
+        int last = toffset + len;
+        while (toffset < last) {
+            char c1 = (char)(value[toffset++] & 0xff);
+            char c2 = (char)(other[ooffset++] & 0xff);
+            if (c1 == c2) {
+                continue;
+            }
+            char u1 = Character.toUpperCase(c1);
+            char u2 = Character.toUpperCase(c2);
+            if (u1 == u2) {
+                continue;
+            }
+            if (Character.toLowerCase(u1) == Character.toLowerCase(u2)) {
+                continue;
+            }
+            return false;
+        }
+        return true;
+    }
+
+    public static boolean regionMatchesCI_UTF16(byte[] value, int toffset,
+                                                byte[] other, int ooffset, int len) {
+        int last = toffset + len;
+        while (toffset < last) {
+            char c1 = (char)(value[toffset++] & 0xff);
+            char c2 = StringUTF16.getChar(other, ooffset++);
+            if (c1 == c2) {
+                continue;
+            }
+            char u1 = Character.toUpperCase(c1);
+            char u2 = Character.toUpperCase(c2);
+            if (u1 == u2) {
+                continue;
+            }
+            if (Character.toLowerCase(u1) == Character.toLowerCase(u2)) {
+                continue;
+            }
+            return false;
+        }
+        return true;
+    }
+
+    public static String toLowerCase(String str, byte[] value, Locale locale) {
+        if (locale == null) {
+            throw new NullPointerException();
+        }
+        int first;
+        final int len = value.length;
+        // Now check if there are any characters that need to be changed, or are surrogate
+        for (first = 0 ; first < len; first++) {
+            int cp = value[first] & 0xff;
+            if (cp != Character.toLowerCase(cp)) {  // no need to check Character.ERROR
+                break;
+            }
+        }
+        if (first == len)
+            return str;
+        String lang = locale.getLanguage();
+        if (lang == "tr" || lang == "az" || lang == "lt") {
+            return toLowerCaseEx(str, value, first, locale, true);
+        }
+        byte[] result = new byte[len];
+        System.arraycopy(value, 0, result, 0, first);  // Just copy the first few
+                                                       // lowerCase characters.
+        for (int i = first; i < len; i++) {
+            int cp = value[i] & 0xff;
+            cp = Character.toLowerCase(cp);
+            if (!canEncode(cp)) {                      // not a latin1 character
+                return toLowerCaseEx(str, value, first, locale, false);
+            }
+            result[i] = (byte)cp;
+        }
+        return new String(result, LATIN1);
+    }
+
+    private static String toLowerCaseEx(String str, byte[] value,
+                                        int first, Locale locale, boolean localeDependent)
+    {
+        byte[] result = StringUTF16.newBytesFor(value.length);
+        int resultOffset = 0;
+        for (int i = 0; i < first; i++) {
+            StringUTF16.putChar(result, resultOffset++, value[i] & 0xff);
+        }
+        for (int i = first; i < value.length; i++) {
+            int srcChar = value[i] & 0xff;
+            int lowerChar;
+            char[] lowerCharArray;
+            if (localeDependent) {
+                lowerChar = ConditionalSpecialCasing.toLowerCaseEx(str, i, locale);
+            } else {
+                lowerChar = Character.toLowerCase(srcChar);
+            }
+            if (Character.isBmpCodePoint(lowerChar)) {    // Character.ERROR is not a bmp
+                StringUTF16.putChar(result, resultOffset++, lowerChar);
+            } else {
+                if (lowerChar == Character.ERROR) {
+                    lowerCharArray = ConditionalSpecialCasing.toLowerCaseCharArray(str, i, locale);
+                } else {
+                    lowerCharArray = Character.toChars(lowerChar);
+                }
+                /* Grow result if needed */
+                int mapLen = lowerCharArray.length;
+                if (mapLen > 1) {
+                    byte[] result2 = StringUTF16.newBytesFor((result.length >> 1) + mapLen - 1);
+                    System.arraycopy(result, 0, result2, 0, resultOffset << 1);
+                    result = result2;
+                }
+                for (int x = 0; x < mapLen; ++x) {
+                    StringUTF16.putChar(result, resultOffset++, lowerCharArray[x]);
+                }
+            }
+        }
+        return StringUTF16.newString(result, 0, resultOffset);
+    }
+
+    public static String toUpperCase(String str, byte[] value, Locale locale) {
+        if (locale == null) {
+            throw new NullPointerException();
+        }
+        int first;
+        final int len = value.length;
+
+        // Now check if there are any characters that need to be changed, or are surrogate
+        for (first = 0 ; first < len; first++ ) {
+            int cp = value[first] & 0xff;
+            if (cp != Character.toUpperCaseEx(cp)) {   // no need to check Character.ERROR
+                break;
+            }
+        }
+        if (first == len) {
+            return str;
+        }
+        String lang = locale.getLanguage();
+        if (lang == "tr" || lang == "az" || lang == "lt") {
+            return toUpperCaseEx(str, value, first, locale, true);
+        }
+        byte[] result = new byte[len];
+        System.arraycopy(value, 0, result, 0, first);  // Just copy the first few
+                                                       // upperCase characters.
+        for (int i = first; i < len; i++) {
+            int cp = value[i] & 0xff;
+            cp = Character.toUpperCaseEx(cp);
+            if (!canEncode(cp)) {                      // not a latin1 character
+                return toUpperCaseEx(str, value, first, locale, false);
+            }
+            result[i] = (byte)cp;
+        }
+        return new String(result, LATIN1);
+    }
+
+    private static String toUpperCaseEx(String str, byte[] value,
+                                        int first, Locale locale, boolean localeDependent)
+    {
+        byte[] result = StringUTF16.newBytesFor(value.length);
+        int resultOffset = 0;
+        for (int i = 0; i < first; i++) {
+            StringUTF16.putChar(result, resultOffset++, value[i] & 0xff);
+        }
+        for (int i = first; i < value.length; i++) {
+            int srcChar = value[i] & 0xff;
+            int upperChar;
+            char[] upperCharArray;
+            if (localeDependent) {
+                upperChar = ConditionalSpecialCasing.toUpperCaseEx(str, i, locale);
+            } else {
+                upperChar = Character.toUpperCaseEx(srcChar);
+            }
+            if (Character.isBmpCodePoint(upperChar)) {
+                StringUTF16.putChar(result, resultOffset++, upperChar);
+            } else {
+                if (upperChar == Character.ERROR) {
+                    if (localeDependent) {
+                        upperCharArray =
+                            ConditionalSpecialCasing.toUpperCaseCharArray(str, i, locale);
+                    } else {
+                        upperCharArray = Character.toUpperCaseCharArray(srcChar);
+                    }
+                } else {
+                    upperCharArray = Character.toChars(upperChar);
+                }
+                /* Grow result if needed */
+                int mapLen = upperCharArray.length;
+                if (mapLen > 1) {
+                    byte[] result2 = StringUTF16.newBytesFor((result.length >> 1) + mapLen - 1);
+                    System.arraycopy(result, 0, result2, 0, resultOffset << 1);
+                    result = result2;
+                }
+                for (int x = 0; x < mapLen; ++x) {
+                    StringUTF16.putChar(result, resultOffset++, upperCharArray[x]);
+                }
+            }
+        }
+        return StringUTF16.newString(result, 0, resultOffset);
+    }
+
+    public static String trim(byte[] value) {
+        int len = value.length;
+        int st = 0;
+        while ((st < len) && ((value[st] & 0xff) <= ' ')) {
+            st++;
+        }
+        while ((st < len) && ((value[len - 1] & 0xff) <= ' ')) {
+            len--;
+        }
+        return ((st > 0) || (len < value.length)) ?
+            newString(value, st, len - st) : null;
+    }
+
+    public static void putChar(byte[] val, int index, int c) {
+        //assert (canEncode(c));
+        val[index] = (byte)(c);
+    }
+
+    public static char getChar(byte[] val, int index) {
+        return (char)(val[index] & 0xff);
+    }
+
+    public static byte[] toBytes(int[] val, int off, int len) {
+        byte[] ret = new byte[len];
+        for (int i = 0; i < len; i++) {
+            int cp = val[off++];
+            if (!canEncode(cp)) {
+                return null;
+            }
+            ret[i] = (byte)cp;
+        }
+        return ret;
+    }
+
+    public static byte[] toBytes(char c) {
+        return new byte[] { (byte)c };
+    }
+
+    public static String newString(byte[] val, int index, int len) {
+        return new String(Arrays.copyOfRange(val, index, index + len),
+                          LATIN1);
+    }
+
+    public static void fillNull(byte[] val, int index, int end) {
+        Arrays.fill(val, index, end, (byte)0);
+    }
+
+    // inflatedCopy byte[] -> char[]
+    @HotSpotIntrinsicCandidate
+    private static void inflate(byte[] src, int srcOff, char[] dst, int dstOff, int len) {
+        for (int i = 0; i < len; i++) {
+            dst[dstOff++] = (char)(src[srcOff++] & 0xff);
+        }
+    }
+
+    // inflatedCopy byte[] -> byte[]
+    @HotSpotIntrinsicCandidate
+    public static void inflate(byte[] src, int srcOff, byte[] dst, int dstOff, int len) {
+        for (int i = 0; i < len; i++) {
+            StringUTF16.putChar(dst, dstOff++, src[srcOff++] & 0xff);
+        }
+    }
+
+    static class CharsSpliterator implements Spliterator.OfInt {
+        private final byte[] array;
+        private int index;        // current index, modified on advance/split
+        private final int fence;  // one past last index
+        private final int cs;
+
+        CharsSpliterator(byte[] array, int acs) {
+            this(array, 0, array.length, acs);
+        }
+
+        CharsSpliterator(byte[] array, int origin, int fence, int acs) {
+            this.array = array;
+            this.index = origin;
+            this.fence = fence;
+            this.cs = acs | Spliterator.ORDERED | Spliterator.SIZED
+                      | Spliterator.SUBSIZED;
+        }
+
+        @Override
+        public OfInt trySplit() {
+            int lo = index, mid = (lo + fence) >>> 1;
+            return (lo >= mid)
+                   ? null
+                   : new CharsSpliterator(array, lo, index = mid, cs);
+        }
+
+        @Override
+        public void forEachRemaining(IntConsumer action) {
+            byte[] a; int i, hi; // hoist accesses and checks from loop
+            if (action == null)
+                throw new NullPointerException();
+            if ((a = array).length >= (hi = fence) &&
+                (i = index) >= 0 && i < (index = hi)) {
+                do { action.accept(a[i] & 0xff); } while (++i < hi);
+            }
+        }
+
+        @Override
+        public boolean tryAdvance(IntConsumer action) {
+            if (action == null)
+                throw new NullPointerException();
+            if (index >= 0 && index < fence) {
+                action.accept(array[index++] & 0xff);
+                return true;
+            }
+            return false;
+        }
+
+        @Override
+        public long estimateSize() { return (long)(fence - index); }
+
+        @Override
+        public int characteristics() {
+            return cs;
+        }
+    }
+
+    ////////////////////////////////////////////////////////////////
+
+    public static void getCharsSB(byte[] val, int srcBegin, int srcEnd, char dst[], int dstBegin) {
+        checkOffset(srcEnd, val.length);
+        getChars(val, srcBegin, srcEnd, dst, dstBegin);
+    }
+
+    public static void inflateSB(byte[] val, byte[] dst, int dstOff, int count) {
+        checkOffset(count, val.length);
+        checkOffset(dstOff + count, dst.length >> 1);  // dst is utf16
+        inflate(val, 0, dst, dstOff, count);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/java.base/share/classes/java/lang/StringUTF16.java	Tue Nov 17 10:29:28 2015 -0800
@@ -0,0 +1,971 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package java.lang;
+
+import java.util.Arrays;
+import java.util.Locale;
+import java.util.Spliterator;
+import java.util.function.IntConsumer;
+import jdk.internal.HotSpotIntrinsicCandidate;
+
+import static java.lang.String.UTF16;
+import static java.lang.String.LATIN1;
+import static java.lang.String.checkIndex;
+import static java.lang.String.checkOffset;
+
+final class StringUTF16 {
+
+    public static byte[] newBytesFor(int len) {
+        if (len < 0) {
+            throw new NegativeArraySizeException();
+        }
+        if (len > MAX_LENGTH) {
+            throw new OutOfMemoryError("UTF16 String size is " + len +
+                                       ", should be less than " + MAX_LENGTH);
+        }
+        return new byte[len << 1];
+    }
+
+    @HotSpotIntrinsicCandidate
+    public static void putChar(byte[] val, int index, int c) {
+        index <<= 1;
+        val[index++] = (byte)(c >> HI_BYTE_SHIFT);
+        val[index]   = (byte)(c >> LO_BYTE_SHIFT);
+    }
+
+    @HotSpotIntrinsicCandidate
+    public static char getChar(byte[] val, int index) {
+        index <<= 1;
+        return (char)(((val[index++] & 0xff) << HI_BYTE_SHIFT) |
+                      ((val[index]   & 0xff) << LO_BYTE_SHIFT));
+    }
+
+    public static char charAt(byte[] value, int index) {
+        if (index < 0 || index >= value.length >> 1) {
+            throw new StringIndexOutOfBoundsException(index);
+        }
+        return getChar(value, index);
+    }
+
+    public static int length(byte[] value) {
+        return value.length >> 1;
+    }
+
+    public static int codePointAt(byte[] value, int index, int end) {
+        char c1 = getChar(value, index);
+        if (Character.isHighSurrogate(c1) && ++index < end) {
+            char c2 = getChar(value, index);
+            if (Character.isLowSurrogate(c2)) {
+               return Character.toCodePoint(c1, c2);
+            }
+        }
+        return c1;
+    }
+
+    public static int codePointBefore(byte[] value, int index) {
+        char c2 = getChar(value, --index);
+        if (Character.isLowSurrogate(c2) && index > 0) {
+            char c1 = getChar(value, --index);
+            if (Character.isHighSurrogate(c1)) {
+               return Character.toCodePoint(c1, c2);
+            }
+        }
+        return c2;
+    }
+
+    public static int codePointCount(byte[] value, int beginIndex, int endIndex) {
+        int count = endIndex - beginIndex;
+        for (int i = beginIndex; i < endIndex; ) {
+            if (Character.isHighSurrogate(getChar(value, i++)) &&
+                i < endIndex &&
+                Character.isLowSurrogate(getChar(value, i))) {
+                count--;
+                i++;
+            }
+        }
+        return count;
+    }
+
+    public static char[] toChars(byte[] value) {
+        char[] dst = new char[value.length >> 1];
+        getChars(value, 0, dst.length, dst, 0);
+        return dst;
+    }
+
+    @HotSpotIntrinsicCandidate
+    public static byte[] toBytes(char[] value, int off, int len) {
+        byte[] val = newBytesFor(len);
+        for (int i = 0; i < len; i++) {
+            putChar(val, i, value[off++]);
+        }
+        return val;
+    }
+
+    public static byte[] compress(char[] val, int off, int len) {
+        byte[] ret = new byte[len];
+        if (compress(val, off, ret, 0, len) == len) {
+            return ret;
+        }
+        return null;
+    }
+
+    public static byte[] compress(byte[] val, int off, int len) {
+        byte[] ret = new byte[len];
+        if (compress(val, off, ret, 0, len) == len) {
+            return ret;
+        }
+        return null;
+    }
+
+    // compressedCopy char[] -> byte[]
+    @HotSpotIntrinsicCandidate
+    private static int compress(char[] src, int srcOff, byte[] dst, int dstOff, int len) {
+        for (int i = 0; i < len; i++) {
+            int c = src[srcOff++];
+            if (c >>> 8 != 0) {
+                return 0;
+            }
+            dst[dstOff++] = (byte)c;
+        }
+        return len;
+    }
+
+    // compressedCopy byte[] -> byte[]
+    @HotSpotIntrinsicCandidate
+    public static int compress(byte[] src, int srcOff, byte[] dst, int dstOff, int len) {
+        for (int i = 0; i < len; i++) {
+            int c = getChar(src, srcOff++);
+            if (c >>> 8 != 0) {
+                return 0;
+            }
+            dst[dstOff++] = (byte)c;
+        }
+        return len;
+    }
+
+    public static byte[] toBytes(int[] val, int index, int len) {
+        final int end = index + len;
+        // Pass 1: Compute precise size of char[]
+        int n = len;
+        for (int i = index; i < end; i++) {
+            int cp = val[i];
+            if (Character.isBmpCodePoint(cp))
+                continue;
+            else if (Character.isValidCodePoint(cp))
+                n++;
+            else throw new IllegalArgumentException(Integer.toString(cp));
+        }
+        // Pass 2: Allocate and fill in <high, low> pair
+        byte[] buf = newBytesFor(n);
+        for (int i = index, j = 0; i < end; i++, j++) {
+            int cp = val[i];
+            if (Character.isBmpCodePoint(cp)) {
+                putChar(buf, j, cp);
+            } else {
+                putChar(buf, j++, Character.highSurrogate(cp));
+                putChar(buf, j, Character.lowSurrogate(cp));
+            }
+        }
+        return buf;
+    }
+
+    public static byte[] toBytes(char c) {
+        byte[] result = new byte[2];
+        putChar(result, 0, c);
+        return result;
+    }
+
+    @HotSpotIntrinsicCandidate
+    public static void getChars(byte[] value, int srcBegin, int srcEnd, char dst[], int dstBegin) {
+        for (int i = srcBegin; i < srcEnd; i++) {
+            dst[dstBegin++] = getChar(value, i);
+        }
+    }
+
+    /* @see java.lang.String.getBytes(int, int, byte[], int) */
+    public static void getBytes(byte[] value, int srcBegin, int srcEnd, byte dst[], int dstBegin) {
+        srcBegin <<= 1;
+        srcEnd <<= 1;
+        for (int i = srcBegin + (1 >> LO_BYTE_SHIFT); i < srcEnd; i += 2) {
+            dst[dstBegin++] = value[i];
+        }
+    }
+
+    @HotSpotIntrinsicCandidate
+    public static boolean equals(byte[] value, byte[] other) {
+        if (value.length == other.length) {
+            int len = value.length >> 1;
+            for (int i = 0; i < len; i++) {
+                if (getChar(value, i) != getChar(other, i)) {
+                    return false;
+                }
+            }
+            return true;
+        }
+        return false;
+    }
+
+    @HotSpotIntrinsicCandidate
+    public static int compareTo(byte[] value, byte[] other) {
+        int len1 = length(value);
+        int len2 = length(other);
+        int lim = Math.min(len1, len2);
+        for (int k = 0; k < lim; k++) {
+            char c1 = getChar(value, k);
+            char c2 = getChar(other, k);
+            if (c1 != c2) {
+                return c1 - c2;
+            }
+        }
+        return len1 - len2;
+    }
+
+    @HotSpotIntrinsicCandidate
+    public static int compareToLatin1(byte[] value, byte[] other) {
+        int len1 = length(value);
+        int len2 = StringLatin1.length(other);
+        int lim = Math.min(len1, len2);
+        for (int k = 0; k < lim; k++) {
+            char c1 = getChar(value, k);
+            char c2 = StringLatin1.getChar(other, k);
+            if (c1 != c2) {
+                return c1 - c2;
+            }
+        }
+        return len1 - len2;
+    }
+
+    public static int hashCode(byte[] value) {
+        int h = 0;
+        int length = value.length >> 1;
+        for (int i = 0; i < length; i++) {
+            h = 31 * h + getChar(value, i);
+        }
+        return h;
+    }
+
+    public static int indexOf(byte[] value, int ch, int fromIndex) {
+        int max = value.length >> 1;
+        if (fromIndex < 0) {
+            fromIndex = 0;
+        } else if (fromIndex >= max) {
+            // Note: fromIndex might be near -1>>>1.
+            return -1;
+        }
+        if (ch < Character.MIN_SUPPLEMENTARY_CODE_POINT) {
+            // handle most cases here (ch is a BMP code point or a
+            // negative value (invalid code point))
+            return indexOfChar(value, ch, fromIndex, max);
+        } else {
+            return indexOfSupplementary(value, ch, fromIndex, max);
+        }
+    }
+
+    @HotSpotIntrinsicCandidate
+    public static int indexOf(byte[] value, byte[] str) {
+        if (str.length == 0) {
+            return 0;
+        }
+        if (value.length == 0) {
+            return -1;
+        }
+        return indexOf(value, length(value), str, length(str), 0);
+    }
+
+    @HotSpotIntrinsicCandidate
+    public static int indexOf(byte[] value, int valueCount, byte[] str, int strCount, int fromIndex) {
+        char first = getChar(str, 0);
+        int max = (valueCount - strCount);
+        for (int i = fromIndex; i <= max; i++) {
+            // Look for first character.
+            if (getChar(value, i) != first) {
+                while (++i <= max && getChar(value, i) != first);
+            }
+            // Found first character, now look at the rest of value
+            if (i <= max) {
+                int j = i + 1;
+                int end = j + strCount - 1;
+                for (int k = 1; j < end && getChar(value, j) == getChar(str, k); j++, k++);
+                if (j == end) {
+                    // Found whole string.
+                    return i;
+                }
+            }
+        }
+        return -1;
+    }
+
+    /**
+     * Handles indexOf Latin1 substring in UTF16 string.
+     */
+    @HotSpotIntrinsicCandidate
+    public static int indexOfLatin1(byte[] value, byte[] str) {
+        if (str.length == 0) {
+            return 0;
+        }
+        if (value.length == 0) {
+            return -1;
+        }
+        return indexOfLatin1(value, length(value), str, str.length, 0);
+    }
+
+    @HotSpotIntrinsicCandidate
+    public static int indexOfLatin1(byte[] src, int srcCount, byte[] tgt, int tgtCount, int fromIndex) {
+        char first = (char)(tgt[0] & 0xff);
+        int max = (srcCount - tgtCount);
+        for (int i = fromIndex; i <= max; i++) {
+            // Look for first character.
+            if (getChar(src, i) != first) {
+                while (++i <= max && getChar(src, i) != first);
+            }
+            // Found first character, now look at the rest of v2
+            if (i <= max) {
+                int j = i + 1;
+                int end = j + tgtCount - 1;
+                for (int k = 1;
+                     j < end && getChar(src, j) == (tgt[k] & 0xff);
+                     j++, k++);
+                if (j == end) {
+                    // Found whole string.
+                    return i;
+                }
+            }
+        }
+        return -1;
+    }
+
+    @HotSpotIntrinsicCandidate
+    private static int indexOfChar(byte[] value, int ch, int fromIndex, int max) {
+        for (int i = fromIndex; i < max; i++) {
+            if (getChar(value, i) == ch) {
+                return i;
+            }
+        }
+        return -1;
+    }
+
+    /**
+     * Handles (rare) calls of indexOf with a supplementary character.
+     */
+    private static int indexOfSupplementary(byte[] value, int ch, int fromIndex, int max) {
+        if (Character.isValidCodePoint(ch)) {
+            final char hi = Character.highSurrogate(ch);
+            final char lo = Character.lowSurrogate(ch);
+            for (int i = fromIndex; i < max - 1; i++) {
+                if (getChar(value, i) == hi && getChar(value, i + 1 ) == lo) {
+                    return i;
+                }
+            }
+        }
+        return -1;
+    }
+
+    public static int lastIndexOf(byte[] src, int srcCount,
+                                  byte[] tgt, int tgtCount, int fromIndex) {
+        int min = tgtCount - 1;
+        int i = min + fromIndex;
+        int strLastIndex = tgtCount - 1;
+        char strLastChar = getChar(tgt, strLastIndex);
+
+    startSearchForLastChar:
+        while (true) {
+            while (i >= min && getChar(src, i) != strLastChar) {
+                i--;
+            }
+            if (i < min) {
+                return -1;
+            }
+            int j = i - 1;
+            int start = j - strLastIndex;
+            int k = strLastIndex - 1;
+            while (j > start) {
+                if (getChar(src, j--) != getChar(tgt, k--)) {
+                    i--;
+                    continue startSearchForLastChar;
+                }
+            }
+            return start + 1;
+        }
+    }
+
+    public static int lastIndexOf(byte[] value, int ch, int fromIndex) {
+        if (ch < Character.MIN_SUPPLEMENTARY_CODE_POINT) {
+            // handle most cases here (ch is a BMP code point or a
+            // negative value (invalid code point))
+            int i = Math.min(fromIndex, (value.length >> 1) - 1);
+            for (; i >= 0; i--) {
+                if (getChar(value, i) == ch) {
+                    return i;
+                }
+            }
+            return -1;
+        } else {
+            return lastIndexOfSupplementary(value, ch, fromIndex);
+        }
+    }
+
+    /**
+     * Handles (rare) calls of lastIndexOf with a supplementary character.
+     */
+    private static int lastIndexOfSupplementary(final byte[] value, int ch, int fromIndex) {
+        if (Character.isValidCodePoint(ch)) {
+            char hi = Character.highSurrogate(ch);
+            char lo = Character.lowSurrogate(ch);
+            int i = Math.min(fromIndex, (value.length >> 1) - 2);
+            for (; i >= 0; i--) {
+                if (getChar(value, i) == hi && getChar(value, i + 1) == lo) {
+                    return i;
+                }
+            }
+        }
+        return -1;
+    }
+
+    public static String replace(byte[] value, char oldChar, char newChar) {
+        int len = value.length >> 1;
+        int i = -1;
+        while (++i < len) {
+            if (getChar(value, i) == oldChar) {
+                break;
+            }
+        }
+        if (i < len) {
+            byte buf[] = new byte[value.length];
+            for (int j = 0; j < i; j++) {
+                putChar(buf, j, getChar(value, j)); // TBD:arraycopy?
+            }
+            while (i < len) {
+                char c = getChar(value, i);
+                putChar(buf, i, c == oldChar ? newChar : c);
+                i++;
+           }
+           // Check if we should try to compress to latin1
+           if (String.COMPACT_STRINGS &&
+               !StringLatin1.canEncode(oldChar) &&
+               StringLatin1.canEncode(newChar)) {
+               byte[] val = compress(buf, 0, len);
+               if (val != null) {
+                   return new String(val, LATIN1);
+               }
+           }
+           return new String(buf, UTF16);
+        }
+        return null;
+    }
+
+    public static boolean regionMatchesCI(byte[] value, int toffset,
+                                          byte[] other, int ooffset, int len) {
+        int last = toffset + len;
+        while (toffset < last) {
+            char c1 = getChar(value, toffset++);
+            char c2 = getChar(other, ooffset++);
+            if (c1 == c2) {
+                continue;
+            }
+            // try converting both characters to uppercase.
+            // If the results match, then the comparison scan should
+            // continue.
+            char u1 = Character.toUpperCase(c1);
+            char u2 = Character.toUpperCase(c2);
+            if (u1 == u2) {
+                continue;
+            }
+            // Unfortunately, conversion to uppercase does not work properly
+            // for the Georgian alphabet, which has strange rules about case
+            // conversion.  So we need to make one last check before
+            // exiting.
+            if (Character.toLowerCase(u1) == Character.toLowerCase(u2)) {
+                continue;
+            }
+            return false;
+        }
+        return true;
+    }
+
+    public static boolean regionMatchesCI_Latin1(byte[] value, int toffset,
+                                                 byte[] other, int ooffset,
+                                                 int len) {
+        int last = toffset + len;
+        while (toffset < last) {
+            char c1 = getChar(value, toffset++);
+            char c2 = (char)(other[ooffset++] & 0xff);
+            if (c1 == c2) {
+                continue;
+            }
+            char u1 = Character.toUpperCase(c1);
+            char u2 = Character.toUpperCase(c2);
+            if (u1 == u2) {
+                continue;
+            }
+            if (Character.toLowerCase(u1) == Character.toLowerCase(u2)) {
+                continue;
+            }
+            return false;
+        }
+        return true;
+    }
+
+    public static String toLowerCase(String str, byte[] value, Locale locale) {
+        if (locale == null) {
+            throw new NullPointerException();
+        }
+        int first;
+        boolean hasSurr = false;
+        final int len = value.length >> 1;
+
+        // Now check if there are any characters that need to be changed, or are surrogate
+        for (first = 0 ; first < len; first++) {
+            int cp = (int)getChar(value, first);
+            if (Character.isSurrogate((char)cp)) {
+                hasSurr = true;
+                break;
+            }
+            if (cp != Character.toLowerCase(cp)) {  // no need to check Character.ERROR
+                break;
+            }
+        }
+        if (first == len)
+            return str;
+        byte[] result = new byte[value.length];
+        System.arraycopy(value, 0, result, 0, first << 1);  // Just copy the first few
+                                                            // lowerCase characters.
+        String lang = locale.getLanguage();
+        if (lang == "tr" || lang == "az" || lang == "lt") {
+            return toLowerCaseEx(str, value, result, first, locale, true);
+        }
+        if (hasSurr) {
+            return toLowerCaseEx(str, value, result, first, locale, false);
+        }
+        int bits = 0;
+        for (int i = first; i < len; i++) {
+            int cp = (int)getChar(value, i);
+            if (cp == '\u03A3' ||                       // GREEK CAPITAL LETTER SIGMA
+                Character.isSurrogate((char)cp)) {
+                return toLowerCaseEx(str, value, result, i, locale, false);
+            }
+            if (cp == '\u0130') {                       // LATIN CAPITAL LETTER I WITH DOT ABOVE
+                return toLowerCaseEx(str, value, result, i, locale, true);
+            }
+            cp = Character.toLowerCase(cp);
+            if (!Character.isBmpCodePoint(cp)) {
+                return toLowerCaseEx(str, value, result, i, locale, false);
+            }
+            bits |= cp;
+            putChar(result, i, cp);
+        }
+        if (bits >>> 8 != 0) {
+            return new String(result, UTF16);
+        } else {
+            return newString(result, 0, len);
+        }
+    }
+
+    private static String toLowerCaseEx(String str, byte[] value,
+                                        byte[] result, int first, Locale locale,
+                                        boolean localeDependent) {
+        int resultOffset = first;
+        int length = value.length >> 1;
+        int srcCount;
+        for (int i = first; i < length; i += srcCount) {
+            int srcChar = getChar(value, i);
+            int lowerChar;
+            char[] lowerCharArray;
+            srcCount = 1;
+            if (Character.isSurrogate((char)srcChar)) {
+                srcChar = codePointAt(value, i, length);
+                srcCount = Character.charCount(srcChar);
+            }
+            if (localeDependent ||
+                srcChar == '\u03A3' ||  // GREEK CAPITAL LETTER SIGMA
+                srcChar == '\u0130') {  // LATIN CAPITAL LETTER I WITH DOT ABOVE
+                lowerChar = ConditionalSpecialCasing.toLowerCaseEx(str, i, locale);
+            } else {
+                lowerChar = Character.toLowerCase(srcChar);
+            }
+            if (Character.isBmpCodePoint(lowerChar)) {    // Character.ERROR is not a bmp
+                putChar(result, resultOffset++, lowerChar);
+            } else {
+                if (lowerChar == Character.ERROR) {
+                    lowerCharArray = ConditionalSpecialCasing.toLowerCaseCharArray(str, i, locale);
+                } else {
+                    lowerCharArray = Character.toChars(lowerChar);
+                }
+                /* Grow result if needed */
+                int mapLen = lowerCharArray.length;
+                if (mapLen > srcCount) {
+                    byte[] result2 = newBytesFor((result.length >> 1) + mapLen - srcCount);
+                    System.arraycopy(result, 0, result2, 0, resultOffset << 1);
+                    result = result2;
+                }
+                for (int x = 0; x < mapLen; ++x) {
+                    putChar(result, resultOffset++, lowerCharArray[x]);
+                }
+            }
+        }
+        return newString(result, 0, resultOffset);
+    }
+
+    public static String toUpperCase(String str, byte[] value, Locale locale) {
+        if (locale == null) {
+            throw new NullPointerException();
+        }
+        int first;
+        boolean hasSurr = false;
+        final int len = value.length >> 1;
+
+        // Now check if there are any characters that need to be changed, or are surrogate
+        for (first = 0 ; first < len; first++) {
+            int cp = (int)getChar(value, first);
+            if (Character.isSurrogate((char)cp)) {
+                hasSurr = true;
+                break;
+            }
+            if (cp != Character.toUpperCaseEx(cp)) {   // no need to check Character.ERROR
+                break;
+            }
+        }
+        if (first == len) {
+            return str;
+        }
+        byte[] result = new byte[value.length];
+        System.arraycopy(value, 0, result, 0, first << 1); // Just copy the first few
+                                                           // upperCase characters.
+        String lang = locale.getLanguage();
+        if (lang == "tr" || lang == "az" || lang == "lt") {
+            return toUpperCaseEx(str, value, result, first, locale, true);
+        }
+        if (hasSurr) {
+            return toUpperCaseEx(str, value, result, first, locale, false);
+        }
+        int bits = 0;
+        for (int i = first; i < len; i++) {
+            int cp = (int)getChar(value, i);
+            if (Character.isSurrogate((char)cp)) {
+                return toUpperCaseEx(str, value, result, i, locale, false);
+            }
+            cp = Character.toUpperCaseEx(cp);
+            if (!Character.isBmpCodePoint(cp)) {    // Character.ERROR is not bmp
+                return toUpperCaseEx(str, value, result, i, locale, false);
+            }
+            bits |= cp;
+            putChar(result, i, cp);
+        }
+        if (bits >>> 8 != 0) {
+            return new String(result, UTF16);
+        } else {
+            return newString(result, 0, len);
+        }
+    }
+
+    private static String toUpperCaseEx(String str, byte[] value,
+                                        byte[] result, int first,
+                                        Locale locale, boolean localeDependent)
+    {
+        int resultOffset = first;
+        int length = value.length >> 1;
+        int srcCount;
+        for (int i = first; i < length; i += srcCount) {
+            int srcChar = getChar(value, i);
+            int upperChar;
+            char[] upperCharArray;
+            srcCount = 1;
+            if (Character.isSurrogate((char)srcChar)) {
+                srcChar = codePointAt(value, i, length);
+                srcCount = Character.charCount(srcChar);
+            }
+            if (localeDependent) {
+                upperChar = ConditionalSpecialCasing.toUpperCaseEx(str, i, locale);
+            } else {
+                upperChar = Character.toUpperCaseEx(srcChar);
+            }
+            if (Character.isBmpCodePoint(upperChar)) {
+                putChar(result, resultOffset++, upperChar);
+            } else {
+                if (upperChar == Character.ERROR) {
+                    if (localeDependent) {
+                        upperCharArray =
+                            ConditionalSpecialCasing.toUpperCaseCharArray(str, i, locale);
+                    } else {
+                        upperCharArray = Character.toUpperCaseCharArray(srcChar);
+                    }
+                } else {
+                    upperCharArray = Character.toChars(upperChar);
+                }
+                /* Grow result if needed */
+                int mapLen = upperCharArray.length;
+                if (mapLen > srcCount) {
+                    byte[] result2 = newBytesFor((result.length >> 1) + mapLen - srcCount);
+                    System.arraycopy(result, 0, result2, 0, resultOffset << 1);
+                    result = result2;
+                 }
+                 for (int x = 0; x < mapLen; ++x) {
+                    putChar(result, resultOffset++, upperCharArray[x]);
+                 }
+            }
+        }
+        return newString(result, 0, resultOffset);
+    }
+
+    public static String trim(byte[] value) {
+        int length = value.length >> 1;
+        int len = length;
+        int st = 0;
+        while (st < len && getChar(value, st) <= ' ') {
+            st++;
+        }
+        while (st < len && getChar(value, len - 1) <= ' ') {
+            len--;
+        }
+        return ((st > 0) || (len < length )) ?
+            new String(Arrays.copyOfRange(value, st << 1, len << 1), UTF16) :
+            null;
+    }
+
+    public static void putChars(byte[] val, int index, char[] str, int off, int end) {
+        while (off < end) {
+            putChar(val, index++, str[off++]);
+        }
+    }
+
+    public static String newString(byte[] val, int index, int len) {
+        if (String.COMPACT_STRINGS) {
+            byte[] buf = compress(val, index, len);
+            if (buf != null) {
+                return new String(buf, LATIN1);
+            }
+        }
+        int last = index + len;
+        return new String(Arrays.copyOfRange(val, index << 1, last << 1), UTF16);
+    }
+
+    public static void fillNull(byte[] val, int index, int end) {
+        Arrays.fill(val, index << 1, end << 1, (byte)0);
+    }
+
+    static class CharsSpliterator implements Spliterator.OfInt {
+        private final byte[] array;
+        private int index;        // current index, modified on advance/split
+        private final int fence;  // one past last index
+        private final int cs;
+
+        CharsSpliterator(byte[] array, int acs) {
+            this(array, 0, array.length >> 1, acs);
+        }
+
+        CharsSpliterator(byte[] array, int origin, int fence, int acs) {
+            this.array = array;
+            this.index = origin;
+            this.fence = fence;
+            this.cs = acs | Spliterator.ORDERED | Spliterator.SIZED
+                      | Spliterator.SUBSIZED;
+        }
+
+        @Override
+        public OfInt trySplit() {
+            int lo = index, mid = (lo + fence) >>> 1;
+            return (lo >= mid)
+                   ? null
+                   : new CharsSpliterator(array, lo, index = mid, cs);
+        }
+
+        @Override
+        public void forEachRemaining(IntConsumer action) {
+            byte[] a; int i, hi; // hoist accesses and checks from loop
+            if (action == null)
+                throw new NullPointerException();
+            if (((a = array).length >> 1) >= (hi = fence) &&
+                (i = index) >= 0 && i < (index = hi)) {
+                do { action.accept(getChar(a, i)); } while (++i < hi);
+            }
+        }
+
+        @Override
+        public boolean tryAdvance(IntConsumer action) {
+            if (action == null)
+                throw new NullPointerException();
+            if (index >= 0 && index < fence) {
+                action.accept(getChar(array, index++));
+                return true;
+            }
+            return false;
+        }
+
+        @Override
+        public long estimateSize() { return (long)(fence - index); }
+
+        @Override
+        public int characteristics() {
+            return cs;
+        }
+    }
+
+    static class CodePointsSpliterator implements Spliterator.OfInt {
+        private final byte[] array;
+        private int index;        // current index, modified on advance/split
+        private final int fence;  // one past last index
+        private final int cs;
+
+        CodePointsSpliterator(byte[] array, int acs) {
+            this(array, 0, array.length >> 1, acs);
+        }
+
+        CodePointsSpliterator(byte[] array, int origin, int fence, int acs) {
+            this.array = array;
+            this.index = origin;
+            this.fence = fence;
+            this.cs = acs | Spliterator.ORDERED;
+        }
+
+        @Override
+        public OfInt trySplit() {
+            int lo = index, mid = (lo + fence) >>> 1;
+            if (lo >= mid)
+                return null;
+
+            int midOneLess;
+            // If the mid-point intersects a surrogate pair
+            if (Character.isLowSurrogate(getChar(array, mid)) &&
+                Character.isHighSurrogate(getChar(array, midOneLess = (mid -1)))) {
+                // If there is only one pair it cannot be split
+                if (lo >= midOneLess)
+                    return null;
+                // Shift the mid-point to align with the surrogate pair
+                return new CodePointsSpliterator(array, lo, index = midOneLess, cs);
+            }
+            return new CodePointsSpliterator(array, lo, index = mid, cs);
+        }
+
+        @Override
+        public void forEachRemaining(IntConsumer action) {
+            byte[] a; int i, hi; // hoist accesses and checks from loop
+            if (action == null)
+                throw new NullPointerException();
+            if (((a = array).length >> 1) >= (hi = fence) &&
+                (i = index) >= 0 && i < (index = hi)) {
+                do {
+                    i = advance(a, i, hi, action);
+                } while (i < hi);
+            }
+        }
+
+        @Override
+        public boolean tryAdvance(IntConsumer action) {
+            if (action == null)
+                throw new NullPointerException();
+            if (index >= 0 && index < fence) {
+                index = advance(array, index, fence, action);
+                return true;
+            }
+            return false;
+        }
+
+        // Advance one code point from the index, i, and return the next
+        // index to advance from
+        private static int advance(byte[] a, int i, int hi, IntConsumer action) {
+            char c1 = getChar(a, i++);
+            int cp = c1;
+            if (Character.isHighSurrogate(c1) && i < hi) {
+                char c2 = getChar(a, i);
+                if (Character.isLowSurrogate(c2)) {
+                    i++;
+                    cp = Character.toCodePoint(c1, c2);
+                }
+            }
+            action.accept(cp);
+            return i;
+        }
+
+        @Override
+        public long estimateSize() { return (long)(fence - index); }
+
+        @Override
+        public int characteristics() {
+            return cs;
+        }
+    }
+
+    ////////////////////////////////////////////////////////////////
+
+    public static void getCharsSB(byte[] val, int srcBegin, int srcEnd, char dst[], int dstBegin) {
+        checkOffset(srcEnd, val.length >> 1);
+        getChars(val, srcBegin, srcEnd, dst, dstBegin);
+    }
+
+    public static void putCharSB(byte[] val, int index, int c) {
+        checkIndex(index, val.length >> 1);
+        putChar(val, index, c);
+    }
+
+    public static void putCharsSB(byte[] val, int index, char[] ca, int off, int end) {
+        checkOffset(index + end - off, val.length >> 1);
+        putChars(val, index, ca, off, end);
+    }
+
+    public static void putCharsSB(byte[] val, int index, CharSequence s, int off, int end) {
+        checkOffset(index + end - off, val.length >> 1);
+        for (int i = off; i < end; i++) {
+            putChar(val, index++, s.charAt(i));
+        }
+    }
+
+    public static int codePointAtSB(byte[] val, int index, int end) {
+        checkOffset(end, val.length >> 1);
+        return codePointAt(val, index, end);
+    }
+
+    public static int codePointBeforeSB(byte[] val, int index) {
+        checkOffset(index, val.length >> 1);
+        return codePointBefore(val, index);
+    }
+
+    public static int codePointCountSB(byte[] val, int beginIndex, int endIndex) {
+        checkOffset(endIndex, val.length >> 1);
+        return codePointCount(val, beginIndex, endIndex);
+    }
+
+    public static String newStringSB(byte[] val, int index, int len) {
+        checkOffset(index + len, val.length >> 1);
+        return newString(val, index, len);
+    }
+
+    ////////////////////////////////////////////////////////////////
+
+    private static native boolean isBigEndian();
+
+    static final int HI_BYTE_SHIFT;
+    static final int LO_BYTE_SHIFT;
+    static {
+        if (isBigEndian()) {
+            HI_BYTE_SHIFT = 8;
+            LO_BYTE_SHIFT = 0;
+        } else {
+            HI_BYTE_SHIFT = 0;
+            LO_BYTE_SHIFT = 8;
+        }
+    }
+
+    static final int MAX_LENGTH = Integer.MAX_VALUE >> 1;
+}
--- a/src/java.base/share/classes/java/lang/invoke/DirectMethodHandle.java	Tue Nov 10 13:46:45 2015 +0300
+++ b/src/java.base/share/classes/java/lang/invoke/DirectMethodHandle.java	Tue Nov 17 10:29:28 2015 -0800
@@ -25,7 +25,7 @@
 
 package java.lang.invoke;
 
-import sun.misc.Unsafe;
+import jdk.internal.misc.Unsafe;
 import java.lang.reflect.Method;
 import java.util.Arrays;
 import sun.invoke.util.VerifyAccess;
@@ -224,12 +224,12 @@
         assert(names.length == nameCursor);
         if (doesAlloc) {
             // names = { argx,y,z,... new C, init method }
-            names[NEW_OBJ] = new Name(Lazy.NF_allocateInstance, names[DMH_THIS]);
-            names[GET_MEMBER] = new Name(Lazy.NF_constructorMethod, names[DMH_THIS]);
+            names[NEW_OBJ] = new Name(NF_allocateInstance, names[DMH_THIS]);
+            names[GET_MEMBER] = new Name(NF_constructorMethod, names[DMH_THIS]);
         } else if (needsInit) {
-            names[GET_MEMBER] = new Name(Lazy.NF_internalMemberNameEnsureInit, names[DMH_THIS]);
+            names[GET_MEMBER] = new Name(NF_internalMemberNameEnsureInit, names[DMH_THIS]);
         } else {
-            names[GET_MEMBER] = new Name(Lazy.NF_internalMemberName, names[DMH_THIS]);
+            names[GET_MEMBER] = new Name(NF_internalMemberName, names[DMH_THIS]);
         }
         assert(findDirectMethodHandle(names[GET_MEMBER]) == names[DMH_THIS]);
         Object[] outArgs = Arrays.copyOfRange(names, ARG_BASE, GET_MEMBER+1, Object[].class);
@@ -250,9 +250,9 @@
     }
 
     static Object findDirectMethodHandle(Name name) {
-        if (name.function == Lazy.NF_internalMemberName ||
-            name.function == Lazy.NF_internalMemberNameEnsureInit ||
-            name.function == Lazy.NF_constructorMethod) {
+        if (name.function == NF_internalMemberName ||
+            name.function == NF_internalMemberNameEnsureInit ||
+            name.function == NF_constructorMethod) {
             assert(name.arguments.length == 1);
             return name.arguments[0];
         }
@@ -613,18 +613,18 @@
         final int RESULT    = nameCursor-1;  // either the call or the cast
         Name[] names = arguments(nameCursor - ARG_LIMIT, mtype.invokerType());
         if (needsInit)
-            names[INIT_BAR] = new Name(Lazy.NF_ensureInitialized, names[DMH_THIS]);
+            names[INIT_BAR] = new Name(NF_ensureInitialized, names[DMH_THIS]);
         if (needsCast && !isGetter)
-            names[PRE_CAST] = new Name(Lazy.NF_checkCast, names[DMH_THIS], names[SET_VALUE]);
+            names[PRE_CAST] = new Name(NF_checkCast, names[DMH_THIS], names[SET_VALUE]);
         Object[] outArgs = new Object[1 + linkerType.parameterCount()];
         assert(outArgs.length == (isGetter ? 3 : 4));
         outArgs[0] = UNSAFE;
         if (isStatic) {
-            outArgs[1] = names[F_HOLDER]  = new Name(Lazy.NF_staticBase, names[DMH_THIS]);
-            outArgs[2] = names[F_OFFSET]  = new Name(Lazy.NF_staticOffset, names[DMH_THIS]);
+            outArgs[1] = names[F_HOLDER]  = new Name(NF_staticBase, names[DMH_THIS]);
+            outArgs[2] = names[F_OFFSET]  = new Name(NF_staticOffset, names[DMH_THIS]);
         } else {
-            outArgs[1] = names[OBJ_CHECK] = new Name(Lazy.NF_checkBase, names[OBJ_BASE]);
-            outArgs[2] = names[F_OFFSET]  = new Name(Lazy.NF_fieldOffset, names[DMH_THIS]);
+            outArgs[1] = names[OBJ_CHECK] = new Name(NF_checkBase, names[OBJ_BASE]);
+            outArgs[2] = names[F_OFFSET]  = new Name(NF_fieldOffset, names[DMH_THIS]);
         }
         if (!isGetter) {
             outArgs[3] = (needsCast ? names[PRE_CAST] : names[SET_VALUE]);
@@ -632,7 +632,7 @@
         for (Object a : outArgs)  assert(a != null);
         names[LINKER_CALL] = new Name(linker, outArgs);
         if (needsCast && isGetter)
-            names[POST_CAST] = new Name(Lazy.NF_checkCast, names[DMH_THIS], names[LINKER_CALL]);
+            names[POST_CAST] = new Name(NF_checkCast, names[DMH_THIS], names[LINKER_CALL]);
         for (Name n : names)  assert(n != null);
         String fieldOrStatic = (isStatic ? "Static" : "Field");
         String lambdaName = (linkerName + fieldOrStatic);  // significant only for debugging
@@ -645,50 +645,45 @@
      * Pre-initialized NamedFunctions for bootstrapping purposes.
      * Factored in an inner class to delay initialization until first usage.
      */
-    private static class Lazy {
-        static final NamedFunction
-                NF_internalMemberName,
-                NF_internalMemberNameEnsureInit,
-                NF_ensureInitialized,
-                NF_fieldOffset,
-                NF_checkBase,
-                NF_staticBase,
-                NF_staticOffset,
-                NF_checkCast,
-                NF_allocateInstance,
-                NF_constructorMethod;
-        static {
-            try {
-                NamedFunction nfs[] = {
-                        NF_internalMemberName = new NamedFunction(DirectMethodHandle.class
-                                .getDeclaredMethod("internalMemberName", Object.class)),
-                        NF_internalMemberNameEnsureInit = new NamedFunction(DirectMethodHandle.class
-                                .getDeclaredMethod("internalMemberNameEnsureInit", Object.class)),
-                        NF_ensureInitialized = new NamedFunction(DirectMethodHandle.class
-                                .getDeclaredMethod("ensureInitialized", Object.class)),
-                        NF_fieldOffset = new NamedFunction(DirectMethodHandle.class
-                                .getDeclaredMethod("fieldOffset", Object.class)),
-                        NF_checkBase = new NamedFunction(DirectMethodHandle.class
-                                .getDeclaredMethod("checkBase", Object.class)),
-                        NF_staticBase = new NamedFunction(DirectMethodHandle.class
-                                .getDeclaredMethod("staticBase", Object.class)),
-                        NF_staticOffset = new NamedFunction(DirectMethodHandle.class
-                                .getDeclaredMethod("staticOffset", Object.class)),
-                        NF_checkCast = new NamedFunction(DirectMethodHandle.class
-                                .getDeclaredMethod("checkCast", Object.class, Object.class)),
-                        NF_allocateInstance = new NamedFunction(DirectMethodHandle.class
-                                .getDeclaredMethod("allocateInstance", Object.class)),
-                        NF_constructorMethod = new NamedFunction(DirectMethodHandle.class
-                                .getDeclaredMethod("constructorMethod", Object.class))
-                };
-                for (NamedFunction nf : nfs) {
-                    // Each nf must be statically invocable or we get tied up in our bootstraps.
-                    assert(InvokerBytecodeGenerator.isStaticallyInvocable(nf.member)) : nf;
-                    nf.resolve();
-                }
-            } catch (ReflectiveOperationException ex) {
-                throw newInternalError(ex);
-            }
+    static final NamedFunction
+            NF_internalMemberName,
+            NF_internalMemberNameEnsureInit,
+            NF_ensureInitialized,
+            NF_fieldOffset,
+            NF_checkBase,
+            NF_staticBase,
+            NF_staticOffset,
+            NF_checkCast,
+            NF_allocateInstance,
+            NF_constructorMethod;
+    static {
+        try {
+            NamedFunction nfs[] = {
+                    NF_internalMemberName = new NamedFunction(DirectMethodHandle.class
+                            .getDeclaredMethod("internalMemberName", Object.class)),
+                    NF_internalMemberNameEnsureInit = new NamedFunction(DirectMethodHandle.class
+                            .getDeclaredMethod("internalMemberNameEnsureInit", Object.class)),
+                    NF_ensureInitialized = new NamedFunction(DirectMethodHandle.class
+                            .getDeclaredMethod("ensureInitialized", Object.class)),
+                    NF_fieldOffset = new NamedFunction(DirectMethodHandle.class
+                            .getDeclaredMethod("fieldOffset", Object.class)),
+                    NF_checkBase = new NamedFunction(DirectMethodHandle.class
+                            .getDeclaredMethod("checkBase", Object.class)),
+                    NF_staticBase = new NamedFunction(DirectMethodHandle.class
+                            .getDeclaredMethod("staticBase", Object.class)),
+                    NF_staticOffset = new NamedFunction(DirectMethodHandle.class
+                            .getDeclaredMethod("staticOffset", Object.class)),
+                    NF_checkCast = new NamedFunction(DirectMethodHandle.class
+                            .getDeclaredMethod("checkCast", Object.class, Object.class)),
+                    NF_allocateInstance = new NamedFunction(DirectMethodHandle.class
+                            .getDeclaredMethod("allocateInstance", Object.class)),
+                    NF_constructorMethod = new NamedFunction(DirectMethodHandle.class
+                            .getDeclaredMethod("constructorMethod", Object.class))
+            };
+            // Each nf must be statically invocable or we get tied up in our bootstraps.
+            assert(InvokerBytecodeGenerator.isStaticallyInvocable(nfs));
+        } catch (ReflectiveOperationException ex) {
+            throw newInternalError(ex);
         }
     }
 }
--- a/src/java.base/share/classes/java/lang/invoke/InnerClassLambdaMetafactory.java	Tue Nov 10 13:46:45 2015 +0300
+++ b/src/java.base/share/classes/java/lang/invoke/InnerClassLambdaMetafactory.java	Tue Nov 17 10:29:28 2015 -0800
@@ -27,7 +27,7 @@
 
 import jdk.internal.org.objectweb.asm.*;
 import sun.invoke.util.BytecodeDescriptor;
-import sun.misc.Unsafe;
+import jdk.internal.misc.Unsafe;
 import sun.security.action.GetPropertyAction;
 
 import java.io.FilePermission;
--- a/src/java.base/share/classes/java/lang/invoke/InvokerBytecodeGenerator.java	Tue Nov 10 13:46:45 2015 +0300
+++ b/src/java.base/share/classes/java/lang/invoke/InvokerBytecodeGenerator.java	Tue Nov 17 10:29:28 2015 -0800
@@ -750,7 +750,7 @@
         assert(!isLinkerMethodInvoke(name));  // should use the static path for these
         if (true) {
             // push receiver
-            MethodHandle target = name.function.resolvedHandle;
+            MethodHandle target = name.function.resolvedHandle();
             assert(target != null) : name.exprString();
             mv.visitLdcInsn(constantPlaceholder(target));
             emitReferenceCast(MethodHandle.class, target);
@@ -775,10 +775,19 @@
         // Sample classes from each package we are willing to bind to statically:
         java.lang.Object.class,
         java.util.Arrays.class,
-        sun.misc.Unsafe.class
+        jdk.internal.misc.Unsafe.class
         //MethodHandle.class already covered
     };
 
+    static boolean isStaticallyInvocable(NamedFunction[] functions) {
+        for (NamedFunction nf : functions) {
+            if (!isStaticallyInvocable(nf.member())) {
+                return false;
+            }
+        }
+        return true;
+    }
+
     static boolean isStaticallyInvocable(Name name) {
         return isStaticallyInvocable(name.function.member());
     }
@@ -881,7 +890,7 @@
             // The array will be a constant.
             Object emptyArray;
             try {
-                emptyArray = name.function.resolvedHandle.invoke();
+                emptyArray = name.function.resolvedHandle().invoke();
             } catch (Throwable ex) {
                 throw newInternalError(ex);
             }
@@ -1085,8 +1094,8 @@
         Label L_handler = new Label();
         Label L_done = new Label();
 
-        Class<?> returnType = result.function.resolvedHandle.type().returnType();
-        MethodType type = args.function.resolvedHandle.type()
+        Class<?> returnType = result.function.resolvedHandle().type().returnType();
+        MethodType type = args.function.resolvedHandle().type()
                               .dropParameterTypes(0,1)
                               .changeReturnType(returnType);
 
--- a/src/java.base/share/classes/java/lang/invoke/Invokers.java	Tue Nov 10 13:46:45 2015 +0300
+++ b/src/java.base/share/classes/java/lang/invoke/Invokers.java	Tue Nov 17 10:29:28 2015 -0800
@@ -429,11 +429,8 @@
                 NF_checkCustomized = new NamedFunction(Invokers.class
                         .getDeclaredMethod("checkCustomized", Object.class))
             };
-            for (NamedFunction nf : nfs) {
-                // Each nf must be statically invocable or we get tied up in our bootstraps.
-                assert(InvokerBytecodeGenerator.isStaticallyInvocable(nf.member)) : nf;
-                nf.resolve();
-            }
+            // Each nf must be statically invocable or we get tied up in our bootstraps.
+            assert(InvokerBytecodeGenerator.isStaticallyInvocable(nfs));
         } catch (ReflectiveOperationException ex) {
             throw newInternalError(ex);
         }
--- a/src/java.base/share/classes/java/lang/invoke/LambdaForm.java	Tue Nov 10 13:46:45 2015 +0300
+++ b/src/java.base/share/classes/java/lang/invoke/LambdaForm.java	Tue Nov 17 10:29:28 2015 -0800
@@ -1024,7 +1024,7 @@
 
     static class NamedFunction {
         final MemberName member;
-        @Stable MethodHandle resolvedHandle;
+        private @Stable MethodHandle resolvedHandle;
         @Stable MethodHandle invoker;
 
         NamedFunction(MethodHandle resolvedHandle) {
@@ -1074,8 +1074,10 @@
             return resolvedHandle;
         }
 
-        void resolve() {
-            resolvedHandle = DirectMethodHandle.make(member);
+        synchronized void resolve() {
+            if (resolvedHandle == null) {
+                resolvedHandle = DirectMethodHandle.make(member);
+            }
         }
 
         @Override
@@ -1235,6 +1237,7 @@
                     traceInterpreter("| getInvoker", this);
                     invoker();
                 }
+                // resolvedHandle might be uninitialized, ok for tracing
                 if (resolvedHandle == null) {
                     traceInterpreter("| resolve", this);
                     resolvedHandle();
@@ -1704,88 +1707,108 @@
     private static final MemberName.Factory IMPL_NAMES = MemberName.getFactory();
 
     static LambdaForm identityForm(BasicType type) {
-        return LF_identityForm[type.ordinal()];
+        int ord = type.ordinal();
+        LambdaForm form = LF_identity[ord];
+        if (form != null) {
+            return form;
+        }
+        createFormsFor(type);
+        return LF_identity[ord];
     }
+
     static LambdaForm zeroForm(BasicType type) {
-        return LF_zeroForm[type.ordinal()];
+        int ord = type.ordinal();
+        LambdaForm form = LF_zero[ord];
+        if (form != null) {
+            return form;
+        }
+        createFormsFor(type);
+        return LF_zero[ord];
     }
+
     static NamedFunction identity(BasicType type) {
-        return NF_identity[type.ordinal()];
+        int ord = type.ordinal();
+        NamedFunction function = NF_identity[ord];
+        if (function != null) {
+            return function;
+        }
+        createFormsFor(type);
+        return NF_identity[ord];
     }
+
     static NamedFunction constantZero(BasicType type) {
-        return NF_zero[type.ordinal()];
+        int ord = type.ordinal();
+        NamedFunction function = NF_zero[ord];
+        if (function != null) {
+            return function;
+        }
+        createFormsFor(type);
+        return NF_zero[ord];
     }
-    private static final LambdaForm[] LF_identityForm = new LambdaForm[TYPE_LIMIT];
-    private static final LambdaForm[] LF_zeroForm = new LambdaForm[TYPE_LIMIT];
-    private static final NamedFunction[] NF_identity = new NamedFunction[TYPE_LIMIT];
-    private static final NamedFunction[] NF_zero = new NamedFunction[TYPE_LIMIT];
-    private static void createIdentityForms() {
-        for (BasicType type : BasicType.ALL_TYPES) {
-            int ord = type.ordinal();
-            char btChar = type.basicTypeChar();
-            boolean isVoid = (type == V_TYPE);
-            Class<?> btClass = type.btClass;
-            MethodType zeType = MethodType.methodType(btClass);
-            MethodType idType = isVoid ? zeType : zeType.appendParameterTypes(btClass);
 
-            // Look up some symbolic names.  It might not be necessary to have these,
-            // but if we need to emit direct references to bytecodes, it helps.
-            // Zero is built from a call to an identity function with a constant zero input.
-            MemberName idMem = new MemberName(LambdaForm.class, "identity_"+btChar, idType, REF_invokeStatic);
-            MemberName zeMem = new MemberName(LambdaForm.class, "zero_"+btChar, zeType, REF_invokeStatic);
-            try {
+    private static final @Stable LambdaForm[] LF_identity = new LambdaForm[TYPE_LIMIT];
+    private static final @Stable LambdaForm[] LF_zero = new LambdaForm[TYPE_LIMIT];
+    private static final @Stable NamedFunction[] NF_identity = new NamedFunction[TYPE_LIMIT];
+    private static final @Stable NamedFunction[] NF_zero = new NamedFunction[TYPE_LIMIT];
+
+    private static synchronized void createFormsFor(BasicType type) {
+        final int ord = type.ordinal();
+        LambdaForm idForm = LF_identity[ord];
+        if (idForm != null) {
+            return;
+        }
+        char btChar = type.basicTypeChar();
+        boolean isVoid = (type == V_TYPE);
+        Class<?> btClass = type.btClass;
+        MethodType zeType = MethodType.methodType(btClass);
+        MethodType idType = (isVoid) ? zeType : zeType.appendParameterTypes(btClass);
+
+        // Look up symbolic names.  It might not be necessary to have these,
+        // but if we need to emit direct references to bytecodes, it helps.
+        // Zero is built from a call to an identity function with a constant zero input.
+        MemberName idMem = new MemberName(LambdaForm.class, "identity_"+btChar, idType, REF_invokeStatic);
+        MemberName zeMem = null;
+        try {
+            idMem = IMPL_NAMES.resolveOrFail(REF_invokeStatic, idMem, null, NoSuchMethodException.class);
+            if (!isVoid) {
+                zeMem = new MemberName(LambdaForm.class, "zero_"+btChar, zeType, REF_invokeStatic);
                 zeMem = IMPL_NAMES.resolveOrFail(REF_invokeStatic, zeMem, null, NoSuchMethodException.class);
-                idMem = IMPL_NAMES.resolveOrFail(REF_invokeStatic, idMem, null, NoSuchMethodException.class);
-            } catch (IllegalAccessException|NoSuchMethodException ex) {
-                throw newInternalError(ex);
             }
-
-            NamedFunction idFun = new NamedFunction(idMem);
-            LambdaForm idForm;
-            if (isVoid) {
-                Name[] idNames = new Name[] { argument(0, L_TYPE) };
-                idForm = new LambdaForm(idMem.getName(), 1, idNames, VOID_RESULT);
-            } else {
-                Name[] idNames = new Name[] { argument(0, L_TYPE), argument(1, type) };
-                idForm = new LambdaForm(idMem.getName(), 2, idNames, 1);
-            }
-            LF_identityForm[ord] = idForm;
-            NF_identity[ord] = idFun;
-
-            NamedFunction zeFun = new NamedFunction(zeMem);
-            LambdaForm zeForm;
-            if (isVoid) {
-                zeForm = idForm;
-            } else {
-                Object zeValue = Wrapper.forBasicType(btChar).zero();
-                Name[] zeNames = new Name[] { argument(0, L_TYPE), new Name(idFun, zeValue) };
-                zeForm = new LambdaForm(zeMem.getName(), 1, zeNames, 1);
-            }
-            LF_zeroForm[ord] = zeForm;
-            NF_zero[ord] = zeFun;
-
-            assert(idFun.isIdentity());
-            assert(zeFun.isConstantZero());
-            assert(new Name(zeFun).isConstantZero());
+        } catch (IllegalAccessException|NoSuchMethodException ex) {
+            throw newInternalError(ex);
         }
 
-        // Do this in a separate pass, so that SimpleMethodHandle.make can see the tables.
-        for (BasicType type : BasicType.ALL_TYPES) {
-            int ord = type.ordinal();
-            NamedFunction idFun = NF_identity[ord];
-            LambdaForm idForm = LF_identityForm[ord];
-            MemberName idMem = idFun.member;
-            idFun.resolvedHandle = SimpleMethodHandle.make(idMem.getInvocationType(), idForm);
+        NamedFunction idFun;
+        LambdaForm zeForm;
+        NamedFunction zeFun;
+        if (isVoid) {
+            Name[] idNames = new Name[] { argument(0, L_TYPE) };
+            idForm = new LambdaForm(idMem.getName(), 1, idNames, VOID_RESULT);
+            idFun = new NamedFunction(idMem, SimpleMethodHandle.make(idMem.getInvocationType(), idForm));
 
-            NamedFunction zeFun = NF_zero[ord];
-            LambdaForm zeForm = LF_zeroForm[ord];
-            MemberName zeMem = zeFun.member;
-            zeFun.resolvedHandle = SimpleMethodHandle.make(zeMem.getInvocationType(), zeForm);
+            assert(zeMem == null);
+            zeForm = idForm;
+            zeFun = idFun;
+        } else {
+            Name[] idNames = new Name[] { argument(0, L_TYPE), argument(1, type) };
+            idForm = new LambdaForm(idMem.getName(), 2, idNames, 1);
+            idFun = new NamedFunction(idMem, SimpleMethodHandle.make(idMem.getInvocationType(), idForm));
 
-            assert(idFun.isIdentity());
-            assert(zeFun.isConstantZero());
-            assert(new Name(zeFun).isConstantZero());
+            assert(zeMem != null);
+            Object zeValue = Wrapper.forBasicType(btChar).zero();
+            Name[] zeNames = new Name[] { argument(0, L_TYPE), new Name(idFun, zeValue) };
+            zeForm = new LambdaForm(zeMem.getName(), 1, zeNames, 1);
+            zeFun = new NamedFunction(zeMem, SimpleMethodHandle.make(zeMem.getInvocationType(), zeForm));
         }
+
+        LF_zero[ord] = zeForm;
+        NF_zero[ord] = zeFun;
+        LF_identity[ord] = idForm;
+        NF_identity[ord] = idFun;
+
+        assert(idFun.isIdentity());
+        assert(zeFun.isConstantZero());
+        assert(new Name(zeFun).isConstantZero());
     }
 
     // Avoid appealing to ValueConversions at bootstrap time:
@@ -1794,13 +1817,12 @@
     private static float identity_F(float x) { return x; }
     private static double identity_D(double x) { return x; }
     private static Object identity_L(Object x) { return x; }
-    private static void identity_V() { return; }  // same as zeroV, but that's OK
+    private static void identity_V() { return; }
     private static int zero_I() { return 0; }
     private static long zero_J() { return 0; }
     private static float zero_F() { return 0; }
     private static double zero_D() { return 0; }
     private static Object zero_L() { return null; }
-    private static void zero_V() { return; }
 
     /**
      * Internal marker for byte-compiled LambdaForms.
@@ -1830,7 +1852,6 @@
 
     // Put this last, so that previous static inits can run before.
     static {
-        createIdentityForms();
         if (USE_PREDEFINED_INTERPRET_METHODS)
             computeInitialPreparedForms();
         NamedFunction.initializeInvokers();
--- a/src/java.base/share/classes/java/lang/invoke/LambdaFormEditor.java	Tue Nov 10 13:46:45 2015 +0300
+++ b/src/java.base/share/classes/java/lang/invoke/LambdaFormEditor.java	Tue Nov 17 10:29:28 2015 -0800
@@ -541,7 +541,7 @@
         assert(pos > 0);  // cannot spread the MH arg itself
 
         Name spreadParam = new Name(L_TYPE);
-        Name checkSpread = new Name(MethodHandleImpl.Lazy.NF_checkSpreadArgument, spreadParam, arrayLength);
+        Name checkSpread = new Name(MethodHandleImpl.NF_checkSpreadArgument, spreadParam, arrayLength);
 
         // insert the new expressions
         int exprPos = lambdaForm.arity();
--- a/src/java.base/share/classes/java/lang/invoke/MethodHandleImpl.java	Tue Nov 10 13:46:45 2015 +0300
+++ b/src/java.base/share/classes/java/lang/invoke/MethodHandleImpl.java	Tue Nov 17 10:29:28 2015 -0800
@@ -219,7 +219,7 @@
             if (convSpec == null)  continue;
             MethodHandle fn;
             if (convSpec instanceof Class) {
-                fn = Lazy.MH_cast.bindTo(convSpec);
+                fn = getConstantHandle(MH_cast).bindTo(convSpec);
             } else {
                 fn = (MethodHandle) convSpec;
             }
@@ -239,7 +239,7 @@
                 if (convSpec == void.class)
                     fn = null;
                 else
-                    fn = Lazy.MH_cast.bindTo(convSpec);
+                    fn = getConstantHandle(MH_cast).bindTo(convSpec);
             } else {
                 fn = (MethodHandle) convSpec;
             }
@@ -302,7 +302,7 @@
             Name conv;
             if (convSpec instanceof Class) {
                 Class<?> convClass = (Class<?>) convSpec;
-                conv = new Name(Lazy.MH_cast, convClass, names[INARG_BASE + i]);
+                conv = new Name(getConstantHandle(MH_cast), convClass, names[INARG_BASE + i]);
             } else {
                 MethodHandle fn = (MethodHandle) convSpec;
                 conv = new Name(fn, names[INARG_BASE + i]);
@@ -326,7 +326,7 @@
                 conv = new Name(LambdaForm.constantZero(BasicType.basicType(srcType.returnType())));
             } else if (convSpec instanceof Class) {
                 Class<?> convClass = (Class<?>) convSpec;
-                conv = new Name(Lazy.MH_cast, convClass, names[OUT_CALL]);
+                conv = new Name(getConstantHandle(MH_cast), convClass, names[OUT_CALL]);
             } else {
                 MethodHandle fn = (MethodHandle) convSpec;
                 if (fn.type().parameterCount() == 0)
@@ -529,7 +529,7 @@
                 // Spread the array.
                 MethodHandle aload = MethodHandles.arrayElementGetter(spreadArgType);
                 Name array = names[argIndex];
-                names[nameCursor++] = new Name(Lazy.NF_checkSpreadArgument, array, spreadArgCount);
+                names[nameCursor++] = new Name(NF_checkSpreadArgument, array, spreadArgCount);
                 for (int j = 0; j < spreadArgCount; i++, j++) {
                     indexes[i] = nameCursor;
                     names[nameCursor++] = new Name(aload, array, j);
@@ -566,66 +566,6 @@
         throw newIllegalArgumentException("array is not of length "+n);
     }
 
-    /**
-     * Pre-initialized NamedFunctions for bootstrapping purposes.
-     * Factored in an inner class to delay initialization until first usage.
-     */
-    static class Lazy {
-        private static final Class<?> MHI = MethodHandleImpl.class;
-        private static final Class<?> CLS = Class.class;
-
-        private static final MethodHandle[] ARRAYS;
-        private static final MethodHandle[] FILL_ARRAYS;
-
-        static final NamedFunction NF_checkSpreadArgument;
-        static final NamedFunction NF_guardWithCatch;
-        static final NamedFunction NF_throwException;
-        static final NamedFunction NF_profileBoolean;
-
-        static final MethodHandle MH_cast;
-        static final MethodHandle MH_selectAlternative;
-        static final MethodHandle MH_copyAsPrimitiveArray;
-        static final MethodHandle MH_fillNewTypedArray;
-        static final MethodHandle MH_fillNewArray;
-        static final MethodHandle MH_arrayIdentity;
-
-        static {
-            ARRAYS      = makeArrays();
-            FILL_ARRAYS = makeFillArrays();
-
-            try {
-                NF_checkSpreadArgument = new NamedFunction(MHI.getDeclaredMethod("checkSpreadArgument", Object.class, int.class));
-                NF_guardWithCatch      = new NamedFunction(MHI.getDeclaredMethod("guardWithCatch", MethodHandle.class, Class.class,
-                                                                                 MethodHandle.class, Object[].class));
-                NF_throwException      = new NamedFunction(MHI.getDeclaredMethod("throwException", Throwable.class));
-                NF_profileBoolean      = new NamedFunction(MHI.getDeclaredMethod("profileBoolean", boolean.class, int[].class));
-
-                NF_checkSpreadArgument.resolve();
-                NF_guardWithCatch.resolve();
-                NF_throwException.resolve();
-                NF_profileBoolean.resolve();
-
-                MH_cast                 = IMPL_LOOKUP.findVirtual(CLS, "cast",
-                                            MethodType.methodType(Object.class, Object.class));
-                MH_copyAsPrimitiveArray = IMPL_LOOKUP.findStatic(MHI, "copyAsPrimitiveArray",
-                                            MethodType.methodType(Object.class, Wrapper.class, Object[].class));
-                MH_arrayIdentity        = IMPL_LOOKUP.findStatic(MHI, "identity",
-                                            MethodType.methodType(Object[].class, Object[].class));
-                MH_fillNewArray         = IMPL_LOOKUP.findStatic(MHI, "fillNewArray",
-                                            MethodType.methodType(Object[].class, Integer.class, Object[].class));
-                MH_fillNewTypedArray    = IMPL_LOOKUP.findStatic(MHI, "fillNewTypedArray",
-                                            MethodType.methodType(Object[].class, Object[].class, Integer.class, Object[].class));
-
-                MH_selectAlternative    = makeIntrinsic(
-                        IMPL_LOOKUP.findStatic(MHI, "selectAlternative",
-                                MethodType.methodType(MethodHandle.class, boolean.class, MethodHandle.class, MethodHandle.class)),
-                        Intrinsic.SELECT_ALTERNATIVE);
-            } catch (ReflectiveOperationException ex) {
-                throw newInternalError(ex);
-            }
-        }
-    }
-
     /** Factory method:  Collect or filter selected argument(s). */
     static MethodHandle makeCollectArguments(MethodHandle target,
                 MethodHandle collector, int collectArgPos, boolean retainOriginalArgs) {
@@ -911,10 +851,10 @@
 
         // profile branch
         if (PROFILE != -1) {
-            names[PROFILE] = new Name(Lazy.NF_profileBoolean, names[CALL_TEST], names[GET_COUNTERS]);
+            names[PROFILE] = new Name(NF_profileBoolean, names[CALL_TEST], names[GET_COUNTERS]);
         }
         // call selectAlternative
-        names[SELECT_ALT] = new Name(Lazy.MH_selectAlternative, names[TEST], names[GET_TARGET], names[GET_FALLBACK]);
+        names[SELECT_ALT] = new Name(getConstantHandle(MH_selectAlternative), names[TEST], names[GET_TARGET], names[GET_FALLBACK]);
 
         // call target or fallback
         invokeArgs[0] = names[SELECT_ALT];
@@ -989,7 +929,7 @@
 
         // t_{i+1}:L=MethodHandleImpl.guardWithCatch(target:L,exType:L,catcher:L,t_{i}:L);
         Object[] gwcArgs = new Object[] {names[GET_TARGET], names[GET_CLASS], names[GET_CATCHER], names[BOXED_ARGS]};
-        names[TRY_CATCH] = new Name(Lazy.NF_guardWithCatch, gwcArgs);
+        names[TRY_CATCH] = new Name(NF_guardWithCatch, gwcArgs);
 
         // t_{i+2}:I=MethodHandle.invokeBasic(unbox:L,t_{i+1}:L);
         MethodHandle invokeBasicUnbox = MethodHandles.basicInvoker(MethodType.methodType(basicType.rtype(), Object.class));
@@ -1073,7 +1013,7 @@
             mh = MethodHandles.dropArguments(mh, 1, type.parameterList().subList(1, arity));
             return mh;
         }
-        return makePairwiseConvert(Lazy.NF_throwException.resolvedHandle(), type, false, true);
+        return makePairwiseConvert(NF_throwException.resolvedHandle(), type, false, true);
     }
 
     static <T extends Throwable> Empty throwException(T t) throws T { throw t; }
@@ -1421,25 +1361,7 @@
                 { return makeArray(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9); }
 
     private static final int ARRAYS_COUNT = 11;
-
-    private static MethodHandle[] makeArrays() {
-        MethodHandle[] mhs = new MethodHandle[MAX_ARITY + 1];
-        for (int i = 0; i < ARRAYS_COUNT; i++) {
-            MethodHandle mh = findCollector("array", i, Object[].class);
-            mh = makeIntrinsic(mh, Intrinsic.NEW_ARRAY);
-            mhs[i] = mh;
-        }
-        assert(assertArrayMethodCount(mhs));
-        return mhs;
-    }
-
-    private static boolean assertArrayMethodCount(MethodHandle[] mhs) {
-        assert(findCollector("array", ARRAYS_COUNT, Object[].class) == null);
-        for (int i = 0; i < ARRAYS_COUNT; i++) {
-            assert(mhs[i] != null);
-        }
-        return true;
-    }
+    private static final @Stable MethodHandle[] ARRAYS = new MethodHandle[MAX_ARITY + 1];
 
     // filling versions of the above:
     // using Integer len instead of int len and no varargs to avoid bootstrapping problems
@@ -1488,24 +1410,17 @@
                 { fillWithArguments(a, pos, a0, a1, a2, a3, a4, a5, a6, a7, a8, a9); return a; }
 
     private static final int FILL_ARRAYS_COUNT = 11; // current number of fillArray methods
+    private static final @Stable MethodHandle[] FILL_ARRAYS = new MethodHandle[FILL_ARRAYS_COUNT];
 
-    private static MethodHandle[] makeFillArrays() {
-        MethodHandle[] mhs = new MethodHandle[FILL_ARRAYS_COUNT];
-        mhs[0] = null;  // there is no empty fill; at least a0 is required
-        for (int i = 1; i < FILL_ARRAYS_COUNT; i++) {
-            MethodHandle mh = findCollector("fillArray", i, Object[].class, Integer.class, Object[].class);
-            mhs[i] = mh;
+    private static MethodHandle getFillArray(int count) {
+        assert (count > 0 && count < FILL_ARRAYS_COUNT);
+        MethodHandle mh = FILL_ARRAYS[count];
+        if (mh != null) {
+            return mh;
         }
-        assert(assertFillArrayMethodCount(mhs));
-        return mhs;
-    }
-
-    private static boolean assertFillArrayMethodCount(MethodHandle[] mhs) {
-        assert(findCollector("fillArray", FILL_ARRAYS_COUNT, Object[].class, Integer.class, Object[].class) == null);
-        for (int i = 1; i < FILL_ARRAYS_COUNT; i++) {
-            assert(mhs[i] != null);
-        }
-        return true;
+        mh = findCollector("fillArray", count, Object[].class, Integer.class, Object[].class);
+        FILL_ARRAYS[count] = mh;
+        return mh;
     }
 
     private static Object copyAsPrimitiveArray(Wrapper w, Object... boxes) {
@@ -1518,12 +1433,19 @@
      *  arguments and returns an Object array of them, as if for varargs.
      */
     static MethodHandle varargsArray(int nargs) {
-        MethodHandle mh = Lazy.ARRAYS[nargs];
-        if (mh != null)  return mh;
-        mh = buildVarargsArray(Lazy.MH_fillNewArray, Lazy.MH_arrayIdentity, nargs);
+        MethodHandle mh = ARRAYS[nargs];
+        if (mh != null) {
+            return mh;
+        }
+        if (nargs < ARRAYS_COUNT) {
+            mh = findCollector("array", nargs, Object[].class);
+        } else {
+            mh = buildVarargsArray(getConstantHandle(MH_fillNewArray),
+                    getConstantHandle(MH_arrayIdentity), nargs);
+        }
         assert(assertCorrectArity(mh, nargs));
         mh = makeIntrinsic(mh, Intrinsic.NEW_ARRAY);
-        return Lazy.ARRAYS[nargs] = mh;
+        return ARRAYS[nargs] = mh;
     }
 
     private static boolean assertCorrectArity(MethodHandle mh, int arity) {
@@ -1531,7 +1453,7 @@
         return true;
     }
 
-    // Array identity function (used as Lazy.MH_arrayIdentity).
+    // Array identity function (used as getConstantHandle(MH_arrayIdentity)).
     static <T> T[] identity(T[] x) {
         return x;
     }
@@ -1547,12 +1469,12 @@
         MethodHandle mh = finisher;
         if (rightLen > 0) {
             MethodHandle rightFiller = fillToRight(LEFT_ARGS + rightLen);
-            if (mh == Lazy.MH_arrayIdentity)
+            if (mh.equals(getConstantHandle(MH_arrayIdentity)))
                 mh = rightFiller;
             else
                 mh = MethodHandles.collectArguments(mh, 0, rightFiller);
         }
-        if (mh == Lazy.MH_arrayIdentity)
+        if (mh.equals(getConstantHandle(MH_arrayIdentity)))
             mh = leftCollector;
         else
             mh = MethodHandles.collectArguments(mh, 0, leftCollector);
@@ -1560,7 +1482,7 @@
     }
 
     private static final int LEFT_ARGS = FILL_ARRAYS_COUNT - 1;
-    private static final MethodHandle[] FILL_ARRAY_TO_RIGHT = new MethodHandle[MAX_ARITY+1];
+    private static final @Stable MethodHandle[] FILL_ARRAY_TO_RIGHT = new MethodHandle[MAX_ARITY+1];
     /** fill_array_to_right(N).invoke(a, argL..arg[N-1])
      *  fills a[L]..a[N-1] with corresponding arguments,
      *  and then returns a.  The value L is a global constant (LEFT_ARGS).
@@ -1574,7 +1496,7 @@
     }
     private static MethodHandle buildFiller(int nargs) {
         if (nargs <= LEFT_ARGS)
-            return Lazy.MH_arrayIdentity;  // no args to fill; return the array unchanged
+            return getConstantHandle(MH_arrayIdentity);  // no args to fill; return the array unchanged
         // we need room for both mh and a in mh.invoke(a, arg*[nargs])
         final int CHUNK = LEFT_ARGS;
         int rightLen = nargs % CHUNK;
@@ -1590,7 +1512,7 @@
         if (midLen < LEFT_ARGS) rightLen = nargs - (midLen = LEFT_ARGS);
         assert(rightLen > 0);
         MethodHandle midFill = fillToRight(midLen);  // recursive fill
-        MethodHandle rightFill = Lazy.FILL_ARRAYS[rightLen].bindTo(midLen);  // [midLen..nargs-1]
+        MethodHandle rightFill = getFillArray(rightLen).bindTo(midLen);  // [midLen..nargs-1]
         assert(midFill.type().parameterCount()   == 1 + midLen - LEFT_ARGS);
         assert(rightFill.type().parameterCount() == 1 + rightLen);
 
@@ -1641,14 +1563,14 @@
             Object example = java.lang.reflect.Array.newInstance(arrayType.getComponentType(), 0);
             mh = MethodHandles.constant(arrayType, example);
         } else if (elemType.isPrimitive()) {
-            MethodHandle builder = Lazy.MH_fillNewArray;
+            MethodHandle builder = getConstantHandle(MH_fillNewArray);
             MethodHandle producer = buildArrayProducer(arrayType);
             mh = buildVarargsArray(builder, producer, nargs);
         } else {
             Class<? extends Object[]> objArrayType = arrayType.asSubclass(Object[].class);
             Object[] example = Arrays.copyOf(NO_ARGS_ARRAY, 0, objArrayType);
-            MethodHandle builder = Lazy.MH_fillNewTypedArray.bindTo(example);
-            MethodHandle producer = Lazy.MH_arrayIdentity; // must be weakly typed
+            MethodHandle builder = getConstantHandle(MH_fillNewTypedArray).bindTo(example);
+            MethodHandle producer = getConstantHandle(MH_arrayIdentity); // must be weakly typed
             mh = buildVarargsArray(builder, producer, nargs);
         }
         mh = mh.asType(MethodType.methodType(arrayType, Collections.<Class<?>>nCopies(nargs, elemType)));
@@ -1662,7 +1584,7 @@
     private static MethodHandle buildArrayProducer(Class<?> arrayType) {
         Class<?> elemType = arrayType.getComponentType();
         assert(elemType.isPrimitive());
-        return Lazy.MH_copyAsPrimitiveArray.bindTo(Wrapper.forPrimitiveType(elemType));
+        return getConstantHandle(MH_copyAsPrimitiveArray).bindTo(Wrapper.forPrimitiveType(elemType));
     }
 
     /*non-public*/ static void assertSame(Object mh1, Object mh2) {
@@ -1673,4 +1595,87 @@
             throw newInternalError(msg);
         }
     }
+
+    // Local constant functions:
+    /*non-public*/ static final NamedFunction
+        NF_checkSpreadArgument,
+        NF_guardWithCatch,
+        NF_throwException,
+        NF_profileBoolean;
+
+    static {
+        try {
+            NF_checkSpreadArgument = new NamedFunction(MethodHandleImpl.class
+                    .getDeclaredMethod("checkSpreadArgument", Object.class, int.class));
+            NF_guardWithCatch = new NamedFunction(MethodHandleImpl.class
+                    .getDeclaredMethod("guardWithCatch", MethodHandle.class, Class.class,
+                            MethodHandle.class, Object[].class));
+            NF_throwException = new NamedFunction(MethodHandleImpl.class
+                    .getDeclaredMethod("throwException", Throwable.class));
+            NF_profileBoolean = new NamedFunction(MethodHandleImpl.class
+                    .getDeclaredMethod("profileBoolean", boolean.class, int[].class));
+        } catch (ReflectiveOperationException ex) {
+            throw newInternalError(ex);
+        }
+    }
+
+    // Indexes into constant method handles:
+    private static final int
+            MH_cast                  =  0,
+            MH_selectAlternative     =  1,
+            MH_copyAsPrimitiveArray  =  2,
+            MH_fillNewTypedArray     =  3,
+            MH_fillNewArray          =  4,
+            MH_arrayIdentity         =  5,
+            MH_LIMIT                 =  6;
+
+    private static MethodHandle getConstantHandle(int idx) {
+        MethodHandle handle = HANDLES[idx];
+        if (handle != null) {
+            return handle;
+        }
+        return setCachedHandle(idx, makeConstantHandle(idx));
+    }
+
+    private static synchronized MethodHandle setCachedHandle(int idx, final MethodHandle method) {
+        // Simulate a CAS, to avoid racy duplication of results.
+        MethodHandle prev = HANDLES[idx];
+        if (prev != null) {
+            return prev;
+        }
+        HANDLES[idx] = method;
+        return method;
+    }
+
+    // Local constant method handles:
+    private static final @Stable MethodHandle[] HANDLES = new MethodHandle[MH_LIMIT];
+
+    private static MethodHandle makeConstantHandle(int idx) {
+        try {
+            switch (idx) {
+                case MH_cast:
+                    return IMPL_LOOKUP.findVirtual(Class.class, "cast",
+                            MethodType.methodType(Object.class, Object.class));
+                case MH_copyAsPrimitiveArray:
+                    return IMPL_LOOKUP.findStatic(MethodHandleImpl.class, "copyAsPrimitiveArray",
+                            MethodType.methodType(Object.class, Wrapper.class, Object[].class));
+                case MH_arrayIdentity:
+                    return IMPL_LOOKUP.findStatic(MethodHandleImpl.class, "identity",
+                            MethodType.methodType(Object[].class, Object[].class));
+                case MH_fillNewArray:
+                    return IMPL_LOOKUP.findStatic(MethodHandleImpl.class, "fillNewArray",
+                            MethodType.methodType(Object[].class, Integer.class, Object[].class));
+                case MH_fillNewTypedArray:
+                    return IMPL_LOOKUP.findStatic(MethodHandleImpl.class, "fillNewTypedArray",
+                            MethodType.methodType(Object[].class, Object[].class, Integer.class, Object[].class));
+                case MH_selectAlternative:
+                    return makeIntrinsic(IMPL_LOOKUP.findStatic(MethodHandleImpl.class, "selectAlternative",
+                            MethodType.methodType(MethodHandle.class, boolean.class, MethodHandle.class, MethodHandle.class)),
+                        Intrinsic.SELECT_ALTERNATIVE);
+            }
+        } catch (ReflectiveOperationException ex) {
+            throw newInternalError(ex);
+        }
+        throw newInternalError("Unknown function index: " + idx);
+    }
 }
--- a/src/java.base/share/classes/java/lang/invoke/MethodHandleNatives.java	Tue Nov 10 13:46:45 2015 +0300
+++ b/src/java.base/share/classes/java/lang/invoke/MethodHandleNatives.java	Tue Nov 17 10:29:28 2015 -0800
@@ -50,7 +50,7 @@
     static native int getMembers(Class<?> defc, String matchName, String matchSig,
             int matchFlags, Class<?> caller, int skip, MemberName[] results);
 
-    /// Field layout queries parallel to sun.misc.Unsafe:
+    /// Field layout queries parallel to jdk.internal.misc.Unsafe:
     static native long objectFieldOffset(MemberName self);  // e.g., returns vmindex
     static native long staticFieldOffset(MemberName self);  // e.g., returns vmindex
     static native Object staticFieldBase(MemberName self);  // e.g., returns clazz
--- a/src/java.base/share/classes/java/lang/invoke/MethodHandleStatics.java	Tue Nov 10 13:46:45 2015 +0300
+++ b/src/java.base/share/classes/java/lang/invoke/MethodHandleStatics.java	Tue Nov 17 10:29:28 2015 -0800
@@ -27,7 +27,7 @@
 
 import java.security.AccessController;
 import java.security.PrivilegedAction;
-import sun.misc.Unsafe;
+import jdk.internal.misc.Unsafe;
 
 /**
  * This class consists exclusively of static names internal to the
--- a/src/java.base/share/classes/java/math/BigDecimal.java	Tue Nov 10 13:46:45 2015 +0300
+++ b/src/java.base/share/classes/java/math/BigDecimal.java	Tue Nov 17 10:29:28 2015 -0800
@@ -3726,12 +3726,12 @@
     }
 
     private static class UnsafeHolder {
-        private static final sun.misc.Unsafe unsafe;
+        private static final jdk.internal.misc.Unsafe unsafe;
         private static final long intCompactOffset;
         private static final long intValOffset;
         static {
             try {
-                unsafe = sun.misc.Unsafe.getUnsafe();
+                unsafe = jdk.internal.misc.Unsafe.getUnsafe();
                 intCompactOffset = unsafe.objectFieldOffset
                     (BigDecimal.class.getDeclaredField("intCompact"));
                 intValOffset = unsafe.objectFieldOffset
--- a/src/java.base/share/classes/java/math/BigInteger.java	Tue Nov 10 13:46:45 2015 +0300
+++ b/src/java.base/share/classes/java/math/BigInteger.java	Tue Nov 17 10:29:28 2015 -0800
@@ -4526,12 +4526,12 @@
 
     // Support for resetting final fields while deserializing
     private static class UnsafeHolder {
-        private static final sun.misc.Unsafe unsafe;
+        private static final jdk.internal.misc.Unsafe unsafe;
         private static final long signumOffset;
         private static final long magOffset;
         static {
             try {
-                unsafe = sun.misc.Unsafe.getUnsafe();
+                unsafe = jdk.internal.misc.Unsafe.getUnsafe();
                 signumOffset = unsafe.objectFieldOffset
                     (BigInteger.class.getDeclaredField("signum"));
                 magOffset = unsafe.objectFieldOffset
--- a/src/java.base/share/classes/java/net/Inet6Address.java	Tue Nov 10 13:46:45 2015 +0300
+++ b/src/java.base/share/classes/java/net/Inet6Address.java	Tue Nov 17 10:29:28 2015 -0800
@@ -576,11 +576,11 @@
     };
 
     private static final long FIELDS_OFFSET;
-    private static final sun.misc.Unsafe UNSAFE;
+    private static final jdk.internal.misc.Unsafe UNSAFE;
 
     static {
         try {
-            sun.misc.Unsafe unsafe = sun.misc.Unsafe.getUnsafe();
+            jdk.internal.misc.Unsafe unsafe = jdk.internal.misc.Unsafe.getUnsafe();
             FIELDS_OFFSET = unsafe.objectFieldOffset(
                     Inet6Address.class.getDeclaredField("holder6"));
             UNSAFE = unsafe;
--- a/src/java.base/share/classes/java/net/InetAddress.java	Tue Nov 10 13:46:45 2015 +0300
+++ b/src/java.base/share/classes/java/net/InetAddress.java	Tue Nov 17 10:29:28 2015 -0800
@@ -29,6 +29,7 @@
 import java.util.Iterator;
 import java.util.List;
 import java.util.ArrayList;
+import java.util.Objects;
 import java.util.ServiceLoader;
 import java.security.AccessController;
 import java.io.ObjectStreamException;
@@ -733,7 +734,7 @@
      */
     public String toString() {
         String hostName = holder().getHostName();
-        return ((hostName != null) ? hostName : "")
+        return Objects.toString(hostName, "")
             + "/" + getHostAddress();
     }
 
@@ -1493,11 +1494,11 @@
     }
 
     private static final long FIELDS_OFFSET;
-    private static final sun.misc.Unsafe UNSAFE;
+    private static final jdk.internal.misc.Unsafe UNSAFE;
 
     static {
         try {
-            sun.misc.Unsafe unsafe = sun.misc.Unsafe.getUnsafe();
+            jdk.internal.misc.Unsafe unsafe = jdk.internal.misc.Unsafe.getUnsafe();
             FIELDS_OFFSET = unsafe.objectFieldOffset(
                 InetAddress.class.getDeclaredField("holder")
             );
--- a/src/java.base/share/classes/java/net/InetSocketAddress.java	Tue Nov 10 13:46:45 2015 +0300
+++ b/src/java.base/share/classes/java/net/InetSocketAddress.java	Tue Nov 17 10:29:28 2015 -0800
@@ -303,10 +303,10 @@
     }
 
     private static final long FIELDS_OFFSET;
-    private static final sun.misc.Unsafe UNSAFE;
+    private static final jdk.internal.misc.Unsafe UNSAFE;
     static {
         try {
-            sun.misc.Unsafe unsafe = sun.misc.Unsafe.getUnsafe();
+            jdk.internal.misc.Unsafe unsafe = jdk.internal.misc.Unsafe.getUnsafe();
             FIELDS_OFFSET = unsafe.objectFieldOffset(
                     InetSocketAddress.class.getDeclaredField("holder"));
             UNSAFE = unsafe;
--- a/src/java.base/share/classes/java/net/SocketOptions.java	Tue Nov 10 13:46:45 2015 +0300
+++ b/src/java.base/share/classes/java/net/SocketOptions.java	Tue Nov 17 10:29:28 2015 -0800
@@ -61,21 +61,21 @@
      * If the requested option is binary, it can be set using this method by
      * a java.lang.Boolean:
      * <BR><PRE>
-     * s.setOption(TCP_NODELAY, new Boolean(true));
+     * s.setOption(TCP_NODELAY, Boolean.TRUE);
      *    // OK - enables TCP_NODELAY, a binary option
      * </PRE>
      * <BR>
-     * Any option can be disabled using this method with a Boolean(false):
+     * Any option can be disabled using this method with a Boolean.FALSE:
      * <BR><PRE>
-     * s.setOption(TCP_NODELAY, new Boolean(false));
+     * s.setOption(TCP_NODELAY, Boolean.FALSE);
      *    // OK - disables TCP_NODELAY
-     * s.setOption(SO_LINGER, new Boolean(false));
+     * s.setOption(SO_LINGER, Boolean.FALSE);
      *    // OK - disables SO_LINGER
      * </PRE>
      * <BR>
      * For an option that has a notion of on and off, and requires
      * a non-boolean parameter, setting its value to anything other than
-     * <I>Boolean(false)</I> implicitly enables it.
+     * <I>Boolean.FALSE</I> implicitly enables it.
      * <BR>
      * Throws SocketException if the option is unrecognized,
      * the socket is closed, or some low-level error occurred
@@ -91,8 +91,8 @@
 
     /**
      * Fetch the value of an option.
-     * Binary options will return java.lang.Boolean(true)
-     * if enabled, java.lang.Boolean(false) if disabled, e.g.:
+     * Binary options will return java.lang.Boolean.TRUE
+     * if enabled, java.lang.Boolean.FALSE if disabled, e.g.:
      * <BR><PRE>
      * SocketImpl s;
      * ...
@@ -105,13 +105,13 @@
      * <P>
      * For options that take a particular type as a parameter,
      * getOption(int) will return the parameter's value, else
-     * it will return java.lang.Boolean(false):
+     * it will return java.lang.Boolean.FALSE:
      * <PRE>
      * Object o = s.getOption(SO_LINGER);
      * if (o instanceof Integer) {
      *     System.out.print("Linger time is " + ((Integer)o).intValue());
      * } else {
-     *   // the true type of o is java.lang.Boolean(false);
+     *   // the true type of o is java.lang.Boolean.FALSE;
      * }
      * </PRE>
      *
--- a/src/java.base/share/classes/java/net/URLConnection.java	Tue Nov 10 13:46:45 2015 +0300
+++ b/src/java.base/share/classes/java/net/URLConnection.java	Tue Nov 17 10:29:28 2015 -0800
@@ -32,6 +32,7 @@
 import java.util.Hashtable;
 import java.util.Date;
 import java.util.Iterator;
+import java.util.Objects;
 import java.util.ServiceConfigurationError;
 import java.util.ServiceLoader;
 import java.util.StringTokenizer;
@@ -1250,7 +1251,7 @@
 
         if (handler != null) {
             ContentHandler h = handlers.putIfAbsent(contentType, handler);
-            return h != null ? h : handler;
+            return Objects.requireNonNullElse(h, handler);
         }
 
         try {
@@ -1263,7 +1264,7 @@
         assert handler != null;
 
         ContentHandler h = handlers.putIfAbsent(contentType, handler);
-        return h != null ? h : handler;
+        return Objects.requireNonNullElse(h, handler);
     }
 
     /*
--- a/src/java.base/share/classes/java/nio/Bits.java	Tue Nov 10 13:46:45 2015 +0300
+++ b/src/java.base/share/classes/java/nio/Bits.java	Tue Nov 17 10:29:28 2015 -0800
@@ -32,7 +32,7 @@
 import jdk.internal.misc.JavaNioAccess;
 import jdk.internal.misc.JavaLangRefAccess;
 import jdk.internal.misc.SharedSecrets;
-import sun.misc.Unsafe;
+import jdk.internal.misc.Unsafe;
 import sun.misc.VM;