Merge
authorprr
Fri, 16 Feb 2018 13:49:07 -0800
changeset 49091 0fa50be70f7a
parent 49090 82c1fe23c469 (current diff)
parent 48909 54b423e1c4cf (diff)
child 49092 6dc5e0cdb44c
Merge
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.sparc.test/src/org/graalvm/compiler/core/sparc/test/SPARCAllocatorTest.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/ArrayRangeWriteNode.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.graphio/src/org/graalvm/graphio/GraphSnippets.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.util.test/src/org/graalvm/util/test/CollectionTest.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.util/src/org/graalvm/util/EconomicMap.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.util/src/org/graalvm/util/EconomicSet.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.util/src/org/graalvm/util/Equivalence.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.util/src/org/graalvm/util/MapCursor.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.util/src/org/graalvm/util/Pair.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.util/src/org/graalvm/util/UnmodifiableEconomicMap.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.util/src/org/graalvm/util/UnmodifiableEconomicSet.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.util/src/org/graalvm/util/UnmodifiableMapCursor.java
src/jdk.internal.vm.compiler/share/classes/org.graalvm.util/src/org/graalvm/util/impl/EconomicMapImpl.java
test/jdk/sun/security/tools/jarsigner/warnings/bad_netscape_cert_type.jks.base64
test/jdk/sun/security/tools/jarsigner/warnings/bad_netscape_cert_type.sh
--- a/.hgtags	Fri Feb 16 12:24:38 2018 -0800
+++ b/.hgtags	Fri Feb 16 13:49:07 2018 -0800
@@ -469,3 +469,4 @@
 3eae36c6baa5f916a3024cf1513e22357e00185d jdk-10+41
 4b62b815b4f49970b91a952929cf50115c263cb3 jdk-10+42
 107413b070b92c88bde6230ceb4a19b579781068 jdk-10+43
+dfa46cfe56346884a61efdc30dc50f7505d66761 jdk-11+1
--- a/make/CompileJavaModules.gmk	Fri Feb 16 12:24:38 2018 -0800
+++ b/make/CompileJavaModules.gmk	Fri Feb 16 13:49:07 2018 -0800
@@ -443,6 +443,7 @@
     #
 
 jdk.internal.vm.compiler_EXCLUDES += \
+    org.graalvm.collections.test \
     org.graalvm.compiler.core.match.processor \
     org.graalvm.compiler.nodeinfo.processor \
     org.graalvm.compiler.options.processor \
@@ -461,6 +462,7 @@
     org.graalvm.compiler.graph.test \
     org.graalvm.compiler.hotspot.amd64.test \
     org.graalvm.compiler.hotspot.lir.test \
+    org.graalvm.compiler.hotspot.sparc.test \
     org.graalvm.compiler.hotspot.test \
     org.graalvm.compiler.jtt \
     org.graalvm.compiler.lir.jtt \
--- a/make/CompileToolsHotspot.gmk	Fri Feb 16 12:24:38 2018 -0800
+++ b/make/CompileToolsHotspot.gmk	Fri Feb 16 13:49:07 2018 -0800
@@ -48,6 +48,7 @@
       SETUP := GENERATE_OLDBYTECODE, \
       SRC := \
           $(SRC_DIR)/org.graalvm.word/src \
+          $(SRC_DIR)/org.graalvm.collections/src \
           $(SRC_DIR)/org.graalvm.compiler.core/src \
           $(SRC_DIR)/org.graalvm.compiler.core.common/src \
           $(SRC_DIR)/org.graalvm.compiler.core.match.processor/src \
@@ -101,6 +102,7 @@
   $(eval $(call SetupJavaCompilation, BUILD_VM_COMPILER_OPTIONS_PROCESSOR, \
       SETUP := GENERATE_OLDBYTECODE, \
       SRC := \
+          $(SRC_DIR)/org.graalvm.collections/src \
           $(SRC_DIR)/org.graalvm.compiler.options/src \
           $(SRC_DIR)/org.graalvm.compiler.options.processor/src \
           $(SRC_DIR)/org.graalvm.util/src \
@@ -117,6 +119,7 @@
       SETUP := GENERATE_OLDBYTECODE, \
       SRC := \
           $(SRC_DIR)/org.graalvm.word/src \
+          $(SRC_DIR)/org.graalvm.collections/src \
           $(SRC_DIR)/org.graalvm.compiler.replacements.verifier/src \
           $(SRC_DIR)/org.graalvm.compiler.api.replacements/src \
           $(SRC_DIR)/org.graalvm.compiler.code/src \
--- a/make/Docs.gmk	Fri Feb 16 12:24:38 2018 -0800
+++ b/make/Docs.gmk	Fri Feb 16 13:49:07 2018 -0800
@@ -445,9 +445,9 @@
 ################################################################################
 # Setup generation of the Java SE API documentation (javadoc + modulegraph)
 
-# The Java SE module scope is just java.se.ee and its transitive indirect
+# The Java SE module scope is just java.se and its transitive indirect
 # exports.
-JAVASE_MODULES := java.se.ee
+JAVASE_MODULES := java.se
 
 $(eval $(call SetupApiDocsGeneration, JAVASE_API, \
     MODULES := $(JAVASE_MODULES), \
--- a/make/InitSupport.gmk	Fri Feb 16 12:24:38 2018 -0800
+++ b/make/InitSupport.gmk	Fri Feb 16 13:49:07 2018 -0800
@@ -361,6 +361,12 @@
 
   BUILD_LOG_PIPE := > >($(TEE) -a $(BUILD_LOG)) 2> >($(TEE) -a $(BUILD_LOG) >&2) && wait
 
+  ifneq ($(CUSTOM_ROOT), )
+    topdir=$(CUSTOM_ROOT)
+  else
+    topdir=$(TOPDIR)
+  endif
+
   # Parse COMPARE_BUILD into COMPARE_BUILD_*
   # Syntax: COMPARE_BUILD=CONF=<configure options>:PATCH=<patch file>:
   #         MAKE=<make targets>:COMP_OPTS=<compare script options>:
@@ -373,7 +379,7 @@
   # FAIL can be set to false to have the return value of compare be ignored.
   define ParseCompareBuild
     ifneq ($$(COMPARE_BUILD), )
-      COMPARE_BUILD_OUTPUTDIR := $(TOPDIR)/build/compare-build/$(CONF_NAME)
+      COMPARE_BUILD_OUTPUTDIR := $(topdir)/build/compare-build/$(CONF_NAME)
       COMPARE_BUILD_FAIL := true
 
       ifneq ($$(findstring :, $$(COMPARE_BUILD)), )
@@ -412,9 +418,9 @@
         endif
       endif
       ifneq ($$(COMPARE_BUILD_PATCH), )
-        ifneq ($$(wildcard $$(TOPDIR)/$$(COMPARE_BUILD_PATCH)), )
+        ifneq ($$(wildcard $$(topdir)/$$(COMPARE_BUILD_PATCH)), )
           # Assume relative path, if file exists
-          COMPARE_BUILD_PATCH := $$(wildcard $$(TOPDIR)/$$(COMPARE_BUILD_PATCH))
+          COMPARE_BUILD_PATCH := $$(wildcard $$(topdir)/$$(COMPARE_BUILD_PATCH))
         else ifeq ($$(wildcard $$(COMPARE_BUILD_PATCH)), )
           $$(error Patch file $$(COMPARE_BUILD_PATCH) does not exist)
         endif
@@ -431,9 +437,9 @@
         # Apply patch, if any
 	$(if $(COMPARE_BUILD_PATCH), $(PATCH) -p1 < $(COMPARE_BUILD_PATCH))
         # Move the first build away temporarily
-	$(RM) -r $(TOPDIR)/build/.compare-build-temp
-	$(MKDIR) -p $(TOPDIR)/build/.compare-build-temp
-	$(MV) $(OUTPUTDIR) $(TOPDIR)/build/.compare-build-temp
+	$(RM) -r $(topdir)/build/.compare-build-temp
+	$(MKDIR) -p $(topdir)/build/.compare-build-temp
+	$(MV) $(OUTPUTDIR) $(topdir)/build/.compare-build-temp
         # Restore an old compare-build, or create a new compare-build directory.
 	if test -d $(COMPARE_BUILD_OUTPUTDIR); then \
 	  $(MV) $(COMPARE_BUILD_OUTPUTDIR) $(OUTPUTDIR); \
@@ -443,7 +449,7 @@
         # Re-run configure with the same arguments (and possibly some additional),
         # must be done after patching.
 	( cd $(OUTPUTDIR) && PATH="$(ORIGINAL_PATH)" \
-	    $(BASH) $(TOPDIR)/configure $(CONFIGURE_COMMAND_LINE) $(COMPARE_BUILD_CONF))
+	    $(BASH) $(topdir)/configure $(CONFIGURE_COMMAND_LINE) $(COMPARE_BUILD_CONF))
   endef
 
   # Cleanup after a compare build
@@ -451,10 +457,10 @@
         # If running with a COMPARE_BUILD patch, reverse-apply it
 	$(if $(COMPARE_BUILD_PATCH), $(PATCH) -R -p1 < $(COMPARE_BUILD_PATCH))
         # Move this build away and restore the original build
-	$(MKDIR) -p $(TOPDIR)/build/compare-build
+	$(MKDIR) -p $(topdir)/build/compare-build
 	$(MV) $(OUTPUTDIR) $(COMPARE_BUILD_OUTPUTDIR)
-	$(MV) $(TOPDIR)/build/.compare-build-temp/$(CONF_NAME) $(OUTPUTDIR)
-	$(RM) -r $(TOPDIR)/build/.compare-build-temp
+	$(MV) $(topdir)/build/.compare-build-temp/$(CONF_NAME) $(OUTPUTDIR)
+	$(RM) -r $(topdir)/build/.compare-build-temp
   endef
 
   # Do the actual comparison of two builds
--- a/make/autoconf/flags.m4	Fri Feb 16 12:24:38 2018 -0800
+++ b/make/autoconf/flags.m4	Fri Feb 16 13:49:07 2018 -0800
@@ -175,6 +175,16 @@
         $1SYSROOT_CFLAGS="-I-xbuiltin -I[$]$1SYSROOT/usr/include"
         $1SYSROOT_LDFLAGS="-L[$]$1SYSROOT/usr/lib$OPENJDK_TARGET_CPU_ISADIR \
             -L[$]$1SYSROOT/lib$OPENJDK_TARGET_CPU_ISADIR"
+        # If the devkit contains the ld linker, make sure we use it.
+        AC_PATH_PROG(SOLARIS_LD, ld, , $DEVKIT_TOOLCHAIN_PATH:$DEVKIT_EXTRA_PATH)
+        # Make sure this ld is runnable.
+        if test -f "$SOLARIS_LD"; then
+          if "$SOLARIS_LD" -V > /dev/null 2> /dev/null; then
+            $1SYSROOT_LDFLAGS="[$]$1SYSROOT_LDFLAGS -Yl,$(dirname $SOLARIS_LD)"
+          else
+            AC_MSG_WARN([Could not run $SOLARIS_LD found in devkit, reverting to system ld])
+          fi
+        fi
       fi
     elif test "x$TOOLCHAIN_TYPE" = xgcc; then
       $1SYSROOT_CFLAGS="--sysroot=[$]$1SYSROOT"
@@ -1030,9 +1040,9 @@
         -qalias=noansi -qstrict -qtls=default -qlanglvl=c99vla \
         -qlanglvl=noredefmac -qnortti -qnoeh -qignerrno"
     # We need '-qminimaltoc' or '-qpic=large -bbigtoc' if the TOC overflows.
-    # Hotspot now overflows its 64K TOC (currently only for slowdebug),
-    # so for slowdebug we build with '-qpic=large -bbigtoc'.
-    if test "x$DEBUG_LEVEL" = xslowdebug; then
+    # Hotspot now overflows its 64K TOC (currently only for debug),
+    # so for debug we build with '-qpic=large -bbigtoc'.
+    if test "x$DEBUG_LEVEL" = xslowdebug || test "x$DEBUG_LEVEL" = xfastdebug; then
       $2JVM_CFLAGS="[$]$2JVM_CFLAGS -qpic=large"
     fi
   elif test "x$OPENJDK_$1_OS" = xbsd; then
@@ -1284,9 +1294,9 @@
     $2LDFLAGS_JDK="${$2LDFLAGS_JDK} $LDFLAGS_XLC"
     $2JVM_LDFLAGS="[$]$2JVM_LDFLAGS $LDFLAGS_XLC"
     # We need '-qminimaltoc' or '-qpic=large -bbigtoc' if the TOC overflows.
-    # Hotspot now overflows its 64K TOC (currently only for slowdebug),
-    # so for slowdebug we build with '-qpic=large -bbigtoc'.
-    if test "x$DEBUG_LEVEL" = xslowdebug; then
+    # Hotspot now overflows its 64K TOC (currently only for debug),
+    # so we build with '-qpic=large -bbigtoc'.
+    if test "x$DEBUG_LEVEL" = xslowdebug || test "x$DEBUG_LEVEL" = xfastdebug; then
       $2JVM_LDFLAGS="[$]$2JVM_LDFLAGS -bbigtoc"
     fi
   fi
--- a/make/conf/jib-profiles.js	Fri Feb 16 12:24:38 2018 -0800
+++ b/make/conf/jib-profiles.js	Fri Feb 16 13:49:07 2018 -0800
@@ -768,7 +768,7 @@
         linux_x64: "gcc4.9.2-OEL6.4+1.2",
         macosx_x64: "Xcode6.3-MacOSX10.9+1.0",
         solaris_x64: "SS12u4-Solaris11u1+1.0",
-        solaris_sparcv9: "SS12u4-Solaris11u1+1.0",
+        solaris_sparcv9: "SS12u4-Solaris11u1+1.1",
         windows_x64: "VS2013SP4+1.0",
         linux_aarch64: "gcc-linaro-aarch64-linux-gnu-4.8-2013.11_linux+1.0",
         linux_arm: (input.profile != null && input.profile.indexOf("hflt") >= 0
--- a/make/devkit/createSolarisDevkit.sh	Fri Feb 16 12:24:38 2018 -0800
+++ b/make/devkit/createSolarisDevkit.sh	Fri Feb 16 13:49:07 2018 -0800
@@ -73,7 +73,8 @@
 DEVKIT_ROOT=${BUILD_DIR}/${DEVKIT_NAME}
 BUNDLE_NAME=${DEVKIT_NAME}.tar.gz
 BUNDLE=${BUILD_DIR}/${BUNDLE_NAME}
-INSTALL_ROOT=${BUILD_DIR}/install-root
+INSTALL_ROOT=${BUILD_DIR}/install-root-$SOLARIS_VERSION
+INSTALL_ROOT_TOOLS=${BUILD_DIR}/install-root-tools-$SOLARIS_VERSION
 SYSROOT=${DEVKIT_ROOT}/sysroot
 SOLARIS_STUDIO_SUBDIR=SS${SOLARIS_STUDIO_VERSION}
 SOLARIS_STUDIO_DIR=${DEVKIT_ROOT}/${SOLARIS_STUDIO_SUBDIR}
@@ -92,17 +93,27 @@
   echo "Skipping installing packages"
 fi
 
+# Since we have implicitly been running 11.2 tools for a long time, we need
+# to pick them for the tools dir in the devkit. Create a separate install-root
+# for it.
+if [ ! -d $INSTALL_ROOT_TOOLS ]; then
+  echo "Creating $INSTALL_ROOT_TOOLS and installing packages"
+  pkg image-create $INSTALL_ROOT_TOOLS
+  pkg -R $INSTALL_ROOT_TOOLS set-publisher -P -g ${PUBLISHER_URI} solaris
+  sudo pkg -R $INSTALL_ROOT_TOOLS install --accept \
+      entire@0.5.11-0.175.2.5.0.5.0 \
+      system/linker \
+      developer/base-developer-utilities \
+      developer/gnu-binutils
+else
+  echo "Skipping installing tools packages"
+fi
+
 if [ ! -d $SYSROOT ]; then
   echo "Copying from $INSTALL_ROOT to $SYSROOT"
   mkdir -p $SYSROOT
   cp -rH $INSTALL_ROOT/lib $SYSROOT/
-  mkdir $SYSROOT/usr $DEVKIT_ROOT/gnu
-  # Some of the tools in sysroot are needed in the OpenJDK build but cannot be
-  # run from their current location due to relative runtime paths in the
-  # binaries. Move the sysroot/usr/bin directory to the outer bin and have them
-  # be runnable from there to force them to link to the system libraries
-  cp -rH $INSTALL_ROOT/usr/bin $DEVKIT_ROOT
-  cp -rH $INSTALL_ROOT/usr/gnu/bin $DEVKIT_ROOT/gnu/
+  mkdir $SYSROOT/usr
   cp -rH $INSTALL_ROOT/usr/lib $SYSROOT/usr/
   cp -rH $INSTALL_ROOT/usr/include $SYSROOT/usr/
   pkg -R $INSTALL_ROOT list > $SYSROOT/pkg-list.txt
@@ -110,10 +121,36 @@
   echo "Skipping copying to $SYSROOT"
 fi
 
+if [ ! -d $DEVKIT_ROOT/tools ]; then
+  echo "Copying from $INSTALL_ROOT_TOOLS to $DEVKIT_ROOT/tools"
+  # Some of the tools in sysroot are needed in the OpenJDK build. We need
+  # to copy them into a tools dir, including their specific libraries.
+  mkdir -p $DEVKIT_ROOT/tools/usr/bin/sparcv9 $DEVKIT_ROOT/tools/lib/sparcv9 \
+      $DEVKIT_ROOT/tools/usr/gnu/bin
+  cp $INSTALL_ROOT_TOOLS/usr/bin/{ar,nm,strip,ld,ldd} \
+       $DEVKIT_ROOT/tools/usr/bin/
+  cp $INSTALL_ROOT_TOOLS/usr/bin/sparcv9/{ar,nm,strip,ld,ldd} \
+       $DEVKIT_ROOT/tools/usr/bin/sparcv9/
+  cp $INSTALL_ROOT_TOOLS/usr/sbin/dtrace $DEVKIT_ROOT/tools/usr/bin/
+  cp $INSTALL_ROOT_TOOLS/usr/sbin/sparcv9/dtrace $DEVKIT_ROOT/tools/usr/bin/sparcv9/
+  cp -rH $INSTALL_ROOT_TOOLS/usr/gnu/bin/* $DEVKIT_ROOT/tools/usr/gnu/bin/
+  cp $INSTALL_ROOT_TOOLS/lib/{libelf.so*,libld.so*,liblddbg.so*} \
+      $DEVKIT_ROOT/tools/lib/
+  cp $INSTALL_ROOT_TOOLS/lib/sparcv9/{libelf.so*,libld.so*,liblddbg.so*} \
+      $DEVKIT_ROOT/tools/lib/sparcv9/
+  for t in $(ls $DEVKIT_ROOT/tools/usr/gnu/bin); do
+    if [ -f $DEVKIT_ROOT/tools/usr/gnu/bin/$t ]; then
+      ln -s ../gnu/bin/$t $DEVKIT_ROOT/tools/usr/bin/g$t
+    fi
+  done
+else
+  echo "Skipping copying to tools dir $DEVKIT_ROOT/tools"
+fi
+
 if [ ! -d $SOLARIS_STUDIO_DIR ]; then
   echo "Copying Solaris Studio from $SOLARIS_STUDIO_SRC"
-  cp -rH $SOLARIS_STUDIO_SRC ${SOLARIS_STUDIO_DIR%/*}
-  mv ${SOLARIS_STUDIO_DIR%/*}/${SOLARIS_STUDIO_SRC##*/} $SOLARIS_STUDIO_DIR
+  mkdir -p ${SOLARIS_STUDIO_DIR}
+  cp -rH $SOLARIS_STUDIO_SRC/. ${SOLARIS_STUDIO_DIR}/
   # Solaris Studio 12.4 requires /lib/libmmheap.so.1 to run, but this lib is not
   # installed by default on all Solaris systems. Sneak it in from the sysroot to
   # make it run OOTB on more systems.
@@ -123,10 +160,9 @@
 fi
 
 echo "Copying gnu make to $DEVKIT_ROOT/bin"
-mkdir -p $DEVKIT_ROOT/bin
-cp $GNU_MAKE $DEVKIT_ROOT/bin/
-if [ ! -e $DEVKIT_ROOT/bin/gmake ]; then
-  ln -s make $DEVKIT_ROOT/bin/gmake
+cp $GNU_MAKE $DEVKIT_ROOT/tools/usr/bin/
+if [ ! -e $DEVKIT_ROOT/tools/usr/bin/gmake ]; then
+  ln -s make $DEVKIT_ROOT/tools/usr/bin/gmake
 fi
 
 # Create the devkit.info file
@@ -136,7 +172,7 @@
 echo "# This file describes to configure how to interpret the contents of this devkit" >> $INFO_FILE
 echo "DEVKIT_NAME=\"Solaris Studio $SOLARIS_STUDIO_VERSION - Solaris $SOLARIS_VERSION - $ARCH\"" >> $INFO_FILE
 echo "DEVKIT_TOOLCHAIN_PATH=\"\$DEVKIT_ROOT/$SOLARIS_STUDIO_SUBDIR/bin:\$DEVKIT_ROOT/bin\"" >> $INFO_FILE
-echo "DEVKIT_EXTRA_PATH=\"\$DEVKIT_ROOT/bin\"" >> $INFO_FILE
+echo "DEVKIT_EXTRA_PATH=\"\$DEVKIT_ROOT/tools/usr/bin\"" >> $INFO_FILE
 echo "DEVKIT_SYSROOT=\"\$DEVKIT_ROOT/sysroot\"" >> $INFO_FILE
 
 if [ ! -e $BUNDLE ]; then
--- a/make/jdk/src/classes/build/tools/taglet/ModuleGraph.java	Fri Feb 16 12:24:38 2018 -0800
+++ b/make/jdk/src/classes/build/tools/taglet/ModuleGraph.java	Fri Feb 16 13:49:07 2018 -0800
@@ -64,7 +64,7 @@
         }
 
         String moduleName = ((ModuleElement) element).getQualifiedName().toString();
-        String imageFile = moduleName + "/module-graph.png";
+        String imageFile = "module-graph.png";
         int thumbnailHeight = -1;
         String hoverImage = "";
         if (!moduleName.equals("java.base")) {
--- a/make/launcher/Launcher-jdk.jcmd.gmk	Fri Feb 16 12:24:38 2018 -0800
+++ b/make/launcher/Launcher-jdk.jcmd.gmk	Fri Feb 16 13:49:07 2018 -0800
@@ -1,5 +1,5 @@
 #
-# Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2011, 2018, Oracle and/or its affiliates. All rights reserved.
 # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 #
 # This code is free software; you can redistribute it and/or modify it
@@ -60,3 +60,6 @@
 $(eval $(call SetupBuildLauncher, jcmd, \
     MAIN_CLASS := sun.tools.jcmd.JCmd, \
 ))
+
+# Hook to include the corresponding custom file, if present.
+$(eval $(call IncludeCustomExtension, launcher/Launcher-jdk.jcmd-post.gmk))
--- a/make/launcher/Launcher-jdk.jstatd.gmk	Fri Feb 16 12:24:38 2018 -0800
+++ b/make/launcher/Launcher-jdk.jstatd.gmk	Fri Feb 16 13:49:07 2018 -0800
@@ -1,5 +1,5 @@
 #
-# Copyright (c) 2011, 2016, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2011, 2018, Oracle and/or its affiliates. All rights reserved.
 # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 #
 # This code is free software; you can redistribute it and/or modify it
@@ -28,3 +28,6 @@
 $(eval $(call SetupBuildLauncher, jstatd, \
     MAIN_CLASS := sun.tools.jstatd.Jstatd, \
 ))
+
+# Hook to include the corresponding custom file, if present.
+$(eval $(call IncludeCustomExtension, launcher/Launcher-jdk.jstatd-post.gmk))
--- a/make/test/JtregNativeHotspot.gmk	Fri Feb 16 12:24:38 2018 -0800
+++ b/make/test/JtregNativeHotspot.gmk	Fri Feb 16 13:49:07 2018 -0800
@@ -67,6 +67,7 @@
     $(TOPDIR)/test/hotspot/jtreg/compiler/calls \
     $(TOPDIR)/test/hotspot/jtreg/compiler/runtime/criticalnatives/lookup \
     $(TOPDIR)/test/hotspot/jtreg/compiler/runtime/criticalnatives/argumentcorruption \
+    $(TOPDIR)/test/hotspot/jtreg/serviceability/jvmti/CanGenerateAllClassHook \
     $(TOPDIR)/test/hotspot/jtreg/serviceability/jvmti/GetOwnedMonitorInfo \
     $(TOPDIR)/test/hotspot/jtreg/serviceability/jvmti/GetOwnedMonitorStackDepthInfo \
     $(TOPDIR)/test/hotspot/jtreg/serviceability/jvmti/GetNamedModule \
@@ -101,6 +102,7 @@
 ifeq ($(TOOLCHAIN_TYPE), solstudio)
     BUILD_HOTSPOT_JTREG_LIBRARIES_LIBS_liboverflow := -lc
     BUILD_HOTSPOT_JTREG_LIBRARIES_LIBS_libSimpleClassFileLoadHook := -lc
+    BUILD_HOTSPOT_JTREG_LIBRARIES_LIBS_libCanGenerateAllClassHook := -lc
     BUILD_HOTSPOT_JTREG_LIBRARIES_LIBS_libGetOwnedMonitorInfoTest := -lc
     BUILD_HOTSPOT_JTREG_LIBRARIES_LIBS_libGetOwnedMonitorStackDepthInfoTest := -lc
     BUILD_HOTSPOT_JTREG_LIBRARIES_LIBS_libGetNamedModuleTest := -lc
--- a/src/hotspot/cpu/aarch64/c1_LIRAssembler_aarch64.cpp	Fri Feb 16 12:24:38 2018 -0800
+++ b/src/hotspot/cpu/aarch64/c1_LIRAssembler_aarch64.cpp	Fri Feb 16 13:49:07 2018 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2000, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2000, 2018, Oracle and/or its affiliates. All rights reserved.
  * Copyright (c) 2014, Red Hat Inc. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
@@ -2532,7 +2532,7 @@
   ciMethodData* md = method->method_data_or_null();
   assert(md != NULL, "Sanity");
   ciProfileData* data = md->bci_to_data(bci);
-  assert(data->is_CounterData(), "need CounterData for calls");
+  assert(data != NULL && data->is_CounterData(), "need CounterData for calls");
   assert(op->mdo()->is_single_cpu(),  "mdo must be allocated");
   Register mdo  = op->mdo()->as_register();
   __ mov_metadata(mdo, md->constant_encoding());
--- a/src/hotspot/cpu/arm/c1_LIRAssembler_arm.cpp	Fri Feb 16 12:24:38 2018 -0800
+++ b/src/hotspot/cpu/arm/c1_LIRAssembler_arm.cpp	Fri Feb 16 13:49:07 2018 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2008, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2008, 2018, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -3150,7 +3150,7 @@
   ciMethodData* md = method->method_data_or_null();
   assert(md != NULL, "Sanity");
   ciProfileData* data = md->bci_to_data(bci);
-  assert(data->is_CounterData(), "need CounterData for calls");
+  assert(data != NULL && data->is_CounterData(), "need CounterData for calls");
   assert(op->mdo()->is_single_cpu(),  "mdo must be allocated");
   Register mdo  = op->mdo()->as_register();
   assert(op->tmp1()->is_register(), "tmp1 must be allocated");
--- a/src/hotspot/cpu/ppc/c1_LIRAssembler_ppc.cpp	Fri Feb 16 12:24:38 2018 -0800
+++ b/src/hotspot/cpu/ppc/c1_LIRAssembler_ppc.cpp	Fri Feb 16 13:49:07 2018 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2000, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2000, 2018, Oracle and/or its affiliates. All rights reserved.
  * Copyright (c) 2012, 2017, SAP SE. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
@@ -2746,7 +2746,7 @@
   ciMethodData* md = method->method_data_or_null();
   assert(md != NULL, "Sanity");
   ciProfileData* data = md->bci_to_data(bci);
-  assert(data->is_CounterData(), "need CounterData for calls");
+  assert(data != NULL && data->is_CounterData(), "need CounterData for calls");
   assert(op->mdo()->is_single_cpu(),  "mdo must be allocated");
   Register mdo = op->mdo()->as_register();
 #ifdef _LP64
--- a/src/hotspot/cpu/s390/c1_LIRAssembler_s390.cpp	Fri Feb 16 12:24:38 2018 -0800
+++ b/src/hotspot/cpu/s390/c1_LIRAssembler_s390.cpp	Fri Feb 16 13:49:07 2018 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
  * Copyright (c) 2016, 2017, SAP SE. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
@@ -2715,7 +2715,7 @@
   ciMethodData* md = method->method_data_or_null();
   assert(md != NULL, "Sanity");
   ciProfileData* data = md->bci_to_data(bci);
-  assert(data->is_CounterData(), "need CounterData for calls");
+  assert(data != NULL && data->is_CounterData(), "need CounterData for calls");
   assert(op->mdo()->is_single_cpu(),  "mdo must be allocated");
   Register mdo  = op->mdo()->as_register();
   assert(op->tmp1()->is_double_cpu(), "tmp1 must be allocated");
--- a/src/hotspot/cpu/sparc/c1_LIRAssembler_sparc.cpp	Fri Feb 16 12:24:38 2018 -0800
+++ b/src/hotspot/cpu/sparc/c1_LIRAssembler_sparc.cpp	Fri Feb 16 13:49:07 2018 -0800
@@ -2761,7 +2761,7 @@
   ciMethodData* md = method->method_data_or_null();
   assert(md != NULL, "Sanity");
   ciProfileData* data = md->bci_to_data(bci);
-  assert(data->is_CounterData(), "need CounterData for calls");
+  assert(data != NULL && data->is_CounterData(), "need CounterData for calls");
   assert(op->mdo()->is_single_cpu(),  "mdo must be allocated");
   Register mdo  = op->mdo()->as_register();
   assert(op->tmp1()->is_double_cpu(), "tmp1 must be allocated");
--- a/src/hotspot/cpu/x86/c1_LIRAssembler_x86.cpp	Fri Feb 16 12:24:38 2018 -0800
+++ b/src/hotspot/cpu/x86/c1_LIRAssembler_x86.cpp	Fri Feb 16 13:49:07 2018 -0800
@@ -3504,7 +3504,7 @@
   ciMethodData* md = method->method_data_or_null();
   assert(md != NULL, "Sanity");
   ciProfileData* data = md->bci_to_data(bci);
-  assert(data->is_CounterData(), "need CounterData for calls");
+  assert(data != NULL && data->is_CounterData(), "need CounterData for calls");
   assert(op->mdo()->is_single_cpu(),  "mdo must be allocated");
   Register mdo  = op->mdo()->as_register();
   __ mov_metadata(mdo, md->constant_encoding());
--- a/src/hotspot/cpu/x86/stubGenerator_x86_32.cpp	Fri Feb 16 12:24:38 2018 -0800
+++ b/src/hotspot/cpu/x86/stubGenerator_x86_32.cpp	Fri Feb 16 13:49:07 2018 -0800
@@ -676,6 +676,7 @@
     assert_different_registers(start, count);
     BarrierSet* bs = Universe::heap()->barrier_set();
     switch (bs->kind()) {
+#if INCLUDE_ALL_GCS
       case BarrierSet::G1SATBCTLogging:
         // With G1, don't generate the call if we statically know that the target in uninitialized
         if (!uninitialized_target) {
@@ -703,6 +704,7 @@
            __ bind(filtered);
          }
         break;
+#endif // INCLUDE_ALL_GCS
       case BarrierSet::CardTableForRS:
       case BarrierSet::CardTableExtension:
       case BarrierSet::ModRef:
@@ -726,6 +728,7 @@
     BarrierSet* bs = Universe::heap()->barrier_set();
     assert_different_registers(start, count);
     switch (bs->kind()) {
+#if INCLUDE_ALL_GCS
       case BarrierSet::G1SATBCTLogging:
         {
           __ pusha();                      // push registers
@@ -734,6 +737,7 @@
           __ popa();
         }
         break;
+#endif // INCLUDE_ALL_GCS
 
       case BarrierSet::CardTableForRS:
       case BarrierSet::CardTableExtension:
--- a/src/hotspot/os/aix/os_aix.cpp	Fri Feb 16 12:24:38 2018 -0800
+++ b/src/hotspot/os/aix/os_aix.cpp	Fri Feb 16 13:49:07 2018 -0800
@@ -188,6 +188,7 @@
 ////////////////////////////////////////////////////////////////////////////////
 // local variables
 
+static volatile jlong max_real_time = 0;
 static jlong    initial_time_count = 0;
 static int      clock_tics_per_sec = 100;
 static sigset_t check_signal_done;         // For diagnostics to print a message once (see run_periodic_checks)
@@ -1076,32 +1077,50 @@
   nanos = jlong(time.tv_usec) * 1000;
 }
 
+// We use mread_real_time here.
+// On AIX: If the CPU has a time register, the result will be RTC_POWER and
+// it has to be converted to real time. AIX documentations suggests to do
+// this unconditionally, so we do it.
+//
+// See: https://www.ibm.com/support/knowledgecenter/ssw_aix_61/com.ibm.aix.basetrf2/read_real_time.htm
+//
+// On PASE: mread_real_time will always return RTC_POWER_PC data, so no
+// conversion is necessary. However, mread_real_time will not return
+// monotonic results but merely matches read_real_time. So we need a tweak
+// to ensure monotonic results.
+//
+// For PASE no public documentation exists, just word by IBM
 jlong os::javaTimeNanos() {
+  timebasestruct_t time;
+  int rc = mread_real_time(&time, TIMEBASE_SZ);
   if (os::Aix::on_pase()) {
-
-    timeval time;
-    int status = gettimeofday(&time, NULL);
-    assert(status != -1, "PASE error at gettimeofday()");
-    jlong usecs = jlong((unsigned long long) time.tv_sec * (1000 * 1000) + time.tv_usec);
-    return 1000 * usecs;
-
+    assert(rc == RTC_POWER, "expected time format RTC_POWER from mread_real_time in PASE");
+    jlong now = jlong(time.tb_high) * NANOSECS_PER_SEC + jlong(time.tb_low);
+    jlong prev = max_real_time;
+    if (now <= prev) {
+      return prev;   // same or retrograde time;
+    }
+    jlong obsv = Atomic::cmpxchg(now, &max_real_time, prev);
+    assert(obsv >= prev, "invariant");   // Monotonicity
+    // If the CAS succeeded then we're done and return "now".
+    // If the CAS failed and the observed value "obsv" is >= now then
+    // we should return "obsv".  If the CAS failed and now > obsv > prv then
+    // some other thread raced this thread and installed a new value, in which case
+    // we could either (a) retry the entire operation, (b) retry trying to install now
+    // or (c) just return obsv.  We use (c).   No loop is required although in some cases
+    // we might discard a higher "now" value in deference to a slightly lower but freshly
+    // installed obsv value.   That's entirely benign -- it admits no new orderings compared
+    // to (a) or (b) -- and greatly reduces coherence traffic.
+    // We might also condition (c) on the magnitude of the delta between obsv and now.
+    // Avoiding excessive CAS operations to hot RW locations is critical.
+    // See https://blogs.oracle.com/dave/entry/cas_and_cache_trivia_invalidate
+    return (prev == obsv) ? now : obsv;
   } else {
-    // On AIX use the precision of processors real time clock
-    // or time base registers.
-    timebasestruct_t time;
-    int rc;
-
-    // If the CPU has a time register, it will be used and
-    // we have to convert to real time first. After convertion we have following data:
-    // time.tb_high [seconds since 00:00:00 UTC on 1.1.1970]
-    // time.tb_low  [nanoseconds after the last full second above]
-    // We better use mread_real_time here instead of read_real_time
-    // to ensure that we will get a monotonic increasing time.
-    if (mread_real_time(&time, TIMEBASE_SZ) != RTC_POWER) {
+    if (rc != RTC_POWER) {
       rc = time_base_to_time(&time, TIMEBASE_SZ);
-      assert(rc != -1, "aix error at time_base_to_time()");
+      assert(rc != -1, "error calling time_base_to_time()");
     }
-    return jlong(time.tb_high) * (1000 * 1000 * 1000) + jlong(time.tb_low);
+    return jlong(time.tb_high) * NANOSECS_PER_SEC + jlong(time.tb_low);
   }
 }
 
--- a/src/hotspot/os/bsd/jvm_bsd.cpp	Fri Feb 16 12:24:38 2018 -0800
+++ b/src/hotspot/os/bsd/jvm_bsd.cpp	Fri Feb 16 13:49:07 2018 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1999, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1999, 2018, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -51,6 +51,12 @@
     case SIGILL:
     case SIGSEGV:
 
+#if defined(__APPLE__)
+    /* On Darwin, memory access errors commonly results in SIGBUS instead
+     * of SIGSEGV. */
+    case SIGBUS:
+#endif
+
     /* The following signal is used by the VM to dump thread stacks unless
        ReduceSignalUsage is set, in which case the user is allowed to set
        his own _native_ handler for this signal; thus, in either case,
--- a/src/hotspot/os/bsd/os_bsd.cpp	Fri Feb 16 12:24:38 2018 -0800
+++ b/src/hotspot/os/bsd/os_bsd.cpp	Fri Feb 16 13:49:07 2018 -0800
@@ -2206,7 +2206,7 @@
 
 bool os::release_memory_special(char* base, size_t bytes) {
   if (MemTracker::tracking_level() > NMT_minimal) {
-    Tracker tkr = MemTracker::get_virtual_memory_release_tracker();
+    Tracker tkr(Tracker::release);
     // detaching the SHM segment will also delete it, see reserve_memory_special()
     int rslt = shmdt(base);
     if (rslt == 0) {
--- a/src/hotspot/os/linux/osContainer_linux.cpp	Fri Feb 16 12:24:38 2018 -0800
+++ b/src/hotspot/os/linux/osContainer_linux.cpp	Fri Feb 16 13:49:07 2018 -0800
@@ -122,35 +122,40 @@
   char file[MAXPATHLEN+1];
   char buf[MAXPATHLEN+1];
 
-  if (c != NULL && c->subsystem_path() != NULL) {
-    strncpy(file, c->subsystem_path(), MAXPATHLEN);
-    file[MAXPATHLEN-1] = '\0';
-    int filelen = strlen(file);
-    if ((filelen + strlen(filename)) > (MAXPATHLEN-1)) {
-       log_debug(os, container)("File path too long %s, %s", file, filename);
-       return OSCONTAINER_ERROR;
-    }
-    strncat(file, filename, MAXPATHLEN-filelen);
-    log_trace(os, container)("Path to %s is %s", filename, file);
-    fp = fopen(file, "r");
-    if (fp != NULL) {
-      p = fgets(buf, MAXPATHLEN, fp);
-      if (p != NULL) {
-        int matched = sscanf(p, scan_fmt, returnval);
-        if (matched == 1) {
-          fclose(fp);
-          return 0;
-        } else {
-          log_debug(os, container)("Type %s not found in file %s",
-                                     scan_fmt , file);
-        }
+  if (c == NULL) {
+    log_debug(os, container)("subsystem_file_contents: CgroupSubsytem* is NULL");
+    return OSCONTAINER_ERROR;
+  }
+  if (c->subsystem_path() == NULL) {
+    log_debug(os, container)("subsystem_file_contents: subsystem path is NULL");
+    return OSCONTAINER_ERROR;
+  }
+
+  strncpy(file, c->subsystem_path(), MAXPATHLEN);
+  file[MAXPATHLEN-1] = '\0';
+  int filelen = strlen(file);
+  if ((filelen + strlen(filename)) > (MAXPATHLEN-1)) {
+    log_debug(os, container)("File path too long %s, %s", file, filename);
+    return OSCONTAINER_ERROR;
+  }
+  strncat(file, filename, MAXPATHLEN-filelen);
+  log_trace(os, container)("Path to %s is %s", filename, file);
+  fp = fopen(file, "r");
+  if (fp != NULL) {
+    p = fgets(buf, MAXPATHLEN, fp);
+    if (p != NULL) {
+      int matched = sscanf(p, scan_fmt, returnval);
+      if (matched == 1) {
+        fclose(fp);
+        return 0;
       } else {
-        log_debug(os, container)("Empty file %s", file);
+        log_debug(os, container)("Type %s not found in file %s", scan_fmt, file);
       }
     } else {
-      log_debug(os, container)("Open of file %s failed, %s", file,
-                               os::strerror(errno));
+      log_debug(os, container)("Empty file %s", file);
     }
+  } else {
+    log_debug(os, container)("Open of file %s failed, %s", file, os::strerror(errno));
   }
   if (fp != NULL)
     fclose(fp);
@@ -273,7 +278,7 @@
         else {
           log_debug(os, container)("Incompatible str containing cgroup and cpuset: %s", p);
         }
-      } else if (strstr(p, "cpu,cpuacct") != NULL) {
+      } else if (strstr(p, "cpu,cpuacct") != NULL || strstr(p, "cpuacct,cpu") != NULL) {
         int matched = sscanf(p, "%d %d %d:%d %s %s",
                              &mountid,
                              &parentid,
@@ -322,8 +327,20 @@
 
   fclose(mntinfo);
 
-  if (memory == NULL || cpuset == NULL || cpu == NULL || cpuacct == NULL) {
-    log_debug(os, container)("Required cgroup subsystems not found");
+  if (memory == NULL) {
+    log_debug(os, container)("Required cgroup memory subsystem not found");
+    return;
+  }
+  if (cpuset == NULL) {
+    log_debug(os, container)("Required cgroup cpuset subsystem not found");
+    return;
+  }
+  if (cpu == NULL) {
+    log_debug(os, container)("Required cgroup cpu subsystem not found");
+    return;
+  }
+  if (cpuacct == NULL) {
+    log_debug(os, container)("Required cgroup cpuacct subsystem not found");
     return;
   }
 
@@ -374,7 +391,7 @@
         memory->set_subsystem_path(base);
       } else if (strstr(controller, "cpuset") != NULL) {
         cpuset->set_subsystem_path(base);
-      } else if (strstr(controller, "cpu,cpuacct") != NULL) {
+      } else if (strstr(controller, "cpu,cpuacct") != NULL || strstr(controller, "cpuacct,cpu") != NULL) {
         cpu->set_subsystem_path(base);
         cpuacct->set_subsystem_path(base);
       } else if (strstr(controller, "cpuacct") != NULL) {
--- a/src/hotspot/os/linux/os_linux.cpp	Fri Feb 16 12:24:38 2018 -0800
+++ b/src/hotspot/os/linux/os_linux.cpp	Fri Feb 16 13:49:07 2018 -0800
@@ -3862,7 +3862,7 @@
 bool os::release_memory_special(char* base, size_t bytes) {
   bool res;
   if (MemTracker::tracking_level() > NMT_minimal) {
-    Tracker tkr = MemTracker::get_virtual_memory_release_tracker();
+    Tracker tkr(Tracker::release);
     res = os::Linux::release_memory_special_impl(base, bytes);
     if (res) {
       tkr.record((address)base, bytes);
--- a/src/hotspot/os/windows/perfMemory_windows.cpp	Fri Feb 16 12:24:38 2018 -0800
+++ b/src/hotspot/os/windows/perfMemory_windows.cpp	Fri Feb 16 13:49:07 2018 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2001, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2001, 2018, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -1840,7 +1840,7 @@
 
   if (MemTracker::tracking_level() > NMT_minimal) {
     // it does not go through os api, the operation has to record from here
-    Tracker tkr = MemTracker::get_virtual_memory_release_tracker();
+    Tracker tkr(Tracker::release);
     remove_file_mapping(addr);
     tkr.record((address)addr, bytes);
   } else {
--- a/src/hotspot/share/c1/c1_GraphBuilder.cpp	Fri Feb 16 12:24:38 2018 -0800
+++ b/src/hotspot/share/c1/c1_GraphBuilder.cpp	Fri Feb 16 13:49:07 2018 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1999, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1999, 2018, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -1556,8 +1556,6 @@
       }
       if (profile_return() && x->type()->is_object_kind()) {
         ciMethod* caller = state()->scope()->method();
-        ciMethodData* md = caller->method_data_or_null();
-        ciProfileData* data = md->bci_to_data(invoke_bci);
         profile_return_type(x, method(), caller, invoke_bci);
       }
     }
--- a/src/hotspot/share/classfile/classLoaderData.cpp	Fri Feb 16 12:24:38 2018 -0800
+++ b/src/hotspot/share/classfile/classLoaderData.cpp	Fri Feb 16 13:49:07 2018 -0800
@@ -80,6 +80,9 @@
 #include "trace/tracing.hpp"
 #endif
 
+volatile size_t ClassLoaderDataGraph::_num_array_classes = 0;
+volatile size_t ClassLoaderDataGraph::_num_instance_classes = 0;
+
 ClassLoaderData * ClassLoaderData::_the_null_class_loader_data = NULL;
 
 ClassLoaderData::ClassLoaderData(Handle h_class_loader, bool is_anonymous, Dependencies dependencies) :
@@ -329,36 +332,36 @@
   ClassLoaderData * const from_cld = this;
   ClassLoaderData * const to_cld = k->class_loader_data();
 
-  // Dependency to the null class loader data doesn't need to be recorded
-  // because the null class loader data never goes away.
-  if (to_cld->is_the_null_class_loader_data()) {
+  // Do not need to record dependency if the dependency is to a class whose
+  // class loader data is never freed.  (i.e. the dependency's class loader
+  // is one of the three builtin class loaders and the dependency is not
+  // anonymous.)
+  if (to_cld->is_permanent_class_loader_data()) {
     return;
   }
 
   oop to;
   if (to_cld->is_anonymous()) {
+    // Just return if an anonymous class is attempting to record a dependency
+    // to itself.  (Note that every anonymous class has its own unique class
+    // loader data.)
+    if (to_cld == from_cld) {
+      return;
+    }
     // Anonymous class dependencies are through the mirror.
     to = k->java_mirror();
   } else {
     to = to_cld->class_loader();
-
-    // If from_cld is anonymous, even if it's class_loader is a parent of 'to'
-    // we still have to add it.  The class_loader won't keep from_cld alive.
-    if (!from_cld->is_anonymous()) {
-      // Check that this dependency isn't from the same or parent class_loader
-      oop from = from_cld->class_loader();
+    oop from = from_cld->class_loader();
 
-      oop curr = from;
-      while (curr != NULL) {
-        if (curr == to) {
-          return; // this class loader is in the parent list, no need to add it.
-        }
-        curr = java_lang_ClassLoader::parent(curr);
-      }
+    // Just return if this dependency is to a class with the same or a parent
+    // class_loader.
+    if (from == to || java_lang_ClassLoader::isAncestor(from, to)) {
+      return; // this class loader is in the parent list, no need to add it.
     }
   }
 
-  // It's a dependency we won't find through GC, add it. This is relatively rare
+  // It's a dependency we won't find through GC, add it. This is relatively rare.
   // Must handle over GC point.
   Handle dependency(THREAD, to);
   from_cld->_dependencies.add(dependency, CHECK);
@@ -443,6 +446,11 @@
     // Link the new item into the list, making sure the linked class is stable
     // since the list can be walked without a lock
     OrderAccess::release_store(&_klasses, k);
+    if (k->is_array_klass()) {
+      ClassLoaderDataGraph::inc_array_classes(1);
+    } else {
+      ClassLoaderDataGraph::inc_instance_classes(1);
+    }
   }
 
   if (publicize && k->class_loader_data() != NULL) {
@@ -468,9 +476,9 @@
 
   InstanceKlass* try_get_next_class() {
     assert(SafepointSynchronize::is_at_safepoint(), "only called at safepoint");
-    int max_classes = InstanceKlass::number_of_instance_classes();
+    size_t max_classes = ClassLoaderDataGraph::num_instance_classes();
     assert(max_classes > 0, "should not be called with no instance classes");
-    for (int i = 0; i < max_classes; ) {
+    for (size_t i = 0; i < max_classes; ) {
 
       if (_current_class_entry != NULL) {
         Klass* k = _current_class_entry;
@@ -545,6 +553,13 @@
         Klass* next = k->next_link();
         prev->set_next_link(next);
       }
+
+      if (k->is_array_klass()) {
+        ClassLoaderDataGraph::dec_array_classes(1);
+      } else {
+        ClassLoaderDataGraph::dec_instance_classes(1);
+      }
+
       return;
     }
     prev = k;
@@ -639,9 +654,34 @@
   return alive;
 }
 
+class ReleaseKlassClosure: public KlassClosure {
+private:
+  size_t  _instance_class_released;
+  size_t  _array_class_released;
+public:
+  ReleaseKlassClosure() : _instance_class_released(0), _array_class_released(0) { }
+
+  size_t instance_class_released() const { return _instance_class_released; }
+  size_t array_class_released()    const { return _array_class_released;    }
+
+  void do_klass(Klass* k) {
+    if (k->is_array_klass()) {
+      _array_class_released ++;
+    } else {
+      assert(k->is_instance_klass(), "Must be");
+      _instance_class_released ++;
+      InstanceKlass::release_C_heap_structures(InstanceKlass::cast(k));
+    }
+  }
+};
+
 ClassLoaderData::~ClassLoaderData() {
   // Release C heap structures for all the classes.
-  classes_do(InstanceKlass::release_C_heap_structures);
+  ReleaseKlassClosure cl;
+  classes_do(&cl);
+
+  ClassLoaderDataGraph::dec_array_classes(cl.array_class_released());
+  ClassLoaderDataGraph::dec_instance_classes(cl.instance_class_released());
 
   // Release C heap allocated hashtable for all the packages.
   if (_packages != NULL) {
@@ -693,25 +733,37 @@
   }
 }
 
-// Returns true if this class loader data is for the system class loader.
+// Returns true if this class loader data is for the app class loader
+// or a user defined system class loader.  (Note that the class loader
+// data may be anonymous.)
 bool ClassLoaderData::is_system_class_loader_data() const {
   return SystemDictionary::is_system_class_loader(class_loader());
 }
 
 // Returns true if this class loader data is for the platform class loader.
+// (Note that the class loader data may be anonymous.)
 bool ClassLoaderData::is_platform_class_loader_data() const {
   return SystemDictionary::is_platform_class_loader(class_loader());
 }
 
-// Returns true if this class loader data is one of the 3 builtin
-// (boot, application/system or platform) class loaders. Note, the
-// builtin loaders are not freed by a GC.
+// Returns true if the class loader for this class loader data is one of
+// the 3 builtin (boot application/system or platform) class loaders,
+// including a user-defined system class loader.  Note that if the class
+// loader data is for an anonymous class then it may get freed by a GC
+// even if its class loader is one of these loaders.
 bool ClassLoaderData::is_builtin_class_loader_data() const {
-  return (is_the_null_class_loader_data() ||
+  return (is_boot_class_loader_data() ||
           SystemDictionary::is_system_class_loader(class_loader()) ||
           SystemDictionary::is_platform_class_loader(class_loader()));
 }
 
+// Returns true if this class loader data is a class loader data
+// that is not ever freed by a GC.  It must be one of the builtin
+// class loaders and not anonymous.
+bool ClassLoaderData::is_permanent_class_loader_data() const {
+  return is_builtin_class_loader_data() && !is_anonymous();
+}
+
 Metaspace* ClassLoaderData::metaspace_non_null() {
   // If the metaspace has not been allocated, create a new one.  Might want
   // to create smaller arena for Reflection class loaders also.
--- a/src/hotspot/share/classfile/classLoaderData.hpp	Fri Feb 16 12:24:38 2018 -0800
+++ b/src/hotspot/share/classfile/classLoaderData.hpp	Fri Feb 16 13:49:07 2018 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2018, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -80,6 +80,9 @@
   // allocations until class unloading
   static bool _metaspace_oom;
 
+  static volatile size_t  _num_instance_classes;
+  static volatile size_t  _num_array_classes;
+
   static ClassLoaderData* add(Handle class_loader, bool anonymous, TRAPS);
   static void post_class_unload_events();
  public:
@@ -154,6 +157,15 @@
   static void print_creation(outputStream* out, Handle loader, ClassLoaderData* cld, TRAPS);
 
   static bool unload_list_contains(const void* x);
+
+  // instance and array class counters
+  static inline size_t num_instance_classes();
+  static inline size_t num_array_classes();
+  static inline void inc_instance_classes(size_t count);
+  static inline void dec_instance_classes(size_t count);
+  static inline void inc_array_classes(size_t count);
+  static inline void dec_array_classes(size_t count);
+
 #ifndef PRODUCT
   static bool contains_loader_data(ClassLoaderData* loader_data);
 #endif
@@ -344,7 +356,15 @@
   }
   bool is_system_class_loader_data() const;
   bool is_platform_class_loader_data() const;
+
+  // Returns true if this class loader data is for the boot class loader.
+  // (Note that the class loader data may be anonymous.)
+  bool is_boot_class_loader_data() const {
+    return class_loader() == NULL;
+  }
+
   bool is_builtin_class_loader_data() const;
+  bool is_permanent_class_loader_data() const;
 
   // The Metaspace is created lazily so may be NULL.  This
   // method will allocate a Metaspace if needed.
--- a/src/hotspot/share/classfile/classLoaderData.inline.hpp	Fri Feb 16 12:24:38 2018 -0800
+++ b/src/hotspot/share/classfile/classLoaderData.inline.hpp	Fri Feb 16 13:49:07 2018 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 2018, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -50,3 +50,29 @@
   }
   return ClassLoaderDataGraph::add(loader, false, THREAD);
 }
+
+size_t ClassLoaderDataGraph::num_instance_classes() {
+  return _num_instance_classes;
+}
+
+size_t ClassLoaderDataGraph::num_array_classes() {
+  return _num_array_classes;
+}
+
+void ClassLoaderDataGraph::inc_instance_classes(size_t count) {
+  Atomic::add(count, &_num_instance_classes);
+}
+
+void ClassLoaderDataGraph::dec_instance_classes(size_t count) {
+  assert(count <= _num_instance_classes, "Sanity");
+  Atomic::sub(count, &_num_instance_classes);
+}
+
+void ClassLoaderDataGraph::inc_array_classes(size_t count) {
+  Atomic::add(count, &_num_array_classes);
+}
+
+void ClassLoaderDataGraph::dec_array_classes(size_t count) {
+  assert(count <= _num_array_classes, "Sanity");
+  Atomic::sub(count, &_num_array_classes);
+}
--- a/src/hotspot/share/classfile/moduleEntry.hpp	Fri Feb 16 12:24:38 2018 -0800
+++ b/src/hotspot/share/classfile/moduleEntry.hpp	Fri Feb 16 13:49:07 2018 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -103,7 +103,11 @@
   void             set_shared_protection_domain(ClassLoaderData *loader_data, Handle pd);
 
   ClassLoaderData* loader_data() const                 { return _loader_data; }
-  void             set_loader_data(ClassLoaderData* l) { _loader_data = l; }
+
+  void set_loader_data(ClassLoaderData* cld) {
+    assert(!cld->is_anonymous(), "Unexpected anonymous class loader data");
+    _loader_data = cld;
+  }
 
   Symbol*          version() const                     { return _version; }
   void             set_version(Symbol* version);
--- a/src/hotspot/share/code/compiledIC.cpp	Fri Feb 16 12:24:38 2018 -0800
+++ b/src/hotspot/share/code/compiledIC.cpp	Fri Feb 16 13:49:07 2018 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1997, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2018, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -417,7 +417,7 @@
     bool static_bound = info.is_optimized() || (info.cached_metadata() == NULL);
 #ifdef ASSERT
     CodeBlob* cb = CodeCache::find_blob_unsafe(info.entry());
-    assert (cb->is_compiled(), "must be compiled!");
+    assert (cb != NULL && cb->is_compiled(), "must be compiled!");
 #endif /* ASSERT */
 
     // This is MT safe if we come from a clean-cache and go through a
--- a/src/hotspot/share/code/nmethod.cpp	Fri Feb 16 12:24:38 2018 -0800
+++ b/src/hotspot/share/code/nmethod.cpp	Fri Feb 16 13:49:07 2018 -0800
@@ -955,6 +955,7 @@
         CompiledIC *ic = CompiledIC_at(&iter);
         // Ok, to lookup references to zombies here
         CodeBlob *cb = CodeCache::find_blob_unsafe(ic->ic_destination());
+        assert(cb != NULL, "destination not in CodeBlob?");
         nmethod* nm = cb->as_nmethod_or_null();
         if( nm != NULL ) {
           // Verify that inline caches pointing to both zombie and not_entrant methods are clean
@@ -967,6 +968,7 @@
       case relocInfo::static_call_type: {
         CompiledStaticCall *csc = compiledStaticCall_at(iter.reloc());
         CodeBlob *cb = CodeCache::find_blob_unsafe(csc->destination());
+        assert(cb != NULL, "destination not in CodeBlob?");
         nmethod* nm = cb->as_nmethod_or_null();
         if( nm != NULL ) {
           // Verify that inline caches pointing to both zombie and not_entrant methods are clean
@@ -2732,7 +2734,7 @@
 
   virtual void verify_resolve_call(address dest) const {
     CodeBlob* db = CodeCache::find_blob_unsafe(dest);
-    assert(!db->is_adapter_blob(), "must use stub!");
+    assert(db != NULL && !db->is_adapter_blob(), "must use stub!");
   }
 
   virtual bool is_call_to_interpreted(address dest) const {
--- a/src/hotspot/share/gc/shared/oopStorage.cpp	Fri Feb 16 12:24:38 2018 -0800
+++ b/src/hotspot/share/gc/shared/oopStorage.cpp	Fri Feb 16 13:49:07 2018 -0800
@@ -26,7 +26,9 @@
 #include "gc/shared/oopStorage.inline.hpp"
 #include "gc/shared/oopStorageParState.inline.hpp"
 #include "logging/log.hpp"
+#include "logging/logStream.hpp"
 #include "memory/allocation.inline.hpp"
+#include "memory/resourceArea.hpp"
 #include "runtime/atomic.hpp"
 #include "runtime/handles.inline.hpp"
 #include "runtime/mutex.hpp"
@@ -107,7 +109,7 @@
 }
 
 // Blocks start with an array of BitsPerWord oop entries.  That array
-// is divided into conceptual BytesPerWord sections of BitsPerWord
+// is divided into conceptual BytesPerWord sections of BitsPerByte
 // entries.  Blocks are allocated aligned on section boundaries, for
 // the convenience of mapping from an entry to the containing block;
 // see block_for_ptr().  Aligning on section boundary rather than on
@@ -130,7 +132,9 @@
   _owner(owner),
   _memory(memory),
   _active_entry(),
-  _allocate_entry()
+  _allocate_entry(),
+  _deferred_updates_next(NULL),
+  _release_refcount(0)
 {
   STATIC_ASSERT(_data_pos == 0);
   STATIC_ASSERT(section_size * section_count == ARRAY_SIZE(_data));
@@ -143,6 +147,8 @@
 #endif
 
 OopStorage::Block::~Block() {
+  assert(_release_refcount == 0, "deleting block while releasing");
+  assert(_deferred_updates_next == NULL, "deleting block with deferred update");
   // Clear fields used by block_for_ptr and entry validation, which
   // might help catch bugs.  Volatile to prevent dead-store elimination.
   const_cast<uintx volatile&>(_allocated_bitmask) = 0;
@@ -182,8 +188,24 @@
   return bitmask_for_index(get_index(ptr));
 }
 
-uintx OopStorage::Block::cmpxchg_allocated_bitmask(uintx new_value, uintx compare_value) {
-  return Atomic::cmpxchg(new_value, &_allocated_bitmask, compare_value);
+// A block is deletable if
+// (1) It is empty.
+// (2) There is not a release() operation currently operating on it.
+// (3) It is not in the deferred updates list.
+// The order of tests is important for proper interaction between release()
+// and concurrent deletion.
+bool OopStorage::Block::is_deletable() const {
+  return (OrderAccess::load_acquire(&_allocated_bitmask) == 0) &&
+         (OrderAccess::load_acquire(&_release_refcount) == 0) &&
+         (OrderAccess::load_acquire(&_deferred_updates_next) == NULL);
+}
+
+OopStorage::Block* OopStorage::Block::deferred_updates_next() const {
+  return _deferred_updates_next;
+}
+
+void OopStorage::Block::set_deferred_updates_next(Block* block) {
+  _deferred_updates_next = block;
 }
 
 bool OopStorage::Block::contains(const oop* ptr) const {
@@ -203,7 +225,7 @@
     assert(!is_full_bitmask(allocated), "attempt to allocate from full block");
     unsigned index = count_trailing_zeros(~allocated);
     uintx new_value = allocated | bitmask_for_index(index);
-    uintx fetched = cmpxchg_allocated_bitmask(new_value, allocated);
+    uintx fetched = Atomic::cmpxchg(new_value, &_allocated_bitmask, allocated);
     if (fetched == allocated) {
       return get_pointer(index); // CAS succeeded; return entry for index.
     }
@@ -261,20 +283,6 @@
   return NULL;
 }
 
-bool OopStorage::is_valid_block_locked_or_safepoint(const Block* check_block) const {
-  assert_locked_or_safepoint(_allocate_mutex);
-  // For now, simple linear search.  Do something more clever if this
-  // is a performance bottleneck, particularly for allocation_status.
-  for (const Block* block = _active_list.chead();
-       block != NULL;
-       block = _active_list.next(*block)) {
-    if (check_block == block) {
-      return true;
-    }
-  }
-  return false;
-}
-
 #ifdef ASSERT
 void OopStorage::assert_at_safepoint() {
   assert(SafepointSynchronize::is_at_safepoint(), "must be at safepoint");
@@ -291,39 +299,49 @@
 // kept at the end of the _allocate_list, to make it easy for empty block
 // deletion to find them.
 //
-// allocate(), release(), and delete_empty_blocks_concurrent() all lock the
+// allocate(), and delete_empty_blocks_concurrent() lock the
 // _allocate_mutex while performing any list modifications.
 //
 // allocate() and release() update a block's _allocated_bitmask using CAS
-// loops.  This prevents loss of updates even though release() may perform
-// some updates without any locking.
+// loops.  This prevents loss of updates even though release() performs
+// its updates without any locking.
 //
 // allocate() obtains the entry from the first block in the _allocate_list,
 // and updates that block's _allocated_bitmask to indicate the entry is in
 // use.  If this makes the block full (all entries in use), the block is
 // removed from the _allocate_list so it won't be considered by future
-// allocations until some entries in it are relased.
+// allocations until some entries in it are released.
 //
-// release() looks up the block for the entry without locking.  Once the block
-// has been determined, its _allocated_bitmask needs to be updated, and its
-// position in the _allocate_list may need to be updated.  There are two
-// cases:
+// release() is performed lock-free. release() first looks up the block for
+// the entry, using address alignment to find the enclosing block (thereby
+// avoiding iteration over the _active_list).  Once the block has been
+// determined, its _allocated_bitmask needs to be updated, and its position in
+// the _allocate_list may need to be updated.  There are two cases:
 //
 // (a) If the block is neither full nor would become empty with the release of
 // the entry, only its _allocated_bitmask needs to be updated.  But if the CAS
 // update fails, the applicable case may change for the retry.
 //
-// (b) Otherwise, the _allocate_list will also need to be modified.  This
-// requires locking the _allocate_mutex, and then attempting to CAS the
-// _allocated_bitmask.  If the CAS fails, the applicable case may change for
-// the retry.  If the CAS succeeds, then update the _allocate_list according
-// to the the state changes.  If the block changed from full to not full, then
-// it needs to be added to the _allocate_list, for use in future allocations.
-// If the block changed from not empty to empty, then it is moved to the end
-// of the _allocate_list, for ease of empty block deletion processing.
+// (b) Otherwise, the _allocate_list also needs to be modified.  This requires
+// locking the _allocate_mutex.  To keep the release() operation lock-free,
+// rather than updating the _allocate_list itself, it instead performs a
+// lock-free push of the block onto the _deferred_updates list.  Entries on
+// that list are processed by allocate() and delete_empty_blocks_XXX(), while
+// they already hold the necessary lock.  That processing makes the block's
+// list state consistent with its current _allocated_bitmask.  The block is
+// added to the _allocate_list if not already present and the bitmask is not
+// full.  The block is moved to the end of the _allocated_list if the bitmask
+// is empty, for ease of empty block deletion processing.
 
 oop* OopStorage::allocate() {
   MutexLockerEx ml(_allocate_mutex, Mutex::_no_safepoint_check_flag);
+  // Do some deferred update processing every time we allocate.
+  // Continue processing deferred updates if _allocate_list is empty,
+  // in the hope that we'll get a block from that, rather than
+  // allocating a new block.
+  while (reduce_deferred_updates() && (_allocate_list.head() == NULL)) {}
+
+  // Use the first block in _allocate_list for the allocation.
   Block* block = _allocate_list.head();
   if (block == NULL) {
     // No available blocks; make a new one, and add to storage.
@@ -331,7 +349,17 @@
       MutexUnlockerEx mul(_allocate_mutex, Mutex::_no_safepoint_check_flag);
       block = Block::new_block(this);
     }
-    if (block != NULL) {
+    if (block == NULL) {
+      while (_allocate_list.head() == NULL) {
+        if (!reduce_deferred_updates()) {
+          // Failed to make new block, no other thread made a block
+          // available while the mutex was released, and didn't get
+          // one from a deferred update either, so return failure.
+          log_info(oopstorage, ref)("%s: failed allocation", name());
+          return NULL;
+        }
+      }
+    } else {
       // Add new block to storage.
       log_info(oopstorage, blocks)("%s: new block " PTR_FORMAT, name(), p2i(block));
 
@@ -340,22 +368,14 @@
       // to allocate from non-empty blocks, to allow empty blocks to
       // be deleted.
       _allocate_list.push_back(*block);
-      ++_empty_block_count;
       // Add to front of _active_list, and then record as the head
       // block, for concurrent iteration protocol.
       _active_list.push_front(*block);
       ++_block_count;
       // Ensure all setup of block is complete before making it visible.
       OrderAccess::release_store(&_active_head, block);
-    } else {
-      log_info(oopstorage, blocks)("%s: failed new block allocation", name());
     }
     block = _allocate_list.head();
-    if (block == NULL) {
-      // Failed to make new block, and no other thread made a block
-      // available while the mutex was released, so return failure.
-      return NULL;
-    }
   }
   // Allocate from first block.
   assert(block != NULL, "invariant");
@@ -363,7 +383,6 @@
   if (block->is_empty()) {
     // Transitioning from empty to not empty.
     log_debug(oopstorage, blocks)("%s: block not empty " PTR_FORMAT, name(), p2i(block));
-    --_empty_block_count;
   }
   oop* result = block->allocate();
   assert(result != NULL, "allocation failed");
@@ -384,72 +403,115 @@
   return Block::block_for_ptr(this, ptr);
 }
 
-void OopStorage::release_from_block(Block& block, uintx releasing) {
-  assert(releasing != 0, "invariant");
-  uintx allocated = block.allocated_bitmask();
-  while (true) {
-    assert(releasing == (allocated & releasing), "invariant");
-    uintx new_value = allocated ^ releasing;
-    // CAS new_value into block's allocated bitmask, retrying with
-    // updated allocated bitmask until the CAS succeeds.
-    uintx fetched;
-    if (!is_full_bitmask(allocated) && !is_empty_bitmask(new_value)) {
-      fetched = block.cmpxchg_allocated_bitmask(new_value, allocated);
-      if (fetched == allocated) return;
-    } else {
-      // Need special handling if transitioning from full to not full,
-      // or from not empty to empty.  For those cases, must hold the
-      // _allocation_mutex when updating the allocated bitmask, to
-      // ensure the associated list manipulations will be consistent
-      // with the allocation bitmask that is visible to other threads
-      // in allocate() or deleting empty blocks.
-      MutexLockerEx ml(_allocate_mutex, Mutex::_no_safepoint_check_flag);
-      fetched = block.cmpxchg_allocated_bitmask(new_value, allocated);
-      if (fetched == allocated) {
-        // CAS succeeded; handle special cases, which might no longer apply.
-        if (is_full_bitmask(allocated)) {
-          // Transitioning from full to not-full; add to _allocate_list.
-          log_debug(oopstorage, blocks)("%s: block not full " PTR_FORMAT, name(), p2i(&block));
-          _allocate_list.push_front(block);
-          assert(!block.is_full(), "invariant"); // Still not full.
-        }
-        if (is_empty_bitmask(new_value)) {
-          // Transitioning from not-empty to empty; move to end of
-          // _allocate_list, to make it a deletion candidate.
-          log_debug(oopstorage, blocks)("%s: block empty " PTR_FORMAT, name(), p2i(&block));
-          _allocate_list.unlink(block);
-          _allocate_list.push_back(block);
-          ++_empty_block_count;
-          assert(block.is_empty(), "invariant"); // Still empty.
-        }
-        return;                 // Successful CAS and transitions handled.
-      }
-    }
-    // CAS failed; retry with latest value.
-    allocated = fetched;
+static void log_release_transitions(uintx releasing,
+                                    uintx old_allocated,
+                                    const OopStorage* owner,
+                                    const void* block) {
+  ResourceMark rm;
+  Log(oopstorage, blocks) log;
+  LogStream ls(log.debug());
+  if (is_full_bitmask(old_allocated)) {
+    ls.print_cr("%s: block not full " PTR_FORMAT, owner->name(), p2i(block));
+  }
+  if (releasing == old_allocated) {
+    ls.print_cr("%s: block empty " PTR_FORMAT, owner->name(), p2i(block));
   }
 }
 
-#ifdef ASSERT
-void OopStorage::check_release(const Block* block, const oop* ptr) const {
-  switch (allocation_status_validating_block(block, ptr)) {
-  case INVALID_ENTRY:
-    fatal("Releasing invalid entry: " PTR_FORMAT, p2i(ptr));
-    break;
+void OopStorage::Block::release_entries(uintx releasing, Block* volatile* deferred_list) {
+  assert(releasing != 0, "preconditon");
+  // Prevent empty block deletion when transitioning to empty.
+  Atomic::inc(&_release_refcount);
+
+  // Atomically update allocated bitmask.
+  uintx old_allocated = _allocated_bitmask;
+  while (true) {
+    assert((releasing & ~old_allocated) == 0, "releasing unallocated entries");
+    uintx new_value = old_allocated ^ releasing;
+    uintx fetched = Atomic::cmpxchg(new_value, &_allocated_bitmask, old_allocated);
+    if (fetched == old_allocated) break; // Successful update.
+    old_allocated = fetched;             // Retry with updated bitmask.
+  }
 
-  case UNALLOCATED_ENTRY:
-    fatal("Releasing unallocated entry: " PTR_FORMAT, p2i(ptr));
-    break;
+  // Now that the bitmask has been updated, if we have a state transition
+  // (updated bitmask is empty or old bitmask was full), atomically push
+  // this block onto the deferred updates list.  Some future call to
+  // reduce_deferred_updates will make any needed changes related to this
+  // block and _allocate_list.  This deferral avoids list updates and the
+  // associated locking here.
+  if ((releasing == old_allocated) || is_full_bitmask(old_allocated)) {
+    // Log transitions.  Both transitions are possible in a single update.
+    if (log_is_enabled(Debug, oopstorage, blocks)) {
+      log_release_transitions(releasing, old_allocated, _owner, this);
+    }
+    // Attempt to claim responsibility for adding this block to the deferred
+    // list, by setting the link to non-NULL by self-looping.  If this fails,
+    // then someone else has made such a claim and the deferred update has not
+    // yet been processed and will include our change, so we don't need to do
+    // anything further.
+    if (Atomic::replace_if_null(this, &_deferred_updates_next)) {
+      // Successfully claimed.  Push, with self-loop for end-of-list.
+      Block* head = *deferred_list;
+      while (true) {
+        _deferred_updates_next = (head == NULL) ? this : head;
+        Block* fetched = Atomic::cmpxchg(this, deferred_list, head);
+        if (fetched == head) break; // Successful update.
+        head = fetched;             // Retry with updated head.
+      }
+      log_debug(oopstorage, blocks)("%s: deferred update " PTR_FORMAT,
+                                    _owner->name(), p2i(this));
+    }
+  }
+  // Release hold on empty block deletion.
+  Atomic::dec(&_release_refcount);
+}
 
-  case ALLOCATED_ENTRY:
-    assert(block->contains(ptr), "invariant");
-    break;
+// Process one available deferred update.  Returns true if one was processed.
+bool OopStorage::reduce_deferred_updates() {
+  assert_locked_or_safepoint(_allocate_mutex);
+  // Atomically pop a block off the list, if any available.
+  // No ABA issue because this is only called by one thread at a time.
+  // The atomicity is wrto pushes by release().
+  Block* block = OrderAccess::load_acquire(&_deferred_updates);
+  while (true) {
+    if (block == NULL) return false;
+    // Try atomic pop of block from list.
+    Block* tail = block->deferred_updates_next();
+    if (block == tail) tail = NULL; // Handle self-loop end marker.
+    Block* fetched = Atomic::cmpxchg(tail, &_deferred_updates, block);
+    if (fetched == block) break; // Update successful.
+    block = fetched;             // Retry with updated block.
+  }
+  block->set_deferred_updates_next(NULL); // Clear tail after updating head.
+  // Ensure bitmask read after pop is complete, including clearing tail, for
+  // ordering with release().  Without this, we may be processing a stale
+  // bitmask state here while blocking a release() operation from recording
+  // the deferred update needed for its bitmask change.
+  OrderAccess::storeload();
+  // Process popped block.
+  uintx allocated = block->allocated_bitmask();
 
-  default:
-    ShouldNotReachHere();
+  // Make membership in list consistent with bitmask state.
+  if ((_allocate_list.ctail() != NULL) &&
+      ((_allocate_list.ctail() == block) ||
+       (_allocate_list.next(*block) != NULL))) {
+    // Block is in the allocate list.
+    assert(!is_full_bitmask(allocated), "invariant");
+  } else if (!is_full_bitmask(allocated)) {
+    // Block is not in the allocate list, but now should be.
+    _allocate_list.push_front(*block);
+  } // Else block is full and not in list, which is correct.
+
+  // Move empty block to end of list, for possible deletion.
+  if (is_empty_bitmask(allocated)) {
+    _allocate_list.unlink(*block);
+    _allocate_list.push_back(*block);
   }
+
+  log_debug(oopstorage, blocks)("%s: processed deferred update " PTR_FORMAT,
+                                name(), p2i(block));
+  return true;              // Processed one pending update.
 }
-#endif // ASSERT
 
 inline void check_release_entry(const oop* entry) {
   assert(entry != NULL, "Releasing NULL");
@@ -459,9 +521,9 @@
 void OopStorage::release(const oop* ptr) {
   check_release_entry(ptr);
   Block* block = find_block_or_null(ptr);
-  check_release(block, ptr);
+  assert(block != NULL, "%s: invalid release " PTR_FORMAT, name(), p2i(ptr));
   log_info(oopstorage, ref)("%s: released " PTR_FORMAT, name(), p2i(ptr));
-  release_from_block(*block, block->bitmask_for_entry(ptr));
+  block->release_entries(block->bitmask_for_entry(ptr), &_deferred_updates);
   Atomic::dec(&_allocation_count);
 }
 
@@ -470,15 +532,15 @@
   while (i < size) {
     check_release_entry(ptrs[i]);
     Block* block = find_block_or_null(ptrs[i]);
-    check_release(block, ptrs[i]);
+    assert(block != NULL, "%s: invalid release " PTR_FORMAT, name(), p2i(ptrs[i]));
     log_info(oopstorage, ref)("%s: released " PTR_FORMAT, name(), p2i(ptrs[i]));
     size_t count = 0;
     uintx releasing = 0;
     for ( ; i < size; ++i) {
       const oop* entry = ptrs[i];
+      check_release_entry(entry);
       // If entry not in block, finish block and resume outer loop with entry.
       if (!block->contains(entry)) break;
-      check_release_entry(entry);
       // Add entry to releasing bitmap.
       log_info(oopstorage, ref)("%s: released " PTR_FORMAT, name(), p2i(entry));
       uintx entry_bitmask = block->bitmask_for_entry(entry);
@@ -488,7 +550,7 @@
       ++count;
     }
     // Release the contiguous entries that are in block.
-    release_from_block(*block, releasing);
+    block->release_entries(releasing, &_deferred_updates);
     Atomic::sub(count, &_allocation_count);
   }
 }
@@ -506,11 +568,11 @@
   _active_list(&Block::get_active_entry),
   _allocate_list(&Block::get_allocate_entry),
   _active_head(NULL),
+  _deferred_updates(NULL),
   _allocate_mutex(allocate_mutex),
   _active_mutex(active_mutex),
   _allocation_count(0),
   _block_count(0),
-  _empty_block_count(0),
   _concurrent_iteration_active(false)
 {
   assert(_active_mutex->rank() < _allocate_mutex->rank(),
@@ -529,6 +591,10 @@
 
 OopStorage::~OopStorage() {
   Block* block;
+  while ((block = _deferred_updates) != NULL) {
+    _deferred_updates = block->deferred_updates_next();
+    block->set_deferred_updates_next(NULL);
+  }
   while ((block = _allocate_list.head()) != NULL) {
     _allocate_list.unlink(*block);
   }
@@ -539,43 +605,47 @@
   FREE_C_HEAP_ARRAY(char, _name);
 }
 
-void OopStorage::delete_empty_blocks_safepoint(size_t retain) {
+void OopStorage::delete_empty_blocks_safepoint() {
   assert_at_safepoint();
+  // Process any pending release updates, which may make more empty
+  // blocks available for deletion.
+  while (reduce_deferred_updates()) {}
   // Don't interfere with a concurrent iteration.
   if (_concurrent_iteration_active) return;
-  // Compute the number of blocks to remove, to minimize volatile accesses.
-  size_t empty_blocks = _empty_block_count;
-  if (retain < empty_blocks) {
-    size_t remove_count = empty_blocks - retain;
-    // Update volatile counters once.
-    _block_count -= remove_count;
-    _empty_block_count -= remove_count;
-    do {
-      const Block* block = _allocate_list.ctail();
-      assert(block != NULL, "invariant");
-      assert(block->is_empty(), "invariant");
-      // Remove block from lists, and delete it.
-      _active_list.unlink(*block);
-      _allocate_list.unlink(*block);
-      delete_empty_block(*block);
-    } while (--remove_count > 0);
-    // Update _active_head, in case current value was in deleted set.
-    _active_head = _active_list.head();
+  // Delete empty (and otherwise deletable) blocks from end of _allocate_list.
+  for (const Block* block = _allocate_list.ctail();
+       (block != NULL) && block->is_deletable();
+       block = _allocate_list.ctail()) {
+    _active_list.unlink(*block);
+    _allocate_list.unlink(*block);
+    delete_empty_block(*block);
+    --_block_count;
   }
+  // Update _active_head, in case current value was in deleted set.
+  _active_head = _active_list.head();
 }
 
-void OopStorage::delete_empty_blocks_concurrent(size_t retain) {
+void OopStorage::delete_empty_blocks_concurrent() {
   MutexLockerEx ml(_allocate_mutex, Mutex::_no_safepoint_check_flag);
   // Other threads could be adding to the empty block count while we
   // release the mutex across the block deletions.  Set an upper bound
   // on how many blocks we'll try to release, so other threads can't
   // cause an unbounded stay in this function.
-  if (_empty_block_count <= retain) return;
-  size_t limit = _empty_block_count - retain;
-  for (size_t i = 0; (i < limit) && (retain < _empty_block_count); ++i) {
+  size_t limit = _block_count;
+
+  for (size_t i = 0; i < limit; ++i) {
+    // Additional updates might become available while we dropped the
+    // lock.  But limit number processed to limit lock duration.
+    reduce_deferred_updates();
+
     const Block* block = _allocate_list.ctail();
-    assert(block != NULL, "invariant");
-    assert(block->is_empty(), "invariant");
+    if ((block == NULL) || !block->is_deletable()) {
+      // No block to delete, so done.  There could be more pending
+      // deferred updates that could give us more work to do; deal with
+      // that in some later call, to limit lock duration here.
+      return;
+    }
+
     {
       MutexLockerEx aml(_active_mutex, Mutex::_no_safepoint_check_flag);
       // Don't interfere with a concurrent iteration.
@@ -589,28 +659,31 @@
     }
     // Remove block from _allocate_list and delete it.
     _allocate_list.unlink(*block);
-    --_empty_block_count;
     // Release mutex while deleting block.
     MutexUnlockerEx ul(_allocate_mutex, Mutex::_no_safepoint_check_flag);
     delete_empty_block(*block);
   }
 }
 
-OopStorage::EntryStatus
-OopStorage::allocation_status_validating_block(const Block* block,
-                                               const oop* ptr) const {
-  MutexLockerEx ml(_allocate_mutex, Mutex::_no_safepoint_check_flag);
-  if ((block == NULL) || !is_valid_block_locked_or_safepoint(block)) {
-    return INVALID_ENTRY;
-  } else if ((block->allocated_bitmask() & block->bitmask_for_entry(ptr)) != 0) {
-    return ALLOCATED_ENTRY;
-  } else {
-    return UNALLOCATED_ENTRY;
+OopStorage::EntryStatus OopStorage::allocation_status(const oop* ptr) const {
+  const Block* block = find_block_or_null(ptr);
+  if (block != NULL) {
+    // Verify block is a real block.  For now, simple linear search.
+    // Do something more clever if this is a performance bottleneck.
+    MutexLockerEx ml(_allocate_mutex, Mutex::_no_safepoint_check_flag);
+    for (const Block* check_block = _active_list.chead();
+         check_block != NULL;
+         check_block = _active_list.next(*check_block)) {
+      if (check_block == block) {
+        if ((block->allocated_bitmask() & block->bitmask_for_entry(ptr)) != 0) {
+          return ALLOCATED_ENTRY;
+        } else {
+          return UNALLOCATED_ENTRY;
+        }
+      }
+    }
   }
-}
-
-OopStorage::EntryStatus OopStorage::allocation_status(const oop* ptr) const {
-  return allocation_status_validating_block(find_block_or_null(ptr), ptr);
+  return INVALID_ENTRY;
 }
 
 size_t OopStorage::allocation_count() const {
@@ -621,10 +694,6 @@
   return _block_count;
 }
 
-size_t OopStorage::empty_block_count() const {
-  return _empty_block_count;
-}
-
 size_t OopStorage::total_memory_usage() const {
   size_t total_size = sizeof(OopStorage);
   total_size += strlen(name()) + 1;
@@ -690,17 +759,12 @@
 void OopStorage::print_on(outputStream* st) const {
   size_t allocations = _allocation_count;
   size_t blocks = _block_count;
-  size_t empties = _empty_block_count;
-  // Comparison is being careful about racy accesses.
-  size_t used = (blocks < empties) ? 0 : (blocks - empties);
 
   double data_size = section_size * section_count;
-  double alloc_percentage = percent_of((double)allocations, used * data_size);
+  double alloc_percentage = percent_of((double)allocations, blocks * data_size);
 
-  st->print("%s: " SIZE_FORMAT " entries in " SIZE_FORMAT " blocks (%.F%%), "
-            SIZE_FORMAT " empties, " SIZE_FORMAT " bytes",
-            name(), allocations, used, alloc_percentage,
-            empties, total_memory_usage());
+  st->print("%s: " SIZE_FORMAT " entries in " SIZE_FORMAT " blocks (%.F%%), " SIZE_FORMAT " bytes",
+            name(), allocations, blocks, alloc_percentage, total_memory_usage());
   if (_concurrent_iteration_active) {
     st->print(", concurrent iteration active");
   }
--- a/src/hotspot/share/gc/shared/oopStorage.hpp	Fri Feb 16 12:24:38 2018 -0800
+++ b/src/hotspot/share/gc/shared/oopStorage.hpp	Fri Feb 16 13:49:07 2018 -0800
@@ -84,10 +84,6 @@
   // The number of blocks of entries.  Useful for sizing parallel iteration.
   size_t block_count() const;
 
-  // The number of blocks with no allocated entries.  Useful for sizing
-  // parallel iteration and scheduling block deletion.
-  size_t empty_block_count() const;
-
   // Total number of blocks * memory allocation per block, plus
   // bookkeeping overhead, including this storage object.
   size_t total_memory_usage() const;
@@ -107,14 +103,13 @@
   // postcondition: *result == NULL.
   oop* allocate();
 
-  // Deallocates ptr, after setting its value to NULL. Locks _allocate_mutex.
+  // Deallocates ptr.  No locking.
   // precondition: ptr is a valid allocated entry.
   // precondition: *ptr == NULL.
   void release(const oop* ptr);
 
   // Releases all the ptrs.  Possibly faster than individual calls to
-  // release(oop*).  Best if ptrs is sorted by address.  Locks
-  // _allocate_mutex.
+  // release(oop*).  Best if ptrs is sorted by address.  No locking.
   // precondition: All elements of ptrs are valid allocated entries.
   // precondition: *ptrs[i] == NULL, for i in [0,size).
   void release(const oop* const* ptrs, size_t size);
@@ -160,8 +155,8 @@
   // Block cleanup functions are for the exclusive use of the GC.
   // Both stop deleting if there is an in-progress concurrent iteration.
   // Concurrent deletion locks both the allocate_mutex and the active_mutex.
-  void delete_empty_blocks_safepoint(size_t retain = 1);
-  void delete_empty_blocks_concurrent(size_t retain = 1);
+  void delete_empty_blocks_safepoint();
+  void delete_empty_blocks_concurrent();
 
   // Debugging and logging support.
   const char* name() const;
@@ -231,6 +226,7 @@
   BlockList _active_list;
   BlockList _allocate_list;
   Block* volatile _active_head;
+  Block* volatile _deferred_updates;
 
   Mutex* _allocate_mutex;
   Mutex* _active_mutex;
@@ -238,16 +234,12 @@
   // Counts are volatile for racy unlocked accesses.
   volatile size_t _allocation_count;
   volatile size_t _block_count;
-  volatile size_t _empty_block_count;
   // mutable because this gets set even for const iteration.
   mutable bool _concurrent_iteration_active;
 
   Block* find_block_or_null(const oop* ptr) const;
-  bool is_valid_block_locked_or_safepoint(const Block* block) const;
-  EntryStatus allocation_status_validating_block(const Block* block, const oop* ptr) const;
-  void check_release(const Block* block, const oop* ptr) const NOT_DEBUG_RETURN;
-  void release_from_block(Block& block, uintx release_bitmask);
   void delete_empty_block(const Block& block);
+  bool reduce_deferred_updates();
 
   static void assert_at_safepoint() NOT_DEBUG_RETURN;
 
--- a/src/hotspot/share/gc/shared/oopStorage.inline.hpp	Fri Feb 16 12:24:38 2018 -0800
+++ b/src/hotspot/share/gc/shared/oopStorage.inline.hpp	Fri Feb 16 13:49:07 2018 -0800
@@ -44,6 +44,8 @@
   void* _memory;              // Unaligned storage containing block.
   BlockEntry _active_entry;
   BlockEntry _allocate_entry;
+  Block* volatile _deferred_updates_next;
+  volatile uintx _release_refcount;
 
   Block(const OopStorage* owner, void* memory);
   ~Block();
@@ -75,7 +77,10 @@
   bool is_full() const;
   bool is_empty() const;
   uintx allocated_bitmask() const;
-  uintx cmpxchg_allocated_bitmask(uintx new_value, uintx compare_value);
+  bool is_deletable() const;
+
+  Block* deferred_updates_next() const;
+  void set_deferred_updates_next(Block* new_next);
 
   bool contains(const oop* ptr) const;
 
@@ -86,6 +91,8 @@
   static Block* new_block(const OopStorage* owner);
   static void delete_block(const Block& block);
 
+  void release_entries(uintx releasing, Block* volatile* deferred_list);
+
   template<typename F> bool iterate(F f);
   template<typename F> bool iterate(F f) const;
 }; // class Block
--- a/src/hotspot/share/interpreter/bytecodeInterpreter.cpp	Fri Feb 16 12:24:38 2018 -0800
+++ b/src/hotspot/share/interpreter/bytecodeInterpreter.cpp	Fri Feb 16 13:49:07 2018 -0800
@@ -594,10 +594,6 @@
     VERIFY_OOP(rcvr);
   }
 #endif
-// #define HACK
-#ifdef HACK
-  bool interesting = false;
-#endif // HACK
 
   /* QQQ this should be a stack method so we don't know actual direction */
   guarantee(istate->msg() == initialize ||
@@ -649,19 +645,6 @@
         os::breakpoint();
       }
 
-#ifdef HACK
-      {
-        ResourceMark rm;
-        char *method_name = istate->method()->name_and_sig_as_C_string();
-        if (strstr(method_name, "runThese$TestRunner.run()V") != NULL) {
-          tty->print_cr("entering: depth %d bci: %d",
-                         (istate->_stack_base - istate->_stack),
-                         istate->_bcp - istate->_method->code_base());
-          interesting = true;
-        }
-      }
-#endif // HACK
-
       // Lock method if synchronized.
       if (METHOD->is_synchronized()) {
         // oop rcvr = locals[0].j.r;
@@ -793,18 +776,6 @@
         // resume
         os::breakpoint();
       }
-#ifdef HACK
-      {
-        ResourceMark rm;
-        char *method_name = istate->method()->name_and_sig_as_C_string();
-        if (strstr(method_name, "runThese$TestRunner.run()V") != NULL) {
-          tty->print_cr("resume: depth %d bci: %d",
-                         (istate->_stack_base - istate->_stack) ,
-                         istate->_bcp - istate->_method->code_base());
-          interesting = true;
-        }
-      }
-#endif // HACK
       // returned from a java call, continue executing.
       if (THREAD->pop_frame_pending() && !THREAD->pop_frame_in_process()) {
         goto handle_Pop_Frame;
--- a/src/hotspot/share/logging/logTag.hpp	Fri Feb 16 12:24:38 2018 -0800
+++ b/src/hotspot/share/logging/logTag.hpp	Fri Feb 16 13:49:07 2018 -0800
@@ -66,6 +66,7 @@
   LOG_TAG(exceptions) \
   LOG_TAG(exit) \
   LOG_TAG(fingerprint) \
+  LOG_TAG(free) \
   LOG_TAG(freelist) \
   LOG_TAG(gc) \
   LOG_TAG(handshake) \
@@ -85,6 +86,7 @@
   LOG_TAG(load) /* Trace all classes loaded */ \
   LOG_TAG(loader) \
   LOG_TAG(logging) \
+  LOG_TAG(malloc) \
   LOG_TAG(mark) \
   LOG_TAG(marking) \
   LOG_TAG(membername) \
--- a/src/hotspot/share/memory/allocation.cpp	Fri Feb 16 12:24:38 2018 -0800
+++ b/src/hotspot/share/memory/allocation.cpp	Fri Feb 16 13:49:07 2018 -0800
@@ -210,18 +210,6 @@
 }
 #endif // ASSERT
 
-
-void trace_heap_malloc(size_t size, const char* name, void* p) {
-  // A lock is not needed here - tty uses a lock internally
-  tty->print_cr("Heap malloc " INTPTR_FORMAT " " SIZE_FORMAT " %s", p2i(p), size, name == NULL ? "" : name);
-}
-
-
-void trace_heap_free(void* p) {
-  // A lock is not needed here - tty uses a lock internally
-  tty->print_cr("Heap free   " INTPTR_FORMAT, p2i(p));
-}
-
 //--------------------------------------------------------------------------------------
 // Non-product code
 
--- a/src/hotspot/share/memory/allocation.inline.hpp	Fri Feb 16 12:24:38 2018 -0800
+++ b/src/hotspot/share/memory/allocation.inline.hpp	Fri Feb 16 13:49:07 2018 -0800
@@ -33,9 +33,6 @@
 
 // Explicit C-heap memory management
 
-void trace_heap_malloc(size_t size, const char* name, void *p);
-void trace_heap_free(void *p);
-
 #ifndef PRODUCT
 // Increments unsigned long value for statistics (not atomic on MP).
 inline void inc_stat_counter(volatile julong* dest, julong add_value) {
@@ -56,9 +53,6 @@
     const NativeCallStack& stack,
     AllocFailType alloc_failmode = AllocFailStrategy::EXIT_OOM) {
   char* p = (char*) os::malloc(size, flags, stack);
-  #ifdef ASSERT
-  if (PrintMallocFree) trace_heap_malloc(size, "AllocateHeap", p);
-  #endif
   if (p == NULL && alloc_failmode == AllocFailStrategy::EXIT_OOM) {
     vm_exit_out_of_memory(size, OOM_MALLOC_ERROR, "AllocateHeap");
   }
@@ -73,9 +67,6 @@
 ALWAYSINLINE char* ReallocateHeap(char *old, size_t size, MEMFLAGS flag,
     AllocFailType alloc_failmode = AllocFailStrategy::EXIT_OOM) {
   char* p = (char*) os::realloc(old, size, flag, CURRENT_PC);
-  #ifdef ASSERT
-  if (PrintMallocFree) trace_heap_malloc(size, "ReallocateHeap", p);
-  #endif
   if (p == NULL && alloc_failmode == AllocFailStrategy::EXIT_OOM) {
     vm_exit_out_of_memory(size, OOM_MALLOC_ERROR, "ReallocateHeap");
   }
@@ -83,20 +74,13 @@
 }
 
 inline void FreeHeap(void* p) {
-  #ifdef ASSERT
-  if (PrintMallocFree) trace_heap_free(p);
-  #endif
   os::free(p);
 }
 
 
 template <MEMFLAGS F> void* CHeapObj<F>::operator new(size_t size,
       const NativeCallStack& stack) throw() {
-  void* p = (void*)AllocateHeap(size, F, stack);
-#ifdef ASSERT
-  if (PrintMallocFree) trace_heap_malloc(size, "CHeapObj-new", p);
-#endif
-  return p;
+  return (void*)AllocateHeap(size, F, stack);
 }
 
 template <MEMFLAGS F> void* CHeapObj<F>::operator new(size_t size) throw() {
@@ -104,14 +88,9 @@
 }
 
 template <MEMFLAGS F> void* CHeapObj<F>::operator new (size_t size,
-  const std::nothrow_t&  nothrow_constant, const NativeCallStack& stack) throw() {
-  void* p = (void*)AllocateHeap(size, F, stack,
-      AllocFailStrategy::RETURN_NULL);
-#ifdef ASSERT
-    if (PrintMallocFree) trace_heap_malloc(size, "CHeapObj-new", p);
-#endif
-    return p;
-  }
+      const std::nothrow_t&  nothrow_constant, const NativeCallStack& stack) throw() {
+  return (void*)AllocateHeap(size, F, stack, AllocFailStrategy::RETURN_NULL);
+}
 
 template <MEMFLAGS F> void* CHeapObj<F>::operator new (size_t size,
   const std::nothrow_t& nothrow_constant) throw() {
--- a/src/hotspot/share/memory/arena.cpp	Fri Feb 16 12:24:38 2018 -0800
+++ b/src/hotspot/share/memory/arena.cpp	Fri Feb 16 13:49:07 2018 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2017, 2018, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -299,23 +299,11 @@
 
   // dynamic memory type binding
 void* Arena::operator new(size_t size, MEMFLAGS flags) throw() {
-#ifdef ASSERT
-  void* p = (void*)AllocateHeap(size, flags, CALLER_PC);
-  if (PrintMallocFree) trace_heap_malloc(size, "Arena-new", p);
-  return p;
-#else
   return (void *) AllocateHeap(size, flags, CALLER_PC);
-#endif
 }
 
 void* Arena::operator new(size_t size, const std::nothrow_t& nothrow_constant, MEMFLAGS flags) throw() {
-#ifdef ASSERT
-  void* p = os::malloc(size, flags, CALLER_PC);
-  if (PrintMallocFree) trace_heap_malloc(size, "Arena-new", p);
-  return p;
-#else
-  return os::malloc(size, flags, CALLER_PC);
-#endif
+  return (void*)AllocateHeap(size, flags, CALLER_PC, AllocFailStrategy::RETURN_NULL);
 }
 
 void Arena::operator delete(void* p) {
--- a/src/hotspot/share/oops/instanceKlass.cpp	Fri Feb 16 12:24:38 2018 -0800
+++ b/src/hotspot/share/oops/instanceKlass.cpp	Fri Feb 16 13:49:07 2018 -0800
@@ -124,8 +124,6 @@
 
 #endif //  ndef DTRACE_ENABLED
 
-volatile int InstanceKlass::_total_instanceKlass_count = 0;
-
 static inline bool is_class_loader(const Symbol* class_name,
                                    const ClassFileParser& parser) {
   assert(class_name != NULL, "invariant");
@@ -193,8 +191,6 @@
   // Add all classes to our internal class loader list here,
   // including classes in the bootstrap (NULL) class loader.
   loader_data->add_class(ik, publicize);
-  Atomic::inc(&_total_instanceKlass_count);
-
   return ik;
 }
 
@@ -2241,9 +2237,6 @@
   // class can't be referenced anymore).
   if (_array_name != NULL)  _array_name->decrement_refcount();
   if (_source_debug_extension != NULL) FREE_C_HEAP_ARRAY(char, _source_debug_extension);
-
-  assert(_total_instanceKlass_count >= 1, "Sanity check");
-  Atomic::dec(&_total_instanceKlass_count);
 }
 
 void InstanceKlass::set_source_debug_extension(const char* array, int length) {
--- a/src/hotspot/share/oops/instanceKlass.hpp	Fri Feb 16 12:24:38 2018 -0800
+++ b/src/hotspot/share/oops/instanceKlass.hpp	Fri Feb 16 13:49:07 2018 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1997, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2018, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -135,10 +135,7 @@
     initialization_error                // error happened during initialization
   };
 
-  static int number_of_instance_classes() { return _total_instanceKlass_count; }
-
  private:
-  static volatile int _total_instanceKlass_count;
   static InstanceKlass* allocate_instance_klass(const ClassFileParser& parser, TRAPS);
 
  protected:
--- a/src/hotspot/share/opto/escape.cpp	Fri Feb 16 12:24:38 2018 -0800
+++ b/src/hotspot/share/opto/escape.cpp	Fri Feb 16 13:49:07 2018 -0800
@@ -3226,7 +3226,7 @@
                n->Opcode() == Op_EncodeISOArray) {
       // get the memory projection
       n = n->find_out_with(Op_SCMemProj);
-      assert(n->Opcode() == Op_SCMemProj, "memory projection required");
+      assert(n != NULL && n->Opcode() == Op_SCMemProj, "memory projection required");
     } else {
       assert(n->is_Mem(), "memory node required.");
       Node *addr = n->in(MemNode::Address);
@@ -3250,7 +3250,7 @@
       } else if (n->is_LoadStore()) {
         // get the memory projection
         n = n->find_out_with(Op_SCMemProj);
-        assert(n->Opcode() == Op_SCMemProj, "memory projection required");
+        assert(n != NULL && n->Opcode() == Op_SCMemProj, "memory projection required");
       }
     }
     // push user on appropriate worklist
--- a/src/hotspot/share/opto/parse2.cpp	Fri Feb 16 12:24:38 2018 -0800
+++ b/src/hotspot/share/opto/parse2.cpp	Fri Feb 16 13:49:07 2018 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1998, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1998, 2018, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -2264,7 +2264,7 @@
     ciMethodData* methodData = method()->method_data();
     if (!methodData->is_mature())  break;
     ciProfileData* data = methodData->bci_to_data(bci());
-    assert( data->is_JumpData(), "" );
+    assert(data != NULL && data->is_JumpData(), "need JumpData for taken branch");
     int taken = ((ciJumpData*)data)->taken();
     taken = method()->scale_count(taken);
     target_block->set_count(taken);
--- a/src/hotspot/share/opto/parseHelper.cpp	Fri Feb 16 12:24:38 2018 -0800
+++ b/src/hotspot/share/opto/parseHelper.cpp	Fri Feb 16 13:49:07 2018 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1998, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1998, 2018, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -459,7 +459,7 @@
     ciMethodData* md = method()->method_data();
     assert(md != NULL, "expected valid ciMethodData");
     ciProfileData* data = md->bci_to_data(cur_bci);
-    assert(data->is_JumpData(), "need JumpData for taken branch");
+    assert(data != NULL && data->is_JumpData(), "need JumpData for taken branch");
     increment_md_counter_at(md, data, JumpData::taken_offset());
   }
 
@@ -470,6 +470,7 @@
     ciMethodData* md = method()->method_data();
     if (osr_site) {
       ciProfileData* data = md->bci_to_data(cur_bci);
+      assert(data != NULL && data->is_JumpData(), "need JumpData for taken branch");
       int limit = (CompileThreshold
                    * (OnStackReplacePercentage - InterpreterProfilePercentage)) / 100;
       test_for_osr_md_counter_at(md, data, JumpData::taken_offset(), limit);
@@ -495,7 +496,7 @@
     ciMethodData* md = method()->method_data();
     assert(md != NULL, "expected valid ciMethodData");
     ciProfileData* data = md->bci_to_data(bci());
-    assert(data->is_BranchData(), "need BranchData for not taken branch");
+    assert(data != NULL && data->is_BranchData(), "need BranchData for not taken branch");
     increment_md_counter_at(md, data, BranchData::not_taken_offset());
   }
 
@@ -526,7 +527,7 @@
   ciMethodData* md = method()->method_data();
   assert(md != NULL, "expected valid ciMethodData");
   ciProfileData* data = md->bci_to_data(bci());
-  assert(data->is_CounterData(), "need CounterData for not taken branch");
+  assert(data != NULL && data->is_CounterData(), "need CounterData for not taken branch");
   increment_md_counter_at(md, data, CounterData::count_offset());
 }
 
@@ -537,7 +538,7 @@
   ciMethodData* md = method()->method_data();
   assert(md != NULL, "expected valid ciMethodData");
   ciProfileData* data = md->bci_to_data(bci());
-  assert(data->is_ReceiverTypeData(), "need ReceiverTypeData here");
+  assert(data != NULL && data->is_ReceiverTypeData(), "need ReceiverTypeData here");
 
   // Skip if we aren't tracking receivers
   if (TypeProfileWidth < 1) {
@@ -568,7 +569,7 @@
   ciMethodData* md = method()->method_data();
   assert(md != NULL, "expected valid ciMethodData");
   ciProfileData* data = md->bci_to_data(bci());
-  assert(data->is_RetData(), "need RetData for ret");
+  assert(data != NULL && data->is_RetData(), "need RetData for ret");
   ciRetData* ret_data = (ciRetData*)data->as_RetData();
 
   // Look for the target_bci is already in the table
@@ -601,7 +602,7 @@
   ciMethodData* md = method()->method_data();
   assert(md != NULL, "expected valid ciMethodData");
   ciProfileData* data = md->bci_to_data(bci());
-  assert(data->is_BitData(), "need BitData for checkcast");
+  assert(data != NULL && data->is_BitData(), "need BitData for checkcast");
   set_md_flag_at(md, data, BitData::null_seen_byte_constant());
 }
 
@@ -613,7 +614,7 @@
   assert(md != NULL, "expected valid ciMethodData");
 
   ciProfileData* data = md->bci_to_data(bci());
-  assert(data->is_MultiBranchData(), "need MultiBranchData for switch case");
+  assert(data != NULL && data->is_MultiBranchData(), "need MultiBranchData for switch case");
   if (table_index >= 0) {
     increment_md_counter_at(md, data, MultiBranchData::case_count_offset(table_index));
   } else {
--- a/src/hotspot/share/prims/jvmtiExport.cpp	Fri Feb 16 12:24:38 2018 -0800
+++ b/src/hotspot/share/prims/jvmtiExport.cpp	Fri Feb 16 13:49:07 2018 -0800
@@ -597,12 +597,10 @@
 }
 
 void JvmtiExport::enter_early_start_phase() {
-  JvmtiManageCapabilities::recompute_always_capabilities();
   set_early_vmstart_recorded(true);
 }
 
 void JvmtiExport::enter_start_phase() {
-  JvmtiManageCapabilities::recompute_always_capabilities();
   JvmtiEnvBase::set_phase(JVMTI_PHASE_START);
 }
 
--- a/src/hotspot/share/prims/jvmtiGetLoadedClasses.cpp	Fri Feb 16 12:24:38 2018 -0800
+++ b/src/hotspot/share/prims/jvmtiGetLoadedClasses.cpp	Fri Feb 16 13:49:07 2018 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2003, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2018, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -29,6 +29,9 @@
 #include "prims/jvmtiGetLoadedClasses.hpp"
 #include "runtime/thread.hpp"
 #include "utilities/stack.inline.hpp"
+#if INCLUDE_ALL_GCS
+#include "gc/g1/g1SATBCardTableModRefBS.hpp"
+#endif
 
 
 // The closure for GetLoadedClasses
@@ -38,6 +41,20 @@
   JvmtiEnv* _env;
   Thread*   _cur_thread;
 
+// Tell the GC to keep this klass alive
+static void ensure_klass_alive(oop o) {
+  // A klass that was previously considered dead can be looked up in the
+  // CLD/SD, and its _java_mirror or _class_loader can be stored in a root
+  // or a reachable object making it alive again. The SATB part of G1 needs
+  // to get notified about this potential resurrection, otherwise the marking
+  // might not find the object.
+#if INCLUDE_ALL_GCS
+  if (UseG1GC && o != NULL) {
+    G1SATBCardTableModRefBS::enqueue(o);
+  }
+#endif
+}
+
 public:
   LoadedClassesClosure(Thread* thread, JvmtiEnv* env) : _cur_thread(thread), _env(env) {
     assert(_cur_thread == Thread::current(), "must be current thread");
@@ -46,6 +63,7 @@
   void do_klass(Klass* k) {
     // Collect all jclasses
     _classStack.push((jclass) _env->jni_reference(Handle(_cur_thread, k->java_mirror())));
+    ensure_klass_alive(k->java_mirror());
   }
 
   int extract(jclass* result_list) {
--- a/src/hotspot/share/prims/jvmtiManageCapabilities.cpp	Fri Feb 16 12:24:38 2018 -0800
+++ b/src/hotspot/share/prims/jvmtiManageCapabilities.cpp	Fri Feb 16 13:49:07 2018 -0800
@@ -57,9 +57,6 @@
 
 void JvmtiManageCapabilities::initialize() {
   always_capabilities = init_always_capabilities();
-  if (JvmtiEnv::get_phase() != JVMTI_PHASE_ONLOAD) {
-    recompute_always_capabilities();
-  }
   onload_capabilities = init_onload_capabilities();
   always_solo_capabilities = init_always_solo_capabilities();
   onload_solo_capabilities = init_onload_solo_capabilities();
@@ -68,19 +65,6 @@
   memset(&acquired_capabilities, 0, sizeof(acquired_capabilities));
 }
 
-// if the capability sets are initialized in the onload phase then
-// it happens before class data sharing (CDS) is initialized. If it
-// turns out that CDS gets disabled then we must adjust the always
-// capabilities. To ensure a consistent view of the capabililties
-// anything we add here should already be in the onload set.
-void JvmtiManageCapabilities::recompute_always_capabilities() {
-  if (!UseSharedSpaces) {
-    jvmtiCapabilities jc = always_capabilities;
-    jc.can_generate_all_class_hook_events = 1;
-    always_capabilities = jc;
-  }
-}
-
 
 // corresponding init functions
 jvmtiCapabilities JvmtiManageCapabilities::init_always_capabilities() {
@@ -94,6 +78,7 @@
   jc.can_get_synthetic_attribute = 1;
   jc.can_get_monitor_info = 1;
   jc.can_get_constant_pool = 1;
+  jc.can_generate_all_class_hook_events = 1;
   jc.can_generate_monitor_events = 1;
   jc.can_generate_garbage_collection_events = 1;
   jc.can_generate_compiled_method_load_events = 1;
@@ -126,7 +111,6 @@
   jc.can_get_source_debug_extension = 1;
   jc.can_access_local_variables = 1;
   jc.can_maintain_original_method_order = 1;
-  jc.can_generate_all_class_hook_events = 1;
   jc.can_generate_single_step_events = 1;
   jc.can_generate_exception_events = 1;
   jc.can_generate_frame_pop_events = 1;
--- a/src/hotspot/share/prims/jvmtiManageCapabilities.hpp	Fri Feb 16 12:24:38 2018 -0800
+++ b/src/hotspot/share/prims/jvmtiManageCapabilities.hpp	Fri Feb 16 13:49:07 2018 -0800
@@ -64,9 +64,6 @@
 public:
   static void initialize();
 
-  // may have to adjust always capabilities when VM initialization has completed
-  static void recompute_always_capabilities();
-
   // queries and actions
   static void get_potential_capabilities(const jvmtiCapabilities *current,
                                          const jvmtiCapabilities *prohibited,
--- a/src/hotspot/share/runtime/arguments.cpp	Fri Feb 16 12:24:38 2018 -0800
+++ b/src/hotspot/share/runtime/arguments.cpp	Fri Feb 16 13:49:07 2018 -0800
@@ -514,7 +514,9 @@
   { "DeferThrSuspendLoopCount",     JDK_Version::jdk(10), JDK_Version::jdk(11), JDK_Version::jdk(12) },
   { "DeferPollingPageLoopCount",    JDK_Version::jdk(10), JDK_Version::jdk(11), JDK_Version::jdk(12) },
   { "IgnoreUnverifiableClassesDuringDump", JDK_Version::jdk(10),  JDK_Version::undefined(), JDK_Version::undefined() },
-  { "CheckEndorsedAndExtDirs",      JDK_Version::jdk(10),  JDK_Version::undefined(), JDK_Version::undefined() },
+  { "CheckEndorsedAndExtDirs",      JDK_Version::jdk(10), JDK_Version::undefined(), JDK_Version::undefined() },
+  { "CompilerThreadHintNoPreempt",  JDK_Version::jdk(11), JDK_Version::jdk(12), JDK_Version::jdk(13) },
+  { "VMThreadHintNoPreempt",        JDK_Version::jdk(11), JDK_Version::jdk(12), JDK_Version::jdk(13) },
 
   // --- Deprecated alias flags (see also aliased_jvm_flags) - sorted by obsolete_in then expired_in:
   { "DefaultMaxRAMFraction",        JDK_Version::jdk(8),  JDK_Version::undefined(), JDK_Version::undefined() },
@@ -527,6 +529,8 @@
   { "ConvertYieldToSleep",           JDK_Version::jdk(9),      JDK_Version::jdk(10), JDK_Version::jdk(11) },
   { "MinSleepInterval",              JDK_Version::jdk(9),      JDK_Version::jdk(10), JDK_Version::jdk(11) },
   { "CheckAssertionStatusDirectives",JDK_Version::undefined(), JDK_Version::jdk(11), JDK_Version::jdk(12) },
+  { "PrintMallocFree",               JDK_Version::undefined(), JDK_Version::jdk(11), JDK_Version::jdk(12) },
+  { "PrintMalloc",                   JDK_Version::undefined(), JDK_Version::jdk(11), JDK_Version::jdk(12) },
   { "PermSize",                      JDK_Version::undefined(), JDK_Version::jdk(8),  JDK_Version::undefined() },
   { "MaxPermSize",                   JDK_Version::undefined(), JDK_Version::jdk(8),  JDK_Version::undefined() },
   { "SharedReadWriteSize",           JDK_Version::undefined(), JDK_Version::jdk(10), JDK_Version::undefined() },
--- a/src/hotspot/share/runtime/compilationPolicy.cpp	Fri Feb 16 12:24:38 2018 -0800
+++ b/src/hotspot/share/runtime/compilationPolicy.cpp	Fri Feb 16 13:49:07 2018 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2000, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2000, 2018, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -23,6 +23,7 @@
  */
 
 #include "precompiled.hpp"
+#include "classfile/classLoaderData.inline.hpp"
 #include "code/compiledIC.hpp"
 #include "code/nmethod.hpp"
 #include "code/scopeDesc.hpp"
@@ -312,10 +313,10 @@
   // and hence GC's will not be going on, all Java mutators are suspended
   // at this point and hence SystemDictionary_lock is also not needed.
   assert(SafepointSynchronize::is_at_safepoint(), "can only be executed at a safepoint");
-  int nclasses = InstanceKlass::number_of_instance_classes();
-  int classes_per_tick = nclasses * (CounterDecayMinIntervalLength * 1e-3 /
+  size_t nclasses = ClassLoaderDataGraph::num_instance_classes();
+  size_t classes_per_tick = nclasses * (CounterDecayMinIntervalLength * 1e-3 /
                                         CounterHalfLifeTime);
-  for (int i = 0; i < classes_per_tick; i++) {
+  for (size_t i = 0; i < classes_per_tick; i++) {
     InstanceKlass* k = ClassLoaderDataGraph::try_get_next_class();
     if (k != NULL) {
       k->methods_do(do_method);
--- a/src/hotspot/share/runtime/globals.hpp	Fri Feb 16 12:24:38 2018 -0800
+++ b/src/hotspot/share/runtime/globals.hpp	Fri Feb 16 13:49:07 2018 -0800
@@ -893,18 +893,12 @@
   develop(bool, TraceJavaAssertions, false,                                 \
           "Trace java language assertions")                                 \
                                                                             \
-  notproduct(bool, PrintMallocFree, false,                                  \
-          "Trace calls to C heap malloc/free allocation")                   \
-                                                                            \
   notproduct(bool, VerifyCodeCache, false,                                  \
           "Verify code cache on memory allocation/deallocation")            \
                                                                             \
   develop(bool, UseMallocOnly, false,                                       \
           "Use only malloc/free for allocation (no resource area/arena)")   \
                                                                             \
-  develop(bool, PrintMalloc, false,                                         \
-          "Print all malloc/free calls")                                    \
-                                                                            \
   develop(bool, PrintMallocStatistics, false,                               \
           "Print malloc/free statistics")                                   \
                                                                             \
@@ -3545,7 +3539,7 @@
           "(-1 means no change)")                                           \
           range(-1, 127)                                                    \
                                                                             \
-  product(bool, CompilerThreadHintNoPreempt, true,                          \
+  product(bool, CompilerThreadHintNoPreempt, false,                         \
           "(Solaris only) Give compiler threads an extra quanta")           \
                                                                             \
   product(bool, VMThreadHintNoPreempt, false,                               \
--- a/src/hotspot/share/runtime/memprofiler.cpp	Fri Feb 16 12:24:38 2018 -0800
+++ b/src/hotspot/share/runtime/memprofiler.cpp	Fri Feb 16 13:49:07 2018 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1998, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1998, 2018, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -23,6 +23,7 @@
  */
 
 #include "precompiled.hpp"
+#include "classfile/classLoaderData.inline.hpp"
 #include "classfile/systemDictionary.hpp"
 #include "code/codeCache.hpp"
 #include "gc/shared/collectedHeap.inline.hpp"
@@ -116,10 +117,10 @@
     }
 
     // Print trace line in log
-    fprintf(_log_fp, "%6.1f,%5d,%5d," UINTX_FORMAT_W(6) "," UINTX_FORMAT_W(6) ",",
+    fprintf(_log_fp, "%6.1f,%5d," SIZE_FORMAT_W(5) "," UINTX_FORMAT_W(6) "," UINTX_FORMAT_W(6) ",",
             os::elapsedTime(),
             jtiwh.length(),
-            InstanceKlass::number_of_instance_classes(),
+            ClassLoaderDataGraph::num_instance_classes(),
             Universe::heap()->used() / K,
             Universe::heap()->capacity() / K);
   }
--- a/src/hotspot/share/runtime/mutexLocker.cpp	Fri Feb 16 12:24:38 2018 -0800
+++ b/src/hotspot/share/runtime/mutexLocker.cpp	Fri Feb 16 13:49:07 2018 -0800
@@ -253,10 +253,10 @@
   // of some places which hold other locks while releasing a handle, including
   // the Patching_lock, which is of "special" rank.  As a temporary workaround,
   // lower the JNI oopstorage lock ranks to make them super-special.
-  def(JNIGlobalAlloc_lock          , PaddedMutex  , special-1,   true,  Monitor::_safepoint_check_never);
-  def(JNIGlobalActive_lock         , PaddedMutex  , special-2,   true,  Monitor::_safepoint_check_never);
-  def(JNIWeakAlloc_lock            , PaddedMutex  , special-1,   true,  Monitor::_safepoint_check_never);
-  def(JNIWeakActive_lock           , PaddedMutex  , special-2,   true,  Monitor::_safepoint_check_never);
+  def(JNIGlobalAlloc_lock          , PaddedMutex  , nonleaf,     true,  Monitor::_safepoint_check_never);
+  def(JNIGlobalActive_lock         , PaddedMutex  , nonleaf-1,   true,  Monitor::_safepoint_check_never);
+  def(JNIWeakAlloc_lock            , PaddedMutex  , nonleaf,     true,  Monitor::_safepoint_check_never);
+  def(JNIWeakActive_lock           , PaddedMutex  , nonleaf-1,   true,  Monitor::_safepoint_check_never);
   def(JNICritical_lock             , PaddedMonitor, nonleaf,     true,  Monitor::_safepoint_check_always);     // used for JNI critical regions
   def(AdapterHandlerLibrary_lock   , PaddedMutex  , nonleaf,     true,  Monitor::_safepoint_check_always);
 
--- a/src/hotspot/share/runtime/os.cpp	Fri Feb 16 12:24:38 2018 -0800
+++ b/src/hotspot/share/runtime/os.cpp	Fri Feb 16 13:49:07 2018 -0800
@@ -33,6 +33,7 @@
 #include "code/icBuffer.hpp"
 #include "code/vtableStubs.hpp"
 #include "gc/shared/vmGCOperations.hpp"
+#include "logging/log.hpp"
 #include "interpreter/interpreter.hpp"
 #include "logging/log.hpp"
 #include "logging/logStream.hpp"
@@ -610,9 +611,12 @@
 static void verify_memory(void* ptr) {
   GuardedMemory guarded(ptr);
   if (!guarded.verify_guards()) {
-    tty->print_cr("## nof_mallocs = " UINT64_FORMAT ", nof_frees = " UINT64_FORMAT, os::num_mallocs, os::num_frees);
-    tty->print_cr("## memory stomp:");
-    guarded.print_on(tty);
+    LogTarget(Warning, malloc, free) lt;
+    ResourceMark rm;
+    LogStream ls(lt);
+    ls.print_cr("## nof_mallocs = " UINT64_FORMAT ", nof_frees = " UINT64_FORMAT, os::num_mallocs, os::num_frees);
+    ls.print_cr("## memory stomp:");
+    guarded.print_on(&ls);
     fatal("memory stomping error");
   }
 }
@@ -684,13 +688,10 @@
   ptr = guarded.get_user_ptr();
 #endif
   if ((intptr_t)ptr == (intptr_t)MallocCatchPtr) {
-    tty->print_cr("os::malloc caught, " SIZE_FORMAT " bytes --> " PTR_FORMAT, size, p2i(ptr));
+    log_warning(malloc, free)("os::malloc caught, " SIZE_FORMAT " bytes --> " PTR_FORMAT, size, p2i(ptr));
     breakpoint();
   }
   debug_only(if (paranoid) verify_memory(ptr));
-  if (PrintMalloc && tty != NULL) {
-    tty->print_cr("os::malloc " SIZE_FORMAT " bytes --> " PTR_FORMAT, size, p2i(ptr));
-  }
 
   // we do not track guard memory
   return MemTracker::record_malloc((address)ptr, size, memflags, stack, level);
@@ -727,7 +728,7 @@
     return os::malloc(size, memflags, stack);
   }
   if ((intptr_t)memblock == (intptr_t)MallocCatchPtr) {
-    tty->print_cr("os::realloc caught " PTR_FORMAT, p2i(memblock));
+    log_warning(malloc, free)("os::realloc caught " PTR_FORMAT, p2i(memblock));
     breakpoint();
   }
   // NMT support
@@ -735,18 +736,15 @@
   verify_memory(membase);
   // always move the block
   void* ptr = os::malloc(size, memflags, stack);
-  if (PrintMalloc && tty != NULL) {
-    tty->print_cr("os::realloc " SIZE_FORMAT " bytes, " PTR_FORMAT " --> " PTR_FORMAT, size, p2i(memblock), p2i(ptr));
-  }
   // Copy to new memory if malloc didn't fail
-  if ( ptr != NULL ) {
+  if (ptr != NULL ) {
     GuardedMemory guarded(MemTracker::malloc_base(memblock));
     // Guard's user data contains NMT header
     size_t memblock_size = guarded.get_user_size() - MemTracker::malloc_header_size(memblock);
     memcpy(ptr, memblock, MIN2(size, memblock_size));
     if (paranoid) verify_memory(MemTracker::malloc_base(ptr));
     if ((intptr_t)ptr == (intptr_t)MallocCatchPtr) {
-      tty->print_cr("os::realloc caught, " SIZE_FORMAT " bytes --> " PTR_FORMAT, size, p2i(ptr));
+      log_warning(malloc, free)("os::realloc caught, " SIZE_FORMAT " bytes --> " PTR_FORMAT, size, p2i(ptr));
       breakpoint();
     }
     os::free(memblock);
@@ -761,7 +759,7 @@
 #ifdef ASSERT
   if (memblock == NULL) return;
   if ((intptr_t)memblock == (intptr_t)MallocCatchPtr) {
-    if (tty != NULL) tty->print_cr("os::free caught " PTR_FORMAT, p2i(memblock));
+    log_warning(malloc, free)("os::free caught " PTR_FORMAT, p2i(memblock));
     breakpoint();
   }
   void* membase = MemTracker::record_free(memblock);
@@ -771,9 +769,6 @@
   size_t size = guarded.get_user_size();
   inc_stat_counter(&free_bytes, size);
   membase = guarded.release_for_freeing();
-  if (PrintMalloc && tty != NULL) {
-      fprintf(stderr, "os::free " SIZE_FORMAT " bytes --> " PTR_FORMAT "\n", size, (uintptr_t)membase);
-  }
   ::free(membase);
 #else
   void* membase = MemTracker::record_free(memblock);
@@ -1754,7 +1749,7 @@
 bool os::uncommit_memory(char* addr, size_t bytes) {
   bool res;
   if (MemTracker::tracking_level() > NMT_minimal) {
-    Tracker tkr = MemTracker::get_virtual_memory_uncommit_tracker();
+    Tracker tkr(Tracker::uncommit);
     res = pd_uncommit_memory(addr, bytes);
     if (res) {
       tkr.record((address)addr, bytes);
@@ -1768,7 +1763,7 @@
 bool os::release_memory(char* addr, size_t bytes) {
   bool res;
   if (MemTracker::tracking_level() > NMT_minimal) {
-    Tracker tkr = MemTracker::get_virtual_memory_release_tracker();
+    Tracker tkr(Tracker::release);
     res = pd_release_memory(addr, bytes);
     if (res) {
       tkr.record((address)addr, bytes);
@@ -1805,7 +1800,7 @@
 bool os::unmap_memory(char *addr, size_t bytes) {
   bool result;
   if (MemTracker::tracking_level() > NMT_minimal) {
-    Tracker tkr = MemTracker::get_virtual_memory_release_tracker();
+    Tracker tkr(Tracker::release);
     result = pd_unmap_memory(addr, bytes);
     if (result) {
       tkr.record((address)addr, bytes);
--- a/src/hotspot/share/services/memBaseline.cpp	Fri Feb 16 12:24:38 2018 -0800
+++ b/src/hotspot/share/services/memBaseline.cpp	Fri Feb 16 13:49:07 2018 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2018, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -23,6 +23,7 @@
  */
 #include "precompiled.hpp"
 
+#include "classfile/classLoaderData.inline.hpp"
 #include "memory/allocation.hpp"
 #include "runtime/safepoint.hpp"
 #include "runtime/thread.inline.hpp"
@@ -180,7 +181,8 @@
 bool MemBaseline::baseline(bool summaryOnly) {
   reset();
 
-  _class_count = InstanceKlass::number_of_instance_classes();
+  _instance_class_count = ClassLoaderDataGraph::num_instance_classes();
+  _array_class_count = ClassLoaderDataGraph::num_array_classes();
 
   if (!baseline_summary()) {
     return false;
--- a/src/hotspot/share/services/memBaseline.hpp	Fri Feb 16 12:24:38 2018 -0800
+++ b/src/hotspot/share/services/memBaseline.hpp	Fri Feb 16 13:49:07 2018 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2018, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -67,7 +67,8 @@
   VirtualMemorySnapshot  _virtual_memory_snapshot;
   MetaspaceSnapshot      _metaspace_snapshot;
 
-  size_t               _class_count;
+  size_t                 _instance_class_count;
+  size_t                 _array_class_count;
 
   // Allocation sites information
   // Malloc allocation sites
@@ -89,7 +90,7 @@
   // create a memory baseline
   MemBaseline():
     _baseline_type(Not_baselined),
-    _class_count(0) {
+    _instance_class_count(0), _array_class_count(0) {
   }
 
   bool baseline(bool summaryOnly = true);
@@ -160,7 +161,17 @@
 
   size_t class_count() const {
     assert(baseline_type() != Not_baselined, "Not yet baselined");
-    return _class_count;
+    return _instance_class_count + _array_class_count;
+  }
+
+  size_t instance_class_count() const {
+    assert(baseline_type() != Not_baselined, "Not yet baselined");
+    return _instance_class_count;
+  }
+
+  size_t array_class_count() const {
+    assert(baseline_type() != Not_baselined, "Not yet baselined");
+    return _array_class_count;
   }
 
   size_t thread_count() const {
@@ -172,7 +183,8 @@
   void reset() {
     _baseline_type = Not_baselined;
     // _malloc_memory_snapshot and _virtual_memory_snapshot are copied over.
-    _class_count  = 0;
+    _instance_class_count  = 0;
+    _array_class_count = 0;
 
     _malloc_sites.clear();
     _virtual_memory_sites.clear();
--- a/src/hotspot/share/services/memReporter.cpp	Fri Feb 16 12:24:38 2018 -0800
+++ b/src/hotspot/share/services/memReporter.cpp	Fri Feb 16 13:49:07 2018 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2018, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -145,7 +145,10 @@
 
     if (flag == mtClass) {
       // report class count
-      out->print_cr("%27s (classes #" SIZE_FORMAT ")", " ", _class_count);
+      out->print_cr("%27s (classes #" SIZE_FORMAT ")",
+        " ", (_instance_class_count + _array_class_count));
+      out->print_cr("%27s (  instance classes #" SIZE_FORMAT ", array classes #" SIZE_FORMAT ")",
+        " ", _instance_class_count, _array_class_count);
     } else if (flag == mtThread) {
       // report thread count
       out->print_cr("%27s (thread #" SIZE_FORMAT ")", " ", _malloc_snapshot->thread_count());
@@ -459,6 +462,17 @@
         out->print(" %+d", (int)(_current_baseline.class_count() - _early_baseline.class_count()));
       }
       out->print_cr(")");
+
+      out->print("%27s (  instance classes #" SIZE_FORMAT, " ", _current_baseline.instance_class_count());
+      if (_current_baseline.instance_class_count() != _early_baseline.instance_class_count()) {
+        out->print(" %+d", (int)(_current_baseline.instance_class_count() - _early_baseline.instance_class_count()));
+      }
+      out->print(", array classes #" SIZE_FORMAT, _current_baseline.array_class_count());
+      if (_current_baseline.array_class_count() != _early_baseline.array_class_count()) {
+        out->print(" %+d", (int)(_current_baseline.array_class_count() - _early_baseline.array_class_count()));
+      }
+      out->print_cr(")");
+
     } else if (flag == mtThread) {
       // report thread count
       out->print("%27s (thread #" SIZE_FORMAT "", " ", _current_baseline.thread_count());
--- a/src/hotspot/share/services/memReporter.hpp	Fri Feb 16 12:24:38 2018 -0800
+++ b/src/hotspot/share/services/memReporter.hpp	Fri Feb 16 13:49:07 2018 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2018, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -94,7 +94,8 @@
  private:
   MallocMemorySnapshot*   _malloc_snapshot;
   VirtualMemorySnapshot*  _vm_snapshot;
-  size_t                  _class_count;
+  size_t                  _instance_class_count;
+  size_t                  _array_class_count;
 
  public:
   // This constructor is for normal reporting from a recent baseline.
@@ -102,7 +103,8 @@
     size_t scale = K) : MemReporterBase(output, scale),
     _malloc_snapshot(baseline.malloc_memory_snapshot()),
     _vm_snapshot(baseline.virtual_memory_snapshot()),
-    _class_count(baseline.class_count()) { }
+    _instance_class_count(baseline.instance_class_count()),
+    _array_class_count(baseline.array_class_count()) { }
 
 
   // Generate summary report
--- a/src/hotspot/share/services/memTracker.hpp	Fri Feb 16 12:24:38 2018 -0800
+++ b/src/hotspot/share/services/memTracker.hpp	Fri Feb 16 13:49:07 2018 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -36,8 +36,14 @@
 
 class Tracker : public StackObj {
  public:
-  Tracker() { }
-  void record(address addr, size_t size) { }
+  enum TrackerType {
+     uncommit,
+     release
+  };
+  Tracker(enum TrackerType type) : _type(type) { }
+  void record(address addr, size_t size);
+ private:
+  enum TrackerType  _type;
 };
 
 class MemTracker : AllStatic {
@@ -63,8 +69,6 @@
   static inline void record_virtual_memory_reserve_and_commit(void* addr, size_t size,
     const NativeCallStack& stack, MEMFLAGS flag = mtNone) { }
   static inline void record_virtual_memory_commit(void* addr, size_t size, const NativeCallStack& stack) { }
-  static inline Tracker get_virtual_memory_uncommit_tracker() { return Tracker(); }
-  static inline Tracker get_virtual_memory_release_tracker() { return Tracker(); }
   static inline void record_virtual_memory_type(void* addr, MEMFLAGS flag) { }
   static inline void record_thread_stack(void* addr, size_t size) { }
   static inline void release_thread_stack(void* addr, size_t size) { }
@@ -227,16 +231,6 @@
     }
   }
 
-  static inline Tracker get_virtual_memory_uncommit_tracker() {
-    assert(tracking_level() >= NMT_summary, "Check by caller");
-    return Tracker(Tracker::uncommit);
-  }
-
-  static inline Tracker get_virtual_memory_release_tracker() {
-    assert(tracking_level() >= NMT_summary, "Check by caller");
-    return Tracker(Tracker::release);
-  }
-
   static inline void record_virtual_memory_type(void* addr, MEMFLAGS flag) {
     if (tracking_level() < NMT_summary) return;
     if (addr != NULL) {
--- a/src/hotspot/share/utilities/ostream.cpp	Fri Feb 16 12:24:38 2018 -0800
+++ b/src/hotspot/share/utilities/ostream.cpp	Fri Feb 16 13:49:07 2018 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1997, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2018, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -947,18 +947,11 @@
     delete classlist_file;
   }
 #endif
-  {
-      // we temporaly disable PrintMallocFree here
-      // as otherwise it'll lead to using of almost deleted
-      // tty or defaultStream::instance in logging facility
-      // of HeapFree(), see 6391258
-      DEBUG_ONLY(FlagSetting fs(PrintMallocFree, false);)
-      if (tty != defaultStream::instance) {
-          delete tty;
-      }
-      if (defaultStream::instance != NULL) {
-          delete defaultStream::instance;
-      }
+  if (tty != defaultStream::instance) {
+    delete tty;
+  }
+  if (defaultStream::instance != NULL) {
+    delete defaultStream::instance;
   }
   tty = NULL;
   xtty = NULL;
--- a/src/java.base/share/classes/java/lang/Thread.java	Fri Feb 16 12:24:38 2018 -0800
+++ b/src/java.base/share/classes/java/lang/Thread.java	Fri Feb 16 13:49:07 2018 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1994, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1994, 2018, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -150,9 +150,6 @@
     private Thread         threadQ;
     private long           eetop;
 
-    /* Whether or not to single_step this thread. */
-    private boolean     single_step;
-
     /* Whether or not the thread is a daemon thread. */
     private boolean     daemon = false;
 
--- a/src/java.base/share/classes/java/lang/invoke/BootstrapMethodInvoker.java	Fri Feb 16 12:24:38 2018 -0800
+++ b/src/java.base/share/classes/java/lang/invoke/BootstrapMethodInvoker.java	Fri Feb 16 13:49:07 2018 -0800
@@ -67,12 +67,12 @@
             // VM is pushing arguments at us
             pullModeBSM = null;
             if (pullMode) {
-                bootstrapMethod = Adapters.pushMePullYou(bootstrapMethod, true);
+                bootstrapMethod = pushMePullYou(bootstrapMethod, true);
             }
         } else {
             // VM wants us to pull args from it
             pullModeBSM = pullMode ? bootstrapMethod :
-                    Adapters.pushMePullYou(bootstrapMethod, false);
+                    pushMePullYou(bootstrapMethod, false);
             bootstrapMethod = null;
         }
         try {
@@ -237,9 +237,10 @@
             // give up at first null and grab the rest in one big block
             if (i >= end)  return i;
             Object[] temp = new Object[end - i];
-            if (TRACE_METHOD_LINKAGE)
-                System.out.println("resolving more BSM arguments: "+
+            if (TRACE_METHOD_LINKAGE) {
+                System.out.println("resolving more BSM arguments: " +
                         Arrays.asList(caller.getSimpleName(), Arrays.toString(indexInfo), i, end));
+            }
             copyOutBootstrapArguments(caller, indexInfo,
                                       i, end, temp, 0,
                                       true, null);
@@ -285,9 +286,10 @@
         private void prefetchIntoCache(int i, int pfLimit) {
             if (pfLimit <= i)  return;  // corner case
             Object[] temp = new Object[pfLimit - i];
-            if (TRACE_METHOD_LINKAGE)
-                System.out.println("prefetching BSM arguments: "+
+            if (TRACE_METHOD_LINKAGE) {
+                System.out.println("prefetching BSM arguments: " +
                         Arrays.asList(caller.getSimpleName(), Arrays.toString(indexInfo), i, pfLimit));
+            }
             copyOutBootstrapArguments(caller, indexInfo,
                                       i, pfLimit, temp, 0,
                                       false, NOT_PRESENT);
@@ -301,7 +303,7 @@
     }
 
     /*non-public*/ static final
-    class Adapters {
+    class PushAdapter {
         // skeleton for push-mode BSM which wraps a pull-mode BSM:
         static Object pushToBootstrapMethod(MethodHandle pullModeBSM,
                                             MethodHandles.Lookup lookup, String name, Object type,
@@ -313,29 +315,75 @@
             return pullModeBSM.invoke(lookup, bsci);
         }
 
-        // skeleton for pull-mode BSM which wraps a push-mode BSM:
-        static Object pullFromBootstrapMethod(MethodHandle pushModeBSM,
-                                              MethodHandles.Lookup lookup, BootstrapCallInfo<?> bsci)
-                throws Throwable {
-            int argc = bsci.size();
-            Object arguments[] = new Object[3 + argc];
-            arguments[0] = lookup;
-            arguments[1] = bsci.invocationName();
-            arguments[2] = bsci.invocationType();
-            bsci.copyConstants(0, argc, arguments, 3);
-            if (TRACE_METHOD_LINKAGE)
-                System.out.println("pulled arguments from VM for push-mode BSM");
-            return pushModeBSM.invokeWithArguments(arguments);
-        }
         static final MethodHandle MH_pushToBootstrapMethod;
-        static final MethodHandle MH_pullFromBootstrapMethod;
         static {
-            final Class<?> THIS_CLASS = Adapters.class;
+            final Class<?> THIS_CLASS = PushAdapter.class;
             try {
                 MH_pushToBootstrapMethod = IMPL_LOOKUP
                     .findStatic(THIS_CLASS, "pushToBootstrapMethod",
                                 MethodType.methodType(Object.class, MethodHandle.class,
                                         Lookup.class, String.class, Object.class, Object[].class));
+            } catch (Throwable ex) {
+                throw new InternalError(ex);
+            }
+        }
+    }
+
+    /*non-public*/ static final
+    class PullAdapter {
+        // skeleton for pull-mode BSM which wraps a push-mode BSM:
+        static Object pullFromBootstrapMethod(MethodHandle pushModeBSM,
+                                              MethodHandles.Lookup lookup,
+                                              BootstrapCallInfo<?> bsci)
+                throws Throwable {
+            int argc = bsci.size();
+            switch (argc) {
+                case 0:
+                    return pushModeBSM.invoke(lookup, bsci.invocationName(), bsci.invocationType());
+                case 1:
+                    return pushModeBSM.invoke(lookup, bsci.invocationName(), bsci.invocationType(),
+                            bsci.get(0));
+                case 2:
+                    return pushModeBSM.invoke(lookup, bsci.invocationName(), bsci.invocationType(),
+                            bsci.get(0), bsci.get(1));
+                case 3:
+                    return pushModeBSM.invoke(lookup, bsci.invocationName(), bsci.invocationType(),
+                            bsci.get(0), bsci.get(1), bsci.get(2));
+                case 4:
+                    return pushModeBSM.invoke(lookup, bsci.invocationName(), bsci.invocationType(),
+                            bsci.get(0), bsci.get(1), bsci.get(2), bsci.get(3));
+                case 5:
+                    return pushModeBSM.invoke(lookup, bsci.invocationName(), bsci.invocationType(),
+                            bsci.get(0), bsci.get(1), bsci.get(2), bsci.get(3), bsci.get(4));
+                case 6:
+                    return pushModeBSM.invoke(lookup, bsci.invocationName(), bsci.invocationType(),
+                            bsci.get(0), bsci.get(1), bsci.get(2), bsci.get(3), bsci.get(4), bsci.get(5));
+                default:
+                    final int NON_SPREAD_ARG_COUNT = 3;  // (lookup, name, type)
+                    final int MAX_SAFE_SIZE = MethodType.MAX_MH_ARITY / 2 - NON_SPREAD_ARG_COUNT;
+                    if (argc >= MAX_SAFE_SIZE) {
+                        // to be on the safe side, use invokeWithArguments which handles jumbo lists
+                        Object[] newargv = new Object[NON_SPREAD_ARG_COUNT + argc];
+                        newargv[0] = lookup;
+                        newargv[1] = bsci.invocationName();
+                        newargv[2] = bsci.invocationType();
+                        bsci.copyConstants(0, argc, newargv, NON_SPREAD_ARG_COUNT);
+                        return pushModeBSM.invokeWithArguments(newargv);
+                    }
+                    MethodType invocationType = MethodType.genericMethodType(NON_SPREAD_ARG_COUNT + argc);
+                    MethodHandle typedBSM = pushModeBSM.asType(invocationType);
+                    MethodHandle spreader = invocationType.invokers().spreadInvoker(NON_SPREAD_ARG_COUNT);
+                    Object[] argv = new Object[argc];
+                    bsci.copyConstants(0, argc, argv, 0);
+                    return spreader.invokeExact(typedBSM, (Object) lookup, (Object) bsci.invocationName(), bsci.invocationType(), argv);
+                }
+        }
+
+        static final MethodHandle MH_pullFromBootstrapMethod;
+
+        static {
+            final Class<?> THIS_CLASS = PullAdapter.class;
+            try {
                 MH_pullFromBootstrapMethod = IMPL_LOOKUP
                     .findStatic(THIS_CLASS, "pullFromBootstrapMethod",
                                 MethodType.methodType(Object.class, MethodHandle.class,
@@ -344,23 +392,25 @@
                 throw new InternalError(ex);
             }
         }
+    }
 
-        /** Given a push-mode BSM (taking one argument) convert it to a
-         *  pull-mode BSM (taking N pre-resolved arguments).
-         *  This method is used when, in fact, the JVM is passing up
-         *  pre-resolved arguments, but the BSM is expecting lazy stuff.
-         *  Or, when goToPushMode is true, do the reverse transform.
-         *  (The two transforms are exactly inverse.)
-         */
-        static MethodHandle pushMePullYou(MethodHandle bsm, boolean goToPushMode) {
-            if (TRACE_METHOD_LINKAGE)
-                System.out.println("converting BSM to "+(goToPushMode ? "push mode" : "pull mode"));
-            assert(isPullModeBSM(bsm) == goToPushMode);  //there must be a change
-            if (goToPushMode) {
-                return Adapters.MH_pushToBootstrapMethod.bindTo(bsm).withVarargs(true);
-            } else {
-                return Adapters.MH_pullFromBootstrapMethod.bindTo(bsm).withVarargs(false);
-            }
+    /** Given a push-mode BSM (taking one argument) convert it to a
+     *  pull-mode BSM (taking N pre-resolved arguments).
+     *  This method is used when, in fact, the JVM is passing up
+     *  pre-resolved arguments, but the BSM is expecting lazy stuff.
+     *  Or, when goToPushMode is true, do the reverse transform.
+     *  (The two transforms are exactly inverse.)
+     */
+    static MethodHandle pushMePullYou(MethodHandle bsm, boolean goToPushMode) {
+        if (TRACE_METHOD_LINKAGE) {
+            System.out.println("converting BSM of type " + bsm.type() + " to "
+                    + (goToPushMode ? "push mode" : "pull mode"));
+        }
+        assert(isPullModeBSM(bsm) == goToPushMode); // there must be a change
+        if (goToPushMode) {
+            return PushAdapter.MH_pushToBootstrapMethod.bindTo(bsm).withVarargs(true);
+        } else {
+            return PullAdapter.MH_pullFromBootstrapMethod.bindTo(bsm).withVarargs(false);
         }
     }
 }
--- a/src/java.base/share/classes/java/lang/invoke/ConstantBootstraps.java	Fri Feb 16 12:24:38 2018 -0800
+++ b/src/java.base/share/classes/java/lang/invoke/ConstantBootstraps.java	Fri Feb 16 13:49:07 2018 -0800
@@ -37,7 +37,7 @@
  * unless the argument is specified to be unused or specified to accept a
  * {@code null} value.
  *
- * @since 10
+ * @since 11
  */
 public final class ConstantBootstraps {
     // implements the upcall from the JVM, MethodHandleNatives.linkDynamicConstant:
--- a/src/java.base/share/classes/java/lang/ref/Finalizer.java	Fri Feb 16 12:24:38 2018 -0800
+++ b/src/java.base/share/classes/java/lang/ref/Finalizer.java	Fri Feb 16 13:49:07 2018 -0800
@@ -36,18 +36,18 @@
                                                           class */
 
     private static ReferenceQueue<Object> queue = new ReferenceQueue<>();
+
+    /** Head of doubly linked list of Finalizers awaiting finalization. */
     private static Finalizer unfinalized = null;
+
+    /** Lock guarding access to unfinalized list. */
     private static final Object lock = new Object();
 
-    private Finalizer
-        next = null,
-        prev = null;
+    private Finalizer next, prev;
 
-    private boolean hasBeenFinalized() {
-        return (next == this);
-    }
-
-    private void add() {
+    private Finalizer(Object finalizee) {
+        super(finalizee, queue);
+        // push onto unfinalized
         synchronized (lock) {
             if (unfinalized != null) {
                 this.next = unfinalized;
@@ -57,31 +57,6 @@
         }
     }
 
-    private void remove() {
-        synchronized (lock) {
-            if (unfinalized == this) {
-                if (this.next != null) {
-                    unfinalized = this.next;
-                } else {
-                    unfinalized = this.prev;
-                }
-            }
-            if (this.next != null) {
-                this.next.prev = this.prev;
-            }
-            if (this.prev != null) {
-                this.prev.next = this.next;
-            }
-            this.next = this;   /* Indicates that this has been finalized */
-            this.prev = this;
-        }
-    }
-
-    private Finalizer(Object finalizee) {
-        super(finalizee, queue);
-        add();
-    }
-
     static ReferenceQueue<Object> getQueue() {
         return queue;
     }
@@ -91,11 +66,24 @@
         new Finalizer(finalizee);
     }
 
+    private void deregisterAndRunFinalizer(JavaLangAccess jla) {
+        synchronized (lock) {
+            if (this.next == this)      // already finalized
+                return;
+            // unlink from unfinalized
+            if (unfinalized == this)
+                unfinalized = this.next;
+            else
+                this.prev.next = this.next;
+            if (this.next != null)
+                this.next.prev = this.prev;
+            this.prev = null;
+            this.next = this;           // mark as finalized
+        }
+        runFinalizer(jla);
+    }
+
     private void runFinalizer(JavaLangAccess jla) {
-        synchronized (this) {
-            if (hasBeenFinalized()) return;
-            remove();
-        }
         try {
             Object finalizee = this.get();
             if (finalizee != null && !(finalizee instanceof java.lang.Enum)) {
@@ -155,11 +143,8 @@
                     return;
                 final JavaLangAccess jla = SharedSecrets.getJavaLangAccess();
                 running = true;
-                for (;;) {
-                    Finalizer f = (Finalizer)queue.poll();
-                    if (f == null) break;
-                    f.runFinalizer(jla);
-                }
+                for (Finalizer f; (f = (Finalizer)queue.poll()) != null; )
+                    f.deregisterAndRunFinalizer(jla);
             }
         });
     }
@@ -179,11 +164,15 @@
                 final JavaLangAccess jla = SharedSecrets.getJavaLangAccess();
                 running = true;
                 for (;;) {
+                    // "pollFirst" from unfinalized
                     Finalizer f;
                     synchronized (lock) {
                         f = unfinalized;
                         if (f == null) break;
                         unfinalized = f.next;
+                        if (unfinalized != null)
+                            unfinalized.prev = null;
+                        f.next = f; // mark as finalized
                     }
                     f.runFinalizer(jla);
                 }}});
@@ -214,7 +203,7 @@
             for (;;) {
                 try {
                     Finalizer f = (Finalizer)queue.remove();
-                    f.runFinalizer(jla);
+                    f.deregisterAndRunFinalizer(jla);
                 } catch (InterruptedException x) {
                     // ignore and continue
                 }
--- a/src/java.base/share/classes/java/util/Base64.java	Fri Feb 16 12:24:38 2018 -0800
+++ b/src/java.base/share/classes/java/util/Base64.java	Fri Feb 16 13:49:07 2018 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2018, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -692,7 +692,27 @@
             int dp = 0;
             int bits = 0;
             int shiftto = 18;       // pos of first byte of 4-byte atom
+
             while (sp < sl) {
+                if (shiftto == 18 && sp + 4 < sl) {       // fast path
+                    int sl0 = sp + ((sl - sp) & ~0b11);
+                    while (sp < sl0) {
+                        int b1 = base64[src[sp++] & 0xff];
+                        int b2 = base64[src[sp++] & 0xff];
+                        int b3 = base64[src[sp++] & 0xff];
+                        int b4 = base64[src[sp++] & 0xff];
+                        if ((b1 | b2 | b3 | b4) < 0) {    // non base64 byte
+                            sp -= 4;
+                            break;
+                        }
+                        int bits0 = b1 << 18 | b2 << 12 | b3 << 6 | b4;
+                        dst[dp++] = (byte)(bits0 >> 16);
+                        dst[dp++] = (byte)(bits0 >>  8);
+                        dst[dp++] = (byte)(bits0);
+                    }
+                    if (sp >= sl)
+                        break;
+                }
                 int b = src[sp++] & 0xff;
                 if ((b = base64[b]) < 0) {
                     if (b == -2) {         // padding byte '='
@@ -762,6 +782,7 @@
         private final int linemax;
         private final boolean doPadding;// whether or not to pad
         private int linepos = 0;
+        private byte[] buf;
 
         EncOutputStream(OutputStream os, char[] base64,
                         byte[] newline, int linemax, boolean doPadding) {
@@ -770,6 +791,7 @@
             this.newline = newline;
             this.linemax = linemax;
             this.doPadding = doPadding;
+            this.buf = new byte[linemax <= 0 ? 8124 : linemax];
         }
 
         @Override
@@ -786,6 +808,14 @@
             }
         }
 
+        private void writeb4(char b1, char b2, char b3, char b4) throws IOException {
+            buf[0] = (byte)b1;
+            buf[1] = (byte)b2;
+            buf[2] = (byte)b3;
+            buf[3] = (byte)b4;
+            out.write(buf, 0, 4);
+        }
+
         @Override
         public void write(byte[] b, int off, int len) throws IOException {
             if (closed)
@@ -806,25 +836,34 @@
                 b2 = b[off++] & 0xff;
                 len--;
                 checkNewline();
-                out.write(base64[b0 >> 2]);
-                out.write(base64[(b0 << 4) & 0x3f | (b1 >> 4)]);
-                out.write(base64[(b1 << 2) & 0x3f | (b2 >> 6)]);
-                out.write(base64[b2 & 0x3f]);
+                writeb4(base64[b0 >> 2],
+                        base64[(b0 << 4) & 0x3f | (b1 >> 4)],
+                        base64[(b1 << 2) & 0x3f | (b2 >> 6)],
+                        base64[b2 & 0x3f]);
                 linepos += 4;
             }
             int nBits24 = len / 3;
             leftover = len - (nBits24 * 3);
-            while (nBits24-- > 0) {
+
+            while (nBits24 > 0) {
                 checkNewline();
-                int bits = (b[off++] & 0xff) << 16 |
-                           (b[off++] & 0xff) <<  8 |
-                           (b[off++] & 0xff);
-                out.write(base64[(bits >>> 18) & 0x3f]);
-                out.write(base64[(bits >>> 12) & 0x3f]);
-                out.write(base64[(bits >>> 6)  & 0x3f]);
-                out.write(base64[bits & 0x3f]);
-                linepos += 4;
-           }
+                int dl = linemax <= 0 ? buf.length : buf.length - linepos;
+                int sl = off + Math.min(nBits24, dl / 4) * 3;
+                int dp = 0;
+                for (int sp = off; sp < sl; ) {
+                    int bits = (b[sp++] & 0xff) << 16 |
+                               (b[sp++] & 0xff) <<  8 |
+                               (b[sp++] & 0xff);
+                    buf[dp++] = (byte)base64[(bits >>> 18) & 0x3f];
+                    buf[dp++] = (byte)base64[(bits >>> 12) & 0x3f];
+                    buf[dp++] = (byte)base64[(bits >>> 6)  & 0x3f];
+                    buf[dp++] = (byte)base64[bits & 0x3f];
+                }
+                out.write(buf, 0, dp);
+                off = sl;
+                linepos += dp;
+                nBits24 -= dp / 4;
+            }
             if (leftover == 1) {
                 b0 = b[off++] & 0xff;
             } else if (leftover == 2) {
@@ -889,6 +928,52 @@
             return read(sbBuf, 0, 1) == -1 ? -1 : sbBuf[0] & 0xff;
         }
 
+        private int eof(byte[] b, int off, int len, int oldOff)
+            throws IOException
+        {
+            eof = true;
+            if (nextin != 18) {
+                if (nextin == 12)
+                    throw new IOException("Base64 stream has one un-decoded dangling byte.");
+                // treat ending xx/xxx without padding character legal.
+                // same logic as v == '=' below
+                b[off++] = (byte)(bits >> (16));
+                if (nextin == 0) {           // only one padding byte
+                    if (len == 1) {          // no enough output space
+                        bits >>= 8;          // shift to lowest byte
+                        nextout = 0;
+                    } else {
+                        b[off++] = (byte) (bits >>  8);
+                    }
+                }
+            }
+            return off == oldOff ? -1 : off - oldOff;
+        }
+
+        private int padding(byte[] b, int off, int len, int oldOff)
+            throws IOException
+        {
+            // =     shiftto==18 unnecessary padding
+            // x=    shiftto==12 dangling x, invalid unit
+            // xx=   shiftto==6 && missing last '='
+            // xx=y  or last is not '='
+            if (nextin == 18 || nextin == 12 ||
+                nextin == 6 && is.read() != '=') {
+                throw new IOException("Illegal base64 ending sequence:" + nextin);
+            }
+            b[off++] = (byte)(bits >> (16));
+            if (nextin == 0) {           // only one padding byte
+                if (len == 1) {          // no enough output space
+                    bits >>= 8;          // shift to lowest byte
+                    nextout = 0;
+                } else {
+                    b[off++] = (byte) (bits >>  8);
+                }
+            }
+            eof = true;
+            return off - oldOff;
+        }
+
         @Override
         public int read(byte[] b, int off, int len) throws IOException {
             if (closed)
@@ -898,82 +983,46 @@
             if (off < 0 || len < 0 || len > b.length - off)
                 throw new IndexOutOfBoundsException();
             int oldOff = off;
-            if (nextout >= 0) {       // leftover output byte(s) in bits buf
-                do {
-                    if (len == 0)
-                        return off - oldOff;
-                    b[off++] = (byte)(bits >> nextout);
-                    len--;
-                    nextout -= 8;
-                } while (nextout >= 0);
-                bits = 0;
+            while (nextout >= 0) {       // leftover output byte(s) in bits buf
+                if (len == 0)
+                    return off - oldOff;
+                b[off++] = (byte)(bits >> nextout);
+                len--;
+                nextout -= 8;
             }
+            bits = 0;
             while (len > 0) {
                 int v = is.read();
                 if (v == -1) {
-                    eof = true;
-                    if (nextin != 18) {
-                        if (nextin == 12)
-                            throw new IOException("Base64 stream has one un-decoded dangling byte.");
-                        // treat ending xx/xxx without padding character legal.
-                        // same logic as v == '=' below
-                        b[off++] = (byte)(bits >> (16));
-                        len--;
-                        if (nextin == 0) {           // only one padding byte
-                            if (len == 0) {          // no enough output space
-                                bits >>= 8;          // shift to lowest byte
-                                nextout = 0;
-                            } else {
-                                b[off++] = (byte) (bits >>  8);
-                            }
-                        }
-                    }
-                    if (off == oldOff)
-                        return -1;
-                    else
-                        return off - oldOff;
+                    return eof(b, off, len, oldOff);
                 }
-                if (v == '=') {                  // padding byte(s)
-                    // =     shiftto==18 unnecessary padding
-                    // x=    shiftto==12 dangling x, invalid unit
-                    // xx=   shiftto==6 && missing last '='
-                    // xx=y  or last is not '='
-                    if (nextin == 18 || nextin == 12 ||
-                        nextin == 6 && is.read() != '=') {
-                        throw new IOException("Illegal base64 ending sequence:" + nextin);
+                if ((v = base64[v]) < 0) {
+                    if (v == -2) {       // padding byte(s)
+                        return padding(b, off, len, oldOff);
                     }
-                    b[off++] = (byte)(bits >> (16));
-                    len--;
-                    if (nextin == 0) {           // only one padding byte
-                        if (len == 0) {          // no enough output space
-                            bits >>= 8;          // shift to lowest byte
-                            nextout = 0;
-                        } else {
-                            b[off++] = (byte) (bits >>  8);
-                        }
+                    if (v == -1) {
+                        if (!isMIME)
+                            throw new IOException("Illegal base64 character " +
+                                Integer.toString(v, 16));
+                        continue;        // skip if for rfc2045
                     }
-                    eof = true;
-                    break;
-                }
-                if ((v = base64[v]) == -1) {
-                    if (isMIME)                 // skip if for rfc2045
-                        continue;
-                    else
-                        throw new IOException("Illegal base64 character " +
-                            Integer.toString(v, 16));
+                    // neve be here
                 }
                 bits |= (v << nextin);
                 if (nextin == 0) {
-                    nextin = 18;    // clear for next
-                    nextout = 16;
-                    while (nextout >= 0) {
-                        b[off++] = (byte)(bits >> nextout);
-                        len--;
-                        nextout -= 8;
-                        if (len == 0 && nextout >= 0) {  // don't clean "bits"
-                            return off - oldOff;
-                        }
+                    nextin = 18;         // clear for next in
+                    b[off++] = (byte)(bits >> 16);
+                    if (len == 1) {
+                        nextout = 8;    // 2 bytes left in bits
+                        break;
                     }
+                    b[off++] = (byte)(bits >> 8);
+                    if (len == 2) {
+                        nextout = 0;    // 1 byte left in bits
+                        break;
+                    }
+                    b[off++] = (byte)bits;
+                    len -= 3;
                     bits = 0;
                 } else {
                     nextin -= 6;
--- a/src/java.base/share/classes/java/util/Collections.java	Fri Feb 16 12:24:38 2018 -0800
+++ b/src/java.base/share/classes/java/util/Collections.java	Fri Feb 16 13:49:07 2018 -0800
@@ -3771,9 +3771,9 @@
                  * Ensure that we don't get an ArrayStoreException even if
                  * s.toArray returns an array of something other than Object
                  */
-                Object[] dest = (CheckedEntry.class.isInstance(
-                    source.getClass().getComponentType()) ? source :
-                                 new Object[source.length]);
+                Object[] dest = (source.getClass() == Object[].class)
+                    ? source
+                    : new Object[source.length];
 
                 for (int i = 0; i < source.length; i++)
                     dest[i] = checkedEntry((Map.Entry<K,V>)source[i],
--- a/src/java.base/share/classes/java/util/regex/Pattern.java	Fri Feb 16 12:24:38 2018 -0800
+++ b/src/java.base/share/classes/java/util/regex/Pattern.java	Fri Feb 16 13:49:07 2018 -0800
@@ -782,12 +782,9 @@
      * arguments, they can also be passed as inline modifiers.
      * For example, the following statements have the same effect.
      * <pre>
-     * RegExp r1 = RegExp.compile("abc", Pattern.I|Pattern.M);
-     * RegExp r2 = RegExp.compile("(?im)abc", 0);
+     * Pattern p1 = Pattern.compile("abc", Pattern.CASE_INSENSITIVE|Pattern.MULTILINE);
+     * Pattern p2 = Pattern.compile("(?im)abc", 0);
      * </pre>
-     *
-     * The flags are duplicated so that the familiar Perl match flag
-     * names are available.
      */
 
     /**
@@ -2527,7 +2524,7 @@
                 throw error("\\k is not followed by '<' for named capturing group");
             String name = groupname(read());
             if (!namedGroups().containsKey(name))
-                throw error("(named capturing group <"+ name+"> does not exit");
+                throw error("named capturing group <" + name + "> does not exist");
             if (create) {
                 hasGroupRef = true;
                 if (has(CASE_INSENSITIVE))
@@ -2922,13 +2919,11 @@
      */
     private String groupname(int ch) {
         StringBuilder sb = new StringBuilder();
-        sb.append(Character.toChars(ch));
-        while (ASCII.isLower(ch=read()) || ASCII.isUpper(ch) ||
-               ASCII.isDigit(ch)) {
-            sb.append(Character.toChars(ch));
-        }
-        if (sb.length() == 0)
-            throw error("named capturing group has 0 length name");
+        if (!ASCII.isAlpha(ch))
+            throw error("capturing group name does not start with a Latin letter");
+        do {
+            sb.append((char) ch);
+        } while (ASCII.isAlnum(ch=read()));
         if (ch != '>')
             throw error("named capturing group is missing trailing '>'");
         return sb.toString();
@@ -2974,7 +2969,7 @@
                 break;
             case '<':   // (?<xxx)  look behind
                 ch = read();
-                if (ASCII.isLower(ch) || ASCII.isUpper(ch)) {
+                if (ch != '=' && ch != '!') {
                     // named captured group
                     String name = groupname(ch);
                     if (namedGroups().containsKey(name))
@@ -3005,14 +3000,12 @@
                                                info.minLength) :
                                    new Behind(head, info.maxLength,
                                               info.minLength));
-                } else if (ch == '!') {
+                } else { // if (ch == '!')
                     head = tail = (hasSupplementary ?
                                    new NotBehindS(head, info.maxLength,
                                                   info.minLength) :
                                    new NotBehind(head, info.maxLength,
                                                  info.minLength));
-                } else {
-                    throw error("Unknown look-behind group");
                 }
                 // clear all top-closure-nodes inside lookbehind
                 if (saveTCNCount < topClosureNodes.size())
--- a/src/java.base/share/classes/sun/launcher/resources/launcher.properties	Fri Feb 16 12:24:38 2018 -0800
+++ b/src/java.base/share/classes/sun/launcher/resources/launcher.properties	Fri Feb 16 13:49:07 2018 -0800
@@ -220,7 +220,7 @@
     Error: The JavaFX launchApplication method has the wrong signature, it\n\
     must be declared static and return a value of type void
 java.launcher.module.error1=\
-    module {0} does not have a MainClass attribute, use -m <module>/<main-class>
+    module {0} does not have a ModuleMainClass attribute, use -m <module>/<main-class>
 java.launcher.module.error2=\
     Error: Could not find or load main class {0} in module {1}
 java.launcher.module.error3=\
--- a/src/java.base/share/classes/sun/net/www/ParseUtil.java	Fri Feb 16 12:24:38 2018 -0800
+++ b/src/java.base/share/classes/sun/net/www/ParseUtil.java	Fri Feb 16 13:49:07 2018 -0800
@@ -44,7 +44,9 @@
  * @author  Mike McCloskey
  */
 
-public class ParseUtil {
+public final class ParseUtil {
+
+    private ParseUtil() {}
 
     /**
      * Constructs an encoded version of the specified path string suitable
@@ -80,10 +82,13 @@
         int len = path.length();
         for (int i = 0; i < len; i++) {
             char c = path.charAt(i);
-            if (c == '/' || c == '.' ||
-                    c >= 'a' && c <= 'z' ||
-                    c >= 'A' && c <= 'Z' ||
-                    c >= '0' && c <= '9') {
+            // Ordering in the following test is performance sensitive,
+            // and typically paths have most chars in the a-z range, then
+            // in the symbol range '&'-':' (includes '.', '/' and '0'-'9')
+            // and more rarely in the A-Z range.
+            if (c >= 'a' && c <= 'z' ||
+                c >= '&' && c <= ':' ||
+                c >= 'A' && c <= 'Z') {
                 continue;
             } else if (c > 0x007F || match(c, L_ENCODED, H_ENCODED)) {
                 return i;
@@ -219,9 +224,17 @@
     /**
      * Returns a canonical version of the specified string.
      */
-    public String canonizeString(String file) {
-        int i = 0;
-        int lim = file.length();
+    public static String canonizeString(String file) {
+        int len = file.length();
+        if (len == 0 || (file.indexOf("./") == -1 && file.charAt(len - 1) != '.')) {
+            return file;
+        } else {
+            return doCanonize(file);
+        }
+    }
+
+    private static String doCanonize(String file) {
+        int i, lim;
 
         // Remove embedded /../
         while ((i = file.indexOf("/../")) >= 0) {
--- a/src/java.base/share/classes/sun/net/www/protocol/jar/Handler.java	Fri Feb 16 12:24:38 2018 -0800
+++ b/src/java.base/share/classes/sun/net/www/protocol/jar/Handler.java	Fri Feb 16 13:49:07 2018 -0800
@@ -141,10 +141,9 @@
         // 1. absolute (jar:)
         // 2. relative (i.e. url + foo/bar/baz.ext)
         // 3. anchor-only (i.e. url + #foo), which we already did (refOnly)
-        boolean absoluteSpec = false;
-        if (spec.length() >= 4) {
-            absoluteSpec = spec.substring(0, 4).equalsIgnoreCase("jar:");
-        }
+        boolean absoluteSpec = spec.length() >= 4
+                ? spec.regionMatches(true, 0, "jar:", 0, 4)
+                : false;
         spec = spec.substring(start, limit);
 
         if (absoluteSpec) {
@@ -156,16 +155,14 @@
             int bangSlash = indexOfBangSlash(file);
             String toBangSlash = file.substring(0, bangSlash);
             String afterBangSlash = file.substring(bangSlash);
-            sun.net.www.ParseUtil canonizer = new ParseUtil();
-            afterBangSlash = canonizer.canonizeString(afterBangSlash);
+            afterBangSlash = ParseUtil.canonizeString(afterBangSlash);
             file = toBangSlash + afterBangSlash;
         }
         setURL(url, "jar", "", -1, file, ref);
     }
 
     private String parseAbsoluteSpec(String spec) {
-        URL url = null;
-        int index = -1;
+        int index;
         // check for !/
         if ((index = indexOfBangSlash(spec)) == -1) {
             throw new NullPointerException("no !/ in spec");
@@ -173,7 +170,7 @@
         // test the inner URL
         try {
             String innerSpec = spec.substring(0, index - 1);
-            url = new URL(innerSpec);
+            new URL(innerSpec);
         } catch (MalformedURLException e) {
             throw new NullPointerException("invalid url: " +
                                            spec + " (" + e + ")");
@@ -193,16 +190,16 @@
                                                ": no !/");
             }
             ctxFile = ctxFile.substring(0, bangSlash);
-        }
-        if (!ctxFile.endsWith("/") && (!spec.startsWith("/"))){
+        } else {
             // chop up the last component
             int lastSlash = ctxFile.lastIndexOf('/');
             if (lastSlash == -1) {
                 throw new NullPointerException("malformed " +
                                                "context url:" +
                                                url);
+            } else if (lastSlash < ctxFile.length() - 1) {
+                ctxFile = ctxFile.substring(0, lastSlash + 1);
             }
-            ctxFile = ctxFile.substring(0, lastSlash + 1);
         }
         return (ctxFile + spec);
     }
--- a/src/java.base/share/classes/sun/util/cldr/CLDRCalendarDataProviderImpl.java	Fri Feb 16 12:24:38 2018 -0800
+++ b/src/java.base/share/classes/sun/util/cldr/CLDRCalendarDataProviderImpl.java	Fri Feb 16 13:49:07 2018 -0800
@@ -97,10 +97,11 @@
     }
 
     private static Optional<Integer> retrieveInteger(String src, String region) {
-        return Arrays.stream(src.split(";"))
-            .filter(entry -> entry.contains(region))
-            .map(entry -> entry.substring(0, entry.indexOf(":")))
-            .findAny()
-            .map(Integer::parseInt);
+        int regionIndex = src.indexOf(region);
+        if (regionIndex >= 0) {
+            int start = src.lastIndexOf(';', regionIndex) + 1;
+            return Optional.of(Integer.parseInt(src, start, src.indexOf(':', start), 10));
+        }
+        return Optional.empty();
     }
 }
--- a/src/java.base/windows/classes/sun/nio/ch/PipeImpl.java	Fri Feb 16 12:24:38 2018 -0800
+++ b/src/java.base/windows/classes/sun/nio/ch/PipeImpl.java	Fri Feb 16 13:49:07 2018 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2002, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2002, 2018, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -110,7 +110,7 @@
                     ByteBuffer bb = ByteBuffer.allocate(NUM_SECRET_BYTES);
 
                     // Loopback address
-                    InetAddress lb = InetAddress.getByName("127.0.0.1");
+                    InetAddress lb = InetAddress.getLoopbackAddress();
                     assert(lb.isLoopbackAddress());
                     InetSocketAddress sa = null;
                     for(;;) {
--- a/src/java.scripting/share/classes/javax/script/ScriptEngineManager.java	Fri Feb 16 12:24:38 2018 -0800
+++ b/src/java.scripting/share/classes/javax/script/ScriptEngineManager.java	Fri Feb 16 13:49:07 2018 -0800
@@ -77,7 +77,10 @@
 
     private void init(final ClassLoader loader) {
         globalScope = new SimpleBindings();
-        engineSpis = new TreeSet<ScriptEngineFactory>(Comparator.comparing(ScriptEngineFactory::getEngineName));
+        engineSpis = new TreeSet<ScriptEngineFactory>(Comparator.comparing(
+            ScriptEngineFactory::getEngineName,
+            Comparator.nullsLast(Comparator.naturalOrder()))
+        );
         nameAssociations = new HashMap<String, ScriptEngineFactory>();
         extensionAssociations = new HashMap<String, ScriptEngineFactory>();
         mimeTypeAssociations = new HashMap<String, ScriptEngineFactory>();
--- a/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/DataPatchProcessor.java	Fri Feb 16 12:24:38 2018 -0800
+++ b/src/jdk.aot/share/classes/jdk.tools.jaotc/src/jdk/tools/jaotc/DataPatchProcessor.java	Fri Feb 16 13:49:07 2018 -0800
@@ -143,7 +143,7 @@
         int alignment = data.getAlignment();
         byte[] value = new byte[size];
         ByteBuffer buffer = ByteBuffer.wrap(value).order(ByteOrder.nativeOrder());
-        DataSection.emit(buffer, data, p -> {
+        DataSection.emit(buffer, data, (p, c) -> {
         });
         String targetSymbol = "data.M" + methodInfo.getCodeId() + "." + dataOffset;
         Symbol relocationSymbol = binaryContainer.getSymbol(targetSymbol);
--- a/src/jdk.internal.vm.compiler/.mx.graal/suite.py	Fri Feb 16 12:24:38 2018 -0800
+++ b/src/jdk.internal.vm.compiler/.mx.graal/suite.py	Fri Feb 16 13:49:07 2018 -0800
@@ -82,6 +82,24 @@
       "javaCompliance" : "1.8",
       "workingSets" : "API,SDK",
     },
+    "org.graalvm.collections" : {
+      "subDir" : "share/classes",
+      "sourceDirs" : ["src"],
+      "checkstyle" : "org.graalvm.word",
+      "javaCompliance" : "1.8",
+      "workingSets" : "API,SDK",
+    },
+    "org.graalvm.collections.test" : {
+      "subDir" : "share/classes",
+      "sourceDirs" : ["src"],
+      "dependencies" : [
+        "mx:JUNIT",
+        "org.graalvm.collections",
+      ],
+      "checkstyle" : "org.graalvm.word",
+      "javaCompliance" : "1.8",
+      "workingSets" : "API,SDK,Test",
+    },
 
     # ------------- Graal -------------
 
@@ -190,6 +208,9 @@
     "org.graalvm.util" : {
       "subDir" : "share/classes",
       "sourceDirs" : ["src"],
+      "dependencies" : [
+        "org.graalvm.collections",
+      ],
       "checkstyle" : "org.graalvm.compiler.graph",
       "javaCompliance" : "1.8",
       "workingSets" : "API,Graal",
@@ -201,6 +222,7 @@
       "dependencies" : [
         "mx:JUNIT",
         "org.graalvm.util",
+        "org.graalvm.compiler.core.test",
       ],
       "checkstyle" : "org.graalvm.compiler.graph",
       "javaCompliance" : "1.8",
@@ -970,10 +992,11 @@
       "workingSets" : "Graal,SPARC",
     },
 
-    "org.graalvm.compiler.core.sparc.test" : {
+    "org.graalvm.compiler.hotspot.sparc.test" : {
       "subDir" : "share/classes",
       "sourceDirs" : ["src"],
       "dependencies" : [
+        "org.graalvm.compiler.hotspot",
         "org.graalvm.compiler.lir.jtt",
         "JVMCI_HOTSPOT"
       ],
@@ -1007,6 +1030,7 @@
       "subDir" : "share/classes",
       "sourceDirs" : ["src"],
       "dependencies" : [
+        "org.graalvm.collections",
         "org.graalvm.compiler.debug",
         "org.graalvm.word",
       ],
@@ -1037,7 +1061,6 @@
       "sourceDirs" : ["src"],
       "dependencies" : [
         "org.graalvm.compiler.debug",
-        "org.graalvm.util",
         "mx:JUNIT",
       ],
       "checkstyle" : "org.graalvm.compiler.graph",
@@ -1225,11 +1248,11 @@
         "org.graalvm.compiler.asm.amd64.test",
         "org.graalvm.compiler.core.aarch64.test",
         "org.graalvm.compiler.core.amd64.test",
-        "org.graalvm.compiler.core.sparc.test",
         "org.graalvm.compiler.debug.test",
         "org.graalvm.compiler.hotspot.aarch64.test",
         "org.graalvm.compiler.hotspot.amd64.test",
         "org.graalvm.compiler.hotspot.lir.test",
+        "org.graalvm.compiler.hotspot.sparc.test",
         "org.graalvm.compiler.options.test",
         "org.graalvm.compiler.jtt",
         "org.graalvm.compiler.lir.jtt",
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.collections.test/src/org/graalvm/collections/test/EconomicMapImplTest.java	Fri Feb 16 13:49:07 2018 -0800
@@ -0,0 +1,126 @@
+/*
+ * Copyright (c) 2017, 2017, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.collections.test;
+
+import java.util.Arrays;
+import java.util.Iterator;
+
+import org.graalvm.collections.EconomicMap;
+import org.graalvm.collections.EconomicSet;
+import org.graalvm.collections.Equivalence;
+import org.graalvm.collections.UnmodifiableEconomicSet;
+import org.junit.Assert;
+import org.junit.Test;
+
+public class EconomicMapImplTest {
+
+    @Test(expected = UnsupportedOperationException.class)
+    public void testRemoveNull() {
+        EconomicMap<Integer, Integer> map = EconomicMap.create(10);
+        map.removeKey(null);
+    }
+
+    @Test
+    public void testInitFromHashSet() {
+        UnmodifiableEconomicSet<Integer> set = new UnmodifiableEconomicSet<Integer>() {
+
+            @Override
+            public boolean contains(Integer element) {
+                return element == 0;
+            }
+
+            @Override
+            public int size() {
+                return 1;
+            }
+
+            @Override
+            public boolean isEmpty() {
+                return false;
+            }
+
+            @Override
+            public Iterator<Integer> iterator() {
+                return new Iterator<Integer>() {
+
+                    private boolean visited = false;
+
+                    @Override
+                    public boolean hasNext() {
+                        return !visited;
+                    }
+
+                    @Override
+                    public Integer next() {
+                        if (visited) {
+                            return null;
+                        } else {
+                            visited = true;
+                            return 1;
+                        }
+                    }
+                };
+            }
+        };
+
+        EconomicSet<Integer> newSet = EconomicSet.create(Equivalence.DEFAULT, set);
+        Assert.assertEquals(newSet.size(), 1);
+    }
+
+    @Test
+    public void testCopyHash() {
+        EconomicSet<Integer> set = EconomicSet.create(Equivalence.IDENTITY);
+        set.addAll(Arrays.asList(0, 1, 2, 3, 4, 5, 6, 7, 8, 9));
+        EconomicSet<Integer> newSet = EconomicSet.create(Equivalence.IDENTITY, set);
+        Assert.assertEquals(newSet.size(), 10);
+        newSet.remove(8);
+        newSet.remove(9);
+        Assert.assertEquals(newSet.size(), 8);
+    }
+
+    @Test
+    public void testNewEquivalence() {
+        EconomicSet<Integer> set = EconomicSet.create(new Equivalence() {
+            @Override
+            public boolean equals(Object a, Object b) {
+                return false;
+            }
+
+            @Override
+            public int hashCode(Object o) {
+                return 0;
+            }
+        });
+        set.addAll(Arrays.asList(0, 1, 2, 3, 4, 5, 6, 7, 8, 9));
+        Assert.assertTrue(set.add(new Integer(0)));
+    }
+
+    @Test(expected = UnsupportedOperationException.class)
+    public void testMapPutNull() {
+        EconomicMap<Integer, Integer> map = EconomicMap.create();
+        map.put(null, null);
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.collections.test/src/org/graalvm/collections/test/EconomicMapLargeTest.java	Fri Feb 16 13:49:07 2018 -0800
@@ -0,0 +1,231 @@
+/*
+ * Copyright (c) 2017, 2017, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.collections.test;
+
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.LinkedHashMap;
+import java.util.Objects;
+import java.util.Random;
+
+import org.graalvm.collections.EconomicMap;
+import org.graalvm.collections.Equivalence;
+import org.graalvm.collections.MapCursor;
+import org.graalvm.collections.UnmodifiableMapCursor;
+import org.junit.Assert;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameter;
+import org.junit.runners.Parameterized.Parameters;
+
+@RunWith(Parameterized.class)
+public class EconomicMapLargeTest {
+
+    @Parameter(value = 0) public EconomicMap<Object, Object> testMap;
+    @Parameter(value = 1) public EconomicMap<Object, Object> referenceMap;
+    @Parameter(value = 2) public String name;
+
+    @Parameters(name = "{2}")
+    public static Collection<Object[]> data() {
+        return Arrays.asList(new Object[]{EconomicMap.create(Equivalence.DEFAULT), EconomicMap.create(Equivalence.DEFAULT), "EconomicMap"},
+                        new Object[]{EconomicMap.create(Equivalence.IDENTITY), EconomicMap.create(Equivalence.IDENTITY), "EconomicMap(IDENTITY)"},
+                        new Object[]{EconomicMap.create(Equivalence.IDENTITY_WITH_SYSTEM_HASHCODE), EconomicMap.create(Equivalence.IDENTITY_WITH_SYSTEM_HASHCODE),
+                                        "EconomicMap(IDENTITY_WITH_SYSTEM_HASHCODE)"},
+                        new Object[]{EconomicMap.create(Equivalence.DEFAULT), EconomicMap.wrapMap(new LinkedHashMap<>()), "EconomicMap<->wrapMap"},
+                        new Object[]{EconomicMap.wrapMap(new LinkedHashMap<>()), EconomicMap.wrapMap(new LinkedHashMap<>()), "wrapMap"});
+    }
+
+    private static int[] createRandomRange(Random random, int count) {
+        int[] result = new int[count];
+        for (int i = 0; i < count; ++i) {
+            int range = random.nextInt(14);
+            if (range == 0 || range > 10) {
+                range = Integer.MAX_VALUE;
+            } else if (range == 10) {
+                range = 100;
+            }
+            result[i] = range;
+        }
+        return result;
+    }
+
+    private static final class BadHashClass {
+        private int value;
+
+        BadHashClass(int randomInt) {
+            this.value = randomInt;
+        }
+
+        @Override
+        public int hashCode() {
+            return 0;
+        }
+
+        @Override
+        public boolean equals(Object other) {
+            if (other instanceof BadHashClass) {
+                BadHashClass badHashClass = (BadHashClass) other;
+                return badHashClass.value == value;
+            }
+            return false;
+        }
+    }
+
+    interface MapAction {
+        Object perform(EconomicMap<Object, Object> map, int randomInt);
+    }
+
+    static final Object EXISTING_VALUE = new Object();
+
+    static final MapAction[] INCREASE_ACTIONS = new MapAction[]{
+                    (map, randomInt) -> map.put(randomInt, "value"),
+                    (map, randomInt) -> map.get(randomInt)
+    };
+
+    static final MapAction[] ACTIONS = new MapAction[]{
+                    (map, randomInt) -> map.removeKey(randomInt),
+                    (map, randomInt) -> map.put(randomInt, "value"),
+                    (map, randomInt) -> map.put(randomInt, null),
+                    (map, randomInt) -> map.put(EXISTING_VALUE, randomInt),
+                    (map, randomInt) -> {
+                        if (randomInt == 0) {
+                            map.clear();
+                        }
+                        return map.isEmpty();
+                    },
+                    (map, randomInt) -> map.containsKey(randomInt),
+                    (map, randomInt) -> map.get(randomInt),
+                    (map, randomInt) -> map.put(new BadHashClass(randomInt), "unique"),
+                    (map, randomInt) -> {
+                        if (randomInt == 0) {
+                            map.replaceAll((key, value) -> Objects.toString(value) + "!");
+                        }
+                        return map.isEmpty();
+                    }
+
+    };
+
+    @Test
+    public void testVeryLarge() {
+        testMap.clear();
+        referenceMap.clear();
+
+        Random random = new Random(0);
+        for (int i = 0; i < 200000; ++i) {
+            for (int j = 0; j < INCREASE_ACTIONS.length; ++j) {
+                int nextInt = random.nextInt(10000000);
+                MapAction action = INCREASE_ACTIONS[j];
+                Object result = action.perform(testMap, nextInt);
+                Object referenceResult = action.perform(referenceMap, nextInt);
+                Assert.assertEquals(result, referenceResult);
+            }
+        }
+    }
+
+    /**
+     * Tests a sequence of random operations on the map.
+     */
+    @Test
+    public void testAddRemove() {
+        testMap.clear();
+        referenceMap.clear();
+
+        for (int seed = 0; seed < 10; ++seed) {
+            Random random = new Random(seed);
+            int[] ranges = createRandomRange(random, ACTIONS.length);
+            int value = random.nextInt(10000);
+            for (int i = 0; i < value; ++i) {
+                for (int j = 0; j < ACTIONS.length; ++j) {
+                    if (random.nextInt(ranges[j]) == 0) {
+                        int nextInt = random.nextInt(100);
+                        MapAction action = ACTIONS[j];
+                        Object result = action.perform(testMap, nextInt);
+                        Object referenceResult = action.perform(referenceMap, nextInt);
+                        Assert.assertEquals(result, referenceResult);
+                        if (j % 100 == 0) {
+                            checkEquality(testMap, referenceMap);
+                        }
+                    }
+                }
+
+                if (random.nextInt(20) == 0) {
+                    removeElement(random.nextInt(100), testMap, referenceMap);
+                }
+            }
+        }
+    }
+
+    private static void removeElement(int index, EconomicMap<?, ?> map, EconomicMap<?, ?> referenceMap) {
+        Assert.assertEquals(referenceMap.size(), map.size());
+        MapCursor<?, ?> cursor = map.getEntries();
+        MapCursor<?, ?> referenceCursor = referenceMap.getEntries();
+        int z = 0;
+        while (cursor.advance()) {
+            Assert.assertTrue(referenceCursor.advance());
+            Assert.assertEquals(referenceCursor.getKey(), cursor.getKey());
+            Assert.assertEquals(referenceCursor.getValue(), cursor.getValue());
+            if (index == z) {
+                cursor.remove();
+                referenceCursor.remove();
+            }
+            ++z;
+        }
+
+        Assert.assertFalse(referenceCursor.advance());
+    }
+
+    private static void checkEquality(EconomicMap<?, ?> map, EconomicMap<?, ?> referenceMap) {
+        Assert.assertEquals(referenceMap.size(), map.size());
+
+        // Check entries.
+        UnmodifiableMapCursor<?, ?> cursor = map.getEntries();
+        UnmodifiableMapCursor<?, ?> referenceCursor = referenceMap.getEntries();
+        while (cursor.advance()) {
+            Assert.assertTrue(referenceCursor.advance());
+            Assert.assertEquals(referenceCursor.getKey(), cursor.getKey());
+            Assert.assertEquals(referenceCursor.getValue(), cursor.getValue());
+        }
+
+        // Check keys.
+        Iterator<?> iterator = map.getKeys().iterator();
+        Iterator<?> referenceIterator = referenceMap.getKeys().iterator();
+        while (iterator.hasNext()) {
+            Assert.assertTrue(referenceIterator.hasNext());
+            Assert.assertEquals(iterator.next(), referenceIterator.next());
+        }
+
+        // Check values.
+        iterator = map.getValues().iterator();
+        referenceIterator = referenceMap.getValues().iterator();
+        while (iterator.hasNext()) {
+            Assert.assertTrue(referenceIterator.hasNext());
+            Assert.assertEquals(iterator.next(), referenceIterator.next());
+        }
+        Assert.assertFalse(referenceIterator.hasNext());
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.collections.test/src/org/graalvm/collections/test/EconomicMapTest.java	Fri Feb 16 13:49:07 2018 -0800
@@ -0,0 +1,72 @@
+/*
+ * Copyright (c) 2017, 2017, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.collections.test;
+
+import java.util.LinkedHashMap;
+
+import org.graalvm.collections.EconomicMap;
+import org.graalvm.collections.UnmodifiableEconomicMap;
+import org.junit.Assert;
+import org.junit.Test;
+
+public class EconomicMapTest {
+
+    @Test
+    public void testMapGetDefault() {
+        EconomicMap<Integer, Integer> map = EconomicMap.create();
+        map.put(0, 1);
+        Assert.assertEquals(map.get(0, 2), Integer.valueOf(1));
+        Assert.assertEquals(map.get(1, 2), Integer.valueOf(2));
+    }
+
+    @Test
+    public void testMapPutAll() {
+        EconomicMap<Integer, Integer> map = EconomicMap.create();
+        EconomicMap<Integer, Integer> newMap = EconomicMap.wrapMap(new LinkedHashMap<>());
+        newMap.put(1, 1);
+        newMap.put(2, 4);
+        map.putAll(newMap);
+        Assert.assertEquals(map.size(), 2);
+
+        UnmodifiableEconomicMap<Integer, Integer> unmodifiableEconomicMap = EconomicMap.create(newMap);
+
+        map.removeKey(1);
+        map.put(2, 2);
+        map.put(3, 9);
+
+        map.putAll(unmodifiableEconomicMap);
+        Assert.assertEquals(map.size(), 3);
+        Assert.assertEquals(map.get(2), Integer.valueOf(4));
+    }
+
+    @Test
+    public void testToString() {
+        EconomicMap<Integer, Integer> map = EconomicMap.create();
+        map.put(0, 0);
+        map.put(1, 1);
+        Assert.assertEquals(map.toString(), "map(size=2, {(0,0),(1,1)})");
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.collections.test/src/org/graalvm/collections/test/EconomicSetTest.java	Fri Feb 16 13:49:07 2018 -0800
@@ -0,0 +1,148 @@
+/*
+ * Copyright (c) 2017, 2017, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.collections.test;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Iterator;
+
+import org.graalvm.collections.EconomicSet;
+import org.graalvm.collections.Equivalence;
+import org.junit.Assert;
+import org.junit.Test;
+
+public class EconomicSetTest {
+
+    @Test
+    public void testUtilities() {
+        EconomicSet<Integer> set = EconomicSet.create(0);
+        set.add(0);
+        Assert.assertTrue(set.add(1));
+        Assert.assertEquals(set.size(), 2);
+        Assert.assertFalse(set.add(1));
+        Assert.assertEquals(set.size(), 2);
+        set.remove(1);
+        Assert.assertEquals(set.size(), 1);
+        set.remove(2);
+        Assert.assertEquals(set.size(), 1);
+        Assert.assertTrue(set.add(1));
+        set.clear();
+        Assert.assertEquals(set.size(), 0);
+    }
+
+    @Test
+    public void testAddAll() {
+        EconomicSet<Integer> set = EconomicSet.create();
+        set.addAll(Arrays.asList(0, 1, 0));
+        Assert.assertEquals(set.size(), 2);
+
+        EconomicSet<Integer> newSet = EconomicSet.create();
+        newSet.addAll(Arrays.asList(1, 2));
+        Assert.assertEquals(newSet.size(), 2);
+        newSet.addAll(set);
+        Assert.assertEquals(newSet.size(), 3);
+    }
+
+    @Test
+    public void testRemoveAll() {
+        EconomicSet<Integer> set = EconomicSet.create();
+        set.addAll(Arrays.asList(0, 1));
+
+        set.removeAll(Arrays.asList(1, 2));
+        Assert.assertEquals(set.size(), 1);
+
+        set.removeAll(EconomicSet.create(set));
+        Assert.assertEquals(set.size(), 0);
+    }
+
+    @Test
+    public void testRetainAll() {
+        EconomicSet<Integer> set = EconomicSet.create();
+        set.addAll(Arrays.asList(0, 1, 2));
+
+        EconomicSet<Integer> newSet = EconomicSet.create();
+        newSet.addAll(Arrays.asList(2, 3));
+
+        set.retainAll(newSet);
+        Assert.assertEquals(set.size(), 1);
+    }
+
+    @Test
+    public void testToArray() {
+        EconomicSet<Integer> set = EconomicSet.create();
+        set.addAll(Arrays.asList(0, 1));
+        Assert.assertArrayEquals(set.toArray(new Integer[2]), new Integer[]{0, 1});
+    }
+
+    @Test
+    public void testToString() {
+        EconomicSet<Integer> set = EconomicSet.create();
+        set.addAll(Arrays.asList(0, 1));
+        Assert.assertEquals(set.toString(), "set(size=2, {0,1})");
+    }
+
+    @Test(expected = UnsupportedOperationException.class)
+    public void testToUnalignedArray() {
+        Assert.assertArrayEquals(EconomicSet.create().toArray(new Integer[2]), new Integer[0]);
+    }
+
+    @Test
+    public void testSetRemoval() {
+        ArrayList<Integer> initialList = new ArrayList<>();
+        ArrayList<Integer> removalList = new ArrayList<>();
+        ArrayList<Integer> finalList = new ArrayList<>();
+        EconomicSet<Integer> set = EconomicSet.create(Equivalence.IDENTITY);
+        set.add(1);
+        set.add(2);
+        set.add(3);
+        set.add(4);
+        set.add(5);
+        set.add(6);
+        set.add(7);
+        set.add(8);
+        set.add(9);
+        Iterator<Integer> i1 = set.iterator();
+        while (i1.hasNext()) {
+            initialList.add(i1.next());
+        }
+        int size = 0;
+        Iterator<Integer> i2 = set.iterator();
+        while (i2.hasNext()) {
+            Integer elem = i2.next();
+            if (size++ < 8) {
+                i2.remove();
+            }
+            removalList.add(elem);
+        }
+        Iterator<Integer> i3 = set.iterator();
+        while (i3.hasNext()) {
+            finalList.add(i3.next());
+        }
+        Assert.assertEquals(initialList, removalList);
+        Assert.assertEquals(1, finalList.size());
+        Assert.assertEquals(new Integer(9), finalList.get(0));
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.collections.test/src/org/graalvm/collections/test/EquivalenceTest.java	Fri Feb 16 13:49:07 2018 -0800
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2017, 2017, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.collections.test;
+
+import org.graalvm.collections.Equivalence;
+import org.junit.Assert;
+import org.junit.Test;
+
+public class EquivalenceTest {
+
+    private static final String TEST_STRING = "Graal";
+    private static final String TEST_STRING2 = "Graal2";
+
+    @Test
+    public void testDEFAULT() {
+        Assert.assertTrue(Equivalence.DEFAULT.equals(TEST_STRING, new String(TEST_STRING)));
+        Assert.assertEquals(Equivalence.DEFAULT.hashCode(TEST_STRING), Equivalence.DEFAULT.hashCode(new String(TEST_STRING)));
+        Assert.assertFalse(Equivalence.DEFAULT.equals(TEST_STRING, TEST_STRING2));
+        Assert.assertNotEquals(Equivalence.DEFAULT.hashCode(TEST_STRING), Equivalence.DEFAULT.hashCode(TEST_STRING2));
+    }
+
+    @Test
+    public void testIDENTITY() {
+        Assert.assertFalse(Equivalence.IDENTITY.equals(TEST_STRING, new String(TEST_STRING)));
+        Assert.assertEquals(Equivalence.IDENTITY.hashCode(TEST_STRING), Equivalence.IDENTITY.hashCode(new String(TEST_STRING)));
+        Assert.assertFalse(Equivalence.IDENTITY.equals(TEST_STRING, TEST_STRING2));
+        Assert.assertNotEquals(Equivalence.IDENTITY.hashCode(TEST_STRING), Equivalence.IDENTITY.hashCode(TEST_STRING2));
+    }
+
+    @Test
+    public void testIDENTITYWITHSYSTEMHASHCODE() {
+        Assert.assertFalse(Equivalence.IDENTITY_WITH_SYSTEM_HASHCODE.equals(TEST_STRING, new String(TEST_STRING)));
+        Assert.assertNotEquals(Equivalence.IDENTITY_WITH_SYSTEM_HASHCODE.hashCode(TEST_STRING), Equivalence.IDENTITY_WITH_SYSTEM_HASHCODE.hashCode(new String(TEST_STRING)));
+        Assert.assertFalse(Equivalence.IDENTITY_WITH_SYSTEM_HASHCODE.equals(TEST_STRING, TEST_STRING2));
+        Assert.assertNotEquals(Equivalence.IDENTITY_WITH_SYSTEM_HASHCODE.hashCode(TEST_STRING), Equivalence.IDENTITY_WITH_SYSTEM_HASHCODE.hashCode(TEST_STRING2));
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.collections.test/src/org/graalvm/collections/test/PairTest.java	Fri Feb 16 13:49:07 2018 -0800
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2017, 2017, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.collections.test;
+
+import org.graalvm.collections.Pair;
+import org.junit.Assert;
+import org.junit.Test;
+
+public class PairTest {
+
+    @Test
+    public void testCreate() {
+        Assert.assertEquals(Pair.create(null, null), Pair.empty());
+        Assert.assertNotEquals(Pair.create(null, null), null);
+        Assert.assertEquals(Pair.createLeft(null), Pair.empty());
+        Assert.assertEquals(Pair.createRight(null), Pair.empty());
+        Assert.assertEquals(Pair.create(1, null), Pair.createLeft(1));
+        Assert.assertEquals(Pair.create(null, 1), Pair.createRight(1));
+    }
+
+    @Test
+    public void testUtilities() {
+        Pair<Integer, Integer> pair = Pair.create(1, null);
+        Assert.assertEquals(pair.getLeft(), Integer.valueOf(1));
+        Assert.assertEquals(pair.getRight(), null);
+        Assert.assertEquals(pair.toString(), "(1, null)");
+        Assert.assertEquals(pair.hashCode(), Pair.createLeft(1).hashCode());
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.collections/src/org/graalvm/collections/EconomicMap.java	Fri Feb 16 13:49:07 2018 -0800
@@ -0,0 +1,265 @@
+/*
+ * Copyright (c) 2017, 2017, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.collections;
+
+import java.util.Iterator;
+import java.util.Map;
+import java.util.function.BiFunction;
+
+/**
+ * Memory efficient map data structure.
+ *
+ * @since 1.0
+ */
+public interface EconomicMap<K, V> extends UnmodifiableEconomicMap<K, V> {
+
+    /**
+     * Associates {@code value} with {@code key} in this map. If the map previously contained a
+     * mapping for {@code key}, the old value is replaced by {@code value}.
+     *
+     * @return the previous value associated with {@code key}, or {@code null} if there was no
+     *         mapping for {@code key}.
+     * @since 1.0
+     */
+    V put(K key, V value);
+
+    /**
+     * Copies all of the mappings from {@code other} to this map.
+     *
+     * @since 1.0
+     */
+    default void putAll(EconomicMap<K, V> other) {
+        MapCursor<K, V> e = other.getEntries();
+        while (e.advance()) {
+            put(e.getKey(), e.getValue());
+        }
+    }
+
+    /**
+     * Copies all of the mappings from {@code other} to this map.
+     *
+     * @since 1.0
+     */
+    default void putAll(UnmodifiableEconomicMap<? extends K, ? extends V> other) {
+        UnmodifiableMapCursor<? extends K, ? extends V> entry = other.getEntries();
+        while (entry.advance()) {
+            put(entry.getKey(), entry.getValue());
+        }
+    }
+
+    /**
+     * Removes all of the mappings from this map. The map will be empty after this call returns.
+     *
+     * @since 1.0
+     */
+    void clear();
+
+    /**
+     * Removes the mapping for {@code key} from this map if it is present. The map will not contain
+     * a mapping for {@code key} once the call returns.
+     *
+     * @return the previous value associated with {@code key}, or {@code null} if there was no
+     *         mapping for {@code key}.
+     * @since 1.0
+     */
+    V removeKey(K key);
+
+    /**
+     * Returns a {@link MapCursor} view of the mappings contained in this map.
+     *
+     * @since 1.0
+     */
+    @Override
+    MapCursor<K, V> getEntries();
+
+    /**
+     * Replaces each entry's value with the result of invoking {@code function} on that entry until
+     * all entries have been processed or the function throws an exception. Exceptions thrown by the
+     * function are relayed to the caller.
+     *
+     * @since 1.0
+     */
+    void replaceAll(BiFunction<? super K, ? super V, ? extends V> function);
+
+    /**
+     * Creates a new map that guarantees insertion order on the key set with the default
+     * {@link Equivalence#DEFAULT} comparison strategy for keys.
+     *
+     * @since 1.0
+     */
+    static <K, V> EconomicMap<K, V> create() {
+        return EconomicMap.create(Equivalence.DEFAULT);
+    }
+
+    /**
+     * Creates a new map that guarantees insertion order on the key set with the default
+     * {@link Equivalence#DEFAULT} comparison strategy for keys and initializes with a specified
+     * capacity.
+     *
+     * @since 1.0
+     */
+    static <K, V> EconomicMap<K, V> create(int initialCapacity) {
+        return EconomicMap.create(Equivalence.DEFAULT, initialCapacity);
+    }
+
+    /**
+     * Creates a new map that guarantees insertion order on the key set with the given comparison
+     * strategy for keys.
+     *
+     * @since 1.0
+     */
+    static <K, V> EconomicMap<K, V> create(Equivalence strategy) {
+        return EconomicMapImpl.create(strategy, false);
+    }
+
+    /**
+     * Creates a new map that guarantees insertion order on the key set with the default
+     * {@link Equivalence#DEFAULT} comparison strategy for keys and copies all elements from the
+     * specified existing map.
+     *
+     * @since 1.0
+     */
+    static <K, V> EconomicMap<K, V> create(UnmodifiableEconomicMap<K, V> m) {
+        return EconomicMap.create(Equivalence.DEFAULT, m);
+    }
+
+    /**
+     * Creates a new map that guarantees insertion order on the key set and copies all elements from
+     * the specified existing map.
+     *
+     * @since 1.0
+     */
+    static <K, V> EconomicMap<K, V> create(Equivalence strategy, UnmodifiableEconomicMap<K, V> m) {
+        return EconomicMapImpl.create(strategy, m, false);
+    }
+
+    /**
+     * Creates a new map that guarantees insertion order on the key set and initializes with a
+     * specified capacity.
+     *
+     * @since 1.0
+     */
+    static <K, V> EconomicMap<K, V> create(Equivalence strategy, int initialCapacity) {
+        return EconomicMapImpl.create(strategy, initialCapacity, false);
+    }
+
+    /**
+     * Wraps an existing {@link Map} as an {@link EconomicMap}.
+     *
+     * @since 1.0
+     */
+    static <K, V> EconomicMap<K, V> wrapMap(Map<K, V> map) {
+        return new EconomicMap<K, V>() {
+
+            @Override
+            public V get(K key) {
+                V result = map.get(key);
+                return result;
+            }
+
+            @Override
+            public V put(K key, V value) {
+                V result = map.put(key, value);
+                return result;
+            }
+
+            @Override
+            public int size() {
+                int result = map.size();
+                return result;
+            }
+
+            @Override
+            public boolean containsKey(K key) {
+                return map.containsKey(key);
+            }
+
+            @Override
+            public void clear() {
+                map.clear();
+            }
+
+            @Override
+            public V removeKey(K key) {
+                V result = map.remove(key);
+                return result;
+            }
+
+            @Override
+            public Iterable<V> getValues() {
+                return map.values();
+            }
+
+            @Override
+            public Iterable<K> getKeys() {
+                return map.keySet();
+            }
+
+            @Override
+            public boolean isEmpty() {
+                return map.isEmpty();
+            }
+
+            @Override
+            public MapCursor<K, V> getEntries() {
+                Iterator<java.util.Map.Entry<K, V>> iterator = map.entrySet().iterator();
+                return new MapCursor<K, V>() {
+
+                    private Map.Entry<K, V> current;
+
+                    @Override
+                    public boolean advance() {
+                        boolean result = iterator.hasNext();
+                        if (result) {
+                            current = iterator.next();
+                        }
+
+                        return result;
+                    }
+
+                    @Override
+                    public K getKey() {
+                        return current.getKey();
+                    }
+
+                    @Override
+                    public V getValue() {
+                        return current.getValue();
+                    }
+
+                    @Override
+                    public void remove() {
+                        iterator.remove();
+                    }
+                };
+            }
+
+            @Override
+            public void replaceAll(BiFunction<? super K, ? super V, ? extends V> function) {
+                map.replaceAll(function);
+            }
+        };
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.collections/src/org/graalvm/collections/EconomicMapImpl.java	Fri Feb 16 13:49:07 2018 -0800
@@ -0,0 +1,857 @@
+/*
+ * Copyright (c) 2017, 2017, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.collections;
+
+import java.util.Iterator;
+import java.util.Objects;
+import java.util.function.BiFunction;
+
+/**
+ * Implementation of a map with a memory-efficient structure that always preserves insertion order
+ * when iterating over keys. Particularly efficient when number of entries is 0 or smaller equal
+ * {@link #INITIAL_CAPACITY} or smaller 256.
+ *
+ * The key/value pairs are kept in an expanding flat object array with keys at even indices and
+ * values at odd indices. If the map has smaller or equal to {@link #HASH_THRESHOLD} entries, there
+ * is no additional hash data structure and comparisons are done via linear checking of the
+ * key/value pairs. For the case where the equality check is particularly cheap (e.g., just an
+ * object identity comparison), this limit below which the map is without an actual hash table is
+ * higher and configured at {@link #HASH_THRESHOLD_IDENTITY_COMPARE}.
+ *
+ * When the hash table needs to be constructed, the field {@link #hashArray} becomes a new hash
+ * array where an entry of 0 means no hit and otherwise denotes the entry number in the
+ * {@link #entries} array. The hash array is interpreted as an actual byte array if the indices fit
+ * within 8 bit, or as an array of short values if the indices fit within 16 bit, or as an array of
+ * integer values in other cases.
+ *
+ * Hash collisions are handled by chaining a linked list of {@link CollisionLink} objects that take
+ * the place of the values in the {@link #entries} array.
+ *
+ * Removing entries will put {@code null} into the {@link #entries} array. If the occupation of the
+ * map falls below a specific threshold, the map will be compressed via the
+ * {@link #maybeCompress(int)} method.
+ */
+final class EconomicMapImpl<K, V> implements EconomicMap<K, V>, EconomicSet<K> {
+
+    /**
+     * Initial number of key/value pair entries that is allocated in the first entries array.
+     */
+    private static final int INITIAL_CAPACITY = 4;
+
+    /**
+     * Maximum number of entries that are moved linearly forward if a key is removed.
+     */
+    private static final int COMPRESS_IMMEDIATE_CAPACITY = 8;
+
+    /**
+     * Minimum number of key/value pair entries added when the entries array is increased in size.
+     */
+    private static final int MIN_CAPACITY_INCREASE = 8;
+
+    /**
+     * Number of entries above which a hash table is created.
+     */
+    private static final int HASH_THRESHOLD = 4;
+
+    /**
+     * Number of entries above which a hash table is created when equality can be checked with
+     * object identity.
+     */
+    private static final int HASH_THRESHOLD_IDENTITY_COMPARE = 8;
+
+    /**
+     * Maximum number of entries allowed in the map.
+     */
+    private static final int MAX_ELEMENT_COUNT = Integer.MAX_VALUE >> 1;
+
+    /**
+     * Number of entries above which more than 1 byte is necessary for the hash index.
+     */
+    private static final int LARGE_HASH_THRESHOLD = ((1 << Byte.SIZE) << 1);
+
+    /**
+     * Number of entries above which more than 2 bytes are are necessary for the hash index.
+     */
+    private static final int VERY_LARGE_HASH_THRESHOLD = (LARGE_HASH_THRESHOLD << Byte.SIZE);
+
+    /**
+     * Total number of entries (actual entries plus deleted entries).
+     */
+    private int totalEntries;
+
+    /**
+     * Number of deleted entries.
+     */
+    private int deletedEntries;
+
+    /**
+     * Entries array with even indices storing keys and odd indices storing values.
+     */
+    private Object[] entries;
+
+    /**
+     * Hash array that is interpreted either as byte or short or int array depending on number of
+     * map entries.
+     */
+    private byte[] hashArray;
+
+    /**
+     * The strategy used for comparing keys or {@code null} for denoting special strategy
+     * {@link Equivalence#IDENTITY}.
+     */
+    private final Equivalence strategy;
+
+    /**
+     * Intercept method for debugging purposes.
+     */
+    private static <K, V> EconomicMapImpl<K, V> intercept(EconomicMapImpl<K, V> map) {
+        return map;
+    }
+
+    public static <K, V> EconomicMapImpl<K, V> create(Equivalence strategy, boolean isSet) {
+        return intercept(new EconomicMapImpl<>(strategy, isSet));
+    }
+
+    public static <K, V> EconomicMapImpl<K, V> create(Equivalence strategy, int initialCapacity, boolean isSet) {
+        return intercept(new EconomicMapImpl<>(strategy, initialCapacity, isSet));
+    }
+
+    public static <K, V> EconomicMapImpl<K, V> create(Equivalence strategy, UnmodifiableEconomicMap<K, V> other, boolean isSet) {
+        return intercept(new EconomicMapImpl<>(strategy, other, isSet));
+    }
+
+    public static <K, V> EconomicMapImpl<K, V> create(Equivalence strategy, UnmodifiableEconomicSet<K> other, boolean isSet) {
+        return intercept(new EconomicMapImpl<>(strategy, other, isSet));
+    }
+
+    private EconomicMapImpl(Equivalence strategy, boolean isSet) {
+        if (strategy == Equivalence.IDENTITY) {
+            this.strategy = null;
+        } else {
+            this.strategy = strategy;
+        }
+        this.isSet = isSet;
+    }
+
+    private EconomicMapImpl(Equivalence strategy, int initialCapacity, boolean isSet) {
+        this(strategy, isSet);
+        init(initialCapacity);
+    }
+
+    private EconomicMapImpl(Equivalence strategy, UnmodifiableEconomicMap<K, V> other, boolean isSet) {
+        this(strategy, isSet);
+        if (!initFrom(other)) {
+            init(other.size());
+            putAll(other);
+        }
+    }
+
+    private EconomicMapImpl(Equivalence strategy, UnmodifiableEconomicSet<K> other, boolean isSet) {
+        this(strategy, isSet);
+        if (!initFrom(other)) {
+            init(other.size());
+            addAll(other);
+        }
+    }
+
+    @SuppressWarnings("unchecked")
+    private boolean initFrom(Object o) {
+        if (o instanceof EconomicMapImpl) {
+            EconomicMapImpl<K, V> otherMap = (EconomicMapImpl<K, V>) o;
+            // We are only allowed to directly copy if the strategies of the two maps are the same.
+            if (strategy == otherMap.strategy) {
+                totalEntries = otherMap.totalEntries;
+                deletedEntries = otherMap.deletedEntries;
+                if (otherMap.entries != null) {
+                    entries = otherMap.entries.clone();
+                }
+                if (otherMap.hashArray != null) {
+                    hashArray = otherMap.hashArray.clone();
+                }
+                return true;
+            }
+        }
+        return false;
+    }
+
+    private void init(int size) {
+        if (size > INITIAL_CAPACITY) {
+            entries = new Object[size << 1];
+        }
+    }
+
+    /**
+     * Links the collisions. Needs to be immutable class for allowing efficient shallow copy from
+     * other map on construction.
+     */
+    private static final class CollisionLink {
+
+        CollisionLink(Object value, int next) {
+            this.value = value;
+            this.next = next;
+        }
+
+        final Object value;
+
+        /**
+         * Index plus one of the next entry in the collision link chain.
+         */
+        final int next;
+    }
+
+    @SuppressWarnings("unchecked")
+    @Override
+    public V get(K key) {
+        Objects.requireNonNull(key);
+
+        int index = find(key);
+        if (index != -1) {
+            return (V) getValue(index);
+        }
+        return null;
+    }
+
+    private int find(K key) {
+        if (hasHashArray()) {
+            return findHash(key);
+        } else {
+            return findLinear(key);
+        }
+    }
+
+    private int findLinear(K key) {
+        for (int i = 0; i < totalEntries; i++) {
+            Object entryKey = entries[i << 1];
+            if (entryKey != null && compareKeys(key, entryKey)) {
+                return i;
+            }
+        }
+        return -1;
+    }
+
+    private boolean compareKeys(Object key, Object entryKey) {
+        if (key == entryKey) {
+            return true;
+        }
+        if (strategy != null && strategy != Equivalence.IDENTITY_WITH_SYSTEM_HASHCODE) {
+            if (strategy == Equivalence.DEFAULT) {
+                return key.equals(entryKey);
+            } else {
+                return strategy.equals(key, entryKey);
+            }
+        }
+        return false;
+    }
+
+    private int findHash(K key) {
+        int index = getHashArray(getHashIndex(key)) - 1;
+        if (index != -1) {
+            Object entryKey = getKey(index);
+            if (compareKeys(key, entryKey)) {
+                return index;
+            } else {
+                Object entryValue = getRawValue(index);
+                if (entryValue instanceof CollisionLink) {
+                    return findWithCollision(key, (CollisionLink) entryValue);
+                }
+            }
+        }
+
+        return -1;
+    }
+
+    private int findWithCollision(K key, CollisionLink initialEntryValue) {
+        int index;
+        Object entryKey;
+        CollisionLink entryValue = initialEntryValue;
+        while (true) {
+            CollisionLink collisionLink = entryValue;
+            index = collisionLink.next;
+            entryKey = getKey(index);
+            if (compareKeys(key, entryKey)) {
+                return index;
+            } else {
+                Object value = getRawValue(index);
+                if (value instanceof CollisionLink) {
+                    entryValue = (CollisionLink) getRawValue(index);
+                } else {
+                    return -1;
+                }
+            }
+        }
+    }
+
+    private int getHashArray(int index) {
+        if (entries.length < LARGE_HASH_THRESHOLD) {
+            return (hashArray[index] & 0xFF);
+        } else if (entries.length < VERY_LARGE_HASH_THRESHOLD) {
+            int adjustedIndex = index << 1;
+            return (hashArray[adjustedIndex] & 0xFF) | ((hashArray[adjustedIndex + 1] & 0xFF) << 8);
+        } else {
+            int adjustedIndex = index << 2;
+            return (hashArray[adjustedIndex] & 0xFF) | ((hashArray[adjustedIndex + 1] & 0xFF) << 8) | ((hashArray[adjustedIndex + 2] & 0xFF) << 16) | ((hashArray[adjustedIndex + 3] & 0xFF) << 24);
+        }
+    }
+
+    private void setHashArray(int index, int value) {
+        if (entries.length < LARGE_HASH_THRESHOLD) {
+            hashArray[index] = (byte) value;
+        } else if (entries.length < VERY_LARGE_HASH_THRESHOLD) {
+            int adjustedIndex = index << 1;
+            hashArray[adjustedIndex] = (byte) value;
+            hashArray[adjustedIndex + 1] = (byte) (value >> 8);
+        } else {
+            int adjustedIndex = index << 2;
+            hashArray[adjustedIndex] = (byte) value;
+            hashArray[adjustedIndex + 1] = (byte) (value >> 8);
+            hashArray[adjustedIndex + 2] = (byte) (value >> 16);
+            hashArray[adjustedIndex + 3] = (byte) (value >> 24);
+        }
+    }
+
+    private int findAndRemoveHash(Object key) {
+        int hashIndex = getHashIndex(key);
+        int index = getHashArray(hashIndex) - 1;
+        if (index != -1) {
+            Object entryKey = getKey(index);
+            if (compareKeys(key, entryKey)) {
+                Object value = getRawValue(index);
+                int nextIndex = -1;
+                if (value instanceof CollisionLink) {
+                    CollisionLink collisionLink = (CollisionLink) value;
+                    nextIndex = collisionLink.next;
+                }
+                setHashArray(hashIndex, nextIndex + 1);
+                return index;
+            } else {
+                Object entryValue = getRawValue(index);
+                if (entryValue instanceof CollisionLink) {
+                    return findAndRemoveWithCollision(key, (CollisionLink) entryValue, index);
+                }
+            }
+        }
+
+        return -1;
+    }
+
+    private int findAndRemoveWithCollision(Object key, CollisionLink initialEntryValue, int initialIndexValue) {
+        int index;
+        Object entryKey;
+        CollisionLink entryValue = initialEntryValue;
+        int lastIndex = initialIndexValue;
+        while (true) {
+            CollisionLink collisionLink = entryValue;
+            index = collisionLink.next;
+            entryKey = getKey(index);
+            if (compareKeys(key, entryKey)) {
+                Object value = getRawValue(index);
+                if (value instanceof CollisionLink) {
+                    CollisionLink thisCollisionLink = (CollisionLink) value;
+                    setRawValue(lastIndex, new CollisionLink(collisionLink.value, thisCollisionLink.next));
+                } else {
+                    setRawValue(lastIndex, collisionLink.value);
+                }
+                return index;
+            } else {
+                Object value = getRawValue(index);
+                if (value instanceof CollisionLink) {
+                    entryValue = (CollisionLink) getRawValue(index);
+                    lastIndex = index;
+                } else {
+                    return -1;
+                }
+            }
+        }
+    }
+
+    private int getHashIndex(Object key) {
+        int hash;
+        if (strategy != null && strategy != Equivalence.DEFAULT) {
+            if (strategy == Equivalence.IDENTITY_WITH_SYSTEM_HASHCODE) {
+                hash = System.identityHashCode(key);
+            } else {
+                hash = strategy.hashCode(key);
+            }
+        } else {
+            hash = key.hashCode();
+        }
+        hash = hash ^ (hash >>> 16);
+        return hash & (getHashTableSize() - 1);
+    }
+
+    @SuppressWarnings("unchecked")
+    @Override
+    public V put(K key, V value) {
+        if (key == null) {
+            throw new UnsupportedOperationException("null not supported as key!");
+        }
+        int index = find(key);
+        if (index != -1) {
+            Object oldValue = getValue(index);
+            setValue(index, value);
+            return (V) oldValue;
+        }
+
+        int nextEntryIndex = totalEntries;
+        if (entries == null) {
+            entries = new Object[INITIAL_CAPACITY << 1];
+        } else if (entries.length == nextEntryIndex << 1) {
+            grow();
+
+            assert entries.length > totalEntries << 1;
+            // Can change if grow is actually compressing.
+            nextEntryIndex = totalEntries;
+        }
+
+        setKey(nextEntryIndex, key);
+        setValue(nextEntryIndex, value);
+        totalEntries++;
+
+        if (hasHashArray()) {
+            // Rehash on collision if hash table is more than three quarters full.
+            boolean rehashOnCollision = (getHashTableSize() < (size() + (size() >> 1)));
+            putHashEntry(key, nextEntryIndex, rehashOnCollision);
+        } else if (totalEntries > getHashThreshold()) {
+            createHash();
+        }
+
+        return null;
+    }
+
+    /**
+     * Number of entries above which a hash table should be constructed.
+     */
+    private int getHashThreshold() {
+        if (strategy == null || strategy == Equivalence.IDENTITY_WITH_SYSTEM_HASHCODE) {
+            return HASH_THRESHOLD_IDENTITY_COMPARE;
+        } else {
+            return HASH_THRESHOLD;
+        }
+    }
+
+    private void grow() {
+        int entriesLength = entries.length;
+        int newSize = (entriesLength >> 1) + Math.max(MIN_CAPACITY_INCREASE, entriesLength >> 2);
+        if (newSize > MAX_ELEMENT_COUNT) {
+            throw new UnsupportedOperationException("map grown too large!");
+        }
+        Object[] newEntries = new Object[newSize << 1];
+        System.arraycopy(entries, 0, newEntries, 0, entriesLength);
+        entries = newEntries;
+        if ((entriesLength < LARGE_HASH_THRESHOLD && newEntries.length >= LARGE_HASH_THRESHOLD) ||
+                        (entriesLength < VERY_LARGE_HASH_THRESHOLD && newEntries.length > VERY_LARGE_HASH_THRESHOLD)) {
+            // Rehash in order to change number of bits reserved for hash indices.
+            createHash();
+        }
+    }
+
+    /**
+     * Compresses the graph if there is a large number of deleted entries and returns the translated
+     * new next index.
+     */
+    private int maybeCompress(int nextIndex) {
+        if (entries.length != INITIAL_CAPACITY << 1 && deletedEntries >= (totalEntries >> 1) + (totalEntries >> 2)) {
+            return compressLarge(nextIndex);
+        }
+        return nextIndex;
+    }
+
+    /**
+     * Compresses the graph and returns the translated new next index.
+     */
+    private int compressLarge(int nextIndex) {
+        int size = INITIAL_CAPACITY;
+        int remaining = totalEntries - deletedEntries;
+
+        while (size <= remaining) {
+            size += Math.max(MIN_CAPACITY_INCREASE, size >> 1);
+        }
+
+        Object[] newEntries = new Object[size << 1];
+        int z = 0;
+        int newNextIndex = remaining;
+        for (int i = 0; i < totalEntries; ++i) {
+            Object key = getKey(i);
+            if (i == nextIndex) {
+                newNextIndex = z;
+            }
+            if (key != null) {
+                newEntries[z << 1] = key;
+                newEntries[(z << 1) + 1] = getValue(i);
+                z++;
+            }
+        }
+
+        this.entries = newEntries;
+        totalEntries = z;
+        deletedEntries = 0;
+        if (z <= getHashThreshold()) {
+            this.hashArray = null;
+        } else {
+            createHash();
+        }
+        return newNextIndex;
+    }
+
+    private int getHashTableSize() {
+        if (entries.length < LARGE_HASH_THRESHOLD) {
+            return hashArray.length;
+        } else if (entries.length < VERY_LARGE_HASH_THRESHOLD) {
+            return hashArray.length >> 1;
+        } else {
+            return hashArray.length >> 2;
+        }
+    }
+
+    private void createHash() {
+        int entryCount = size();
+
+        // Calculate smallest 2^n that is greater number of entries.
+        int size = getHashThreshold();
+        while (size <= entryCount) {
+            size <<= 1;
+        }
+
+        // Give extra size to avoid collisions.
+        size <<= 1;
+
+        if (this.entries.length >= VERY_LARGE_HASH_THRESHOLD) {
+            // Every entry has 4 bytes.
+            size <<= 2;
+        } else if (this.entries.length >= LARGE_HASH_THRESHOLD) {
+            // Every entry has 2 bytes.
+            size <<= 1;
+        } else {
+            // Entries are very small => give extra size to further reduce collisions.
+            size <<= 1;
+        }
+
+        hashArray = new byte[size];
+        for (int i = 0; i < totalEntries; i++) {
+            Object entryKey = getKey(i);
+            if (entryKey != null) {
+                putHashEntry(entryKey, i, false);
+            }
+        }
+    }
+
+    private void putHashEntry(Object key, int entryIndex, boolean rehashOnCollision) {
+        int hashIndex = getHashIndex(key);
+        int oldIndex = getHashArray(hashIndex) - 1;
+        if (oldIndex != -1 && rehashOnCollision) {
+            this.createHash();
+            return;
+        }
+        setHashArray(hashIndex, entryIndex + 1);
+        Object value = getRawValue(entryIndex);
+        if (oldIndex != -1) {
+            assert entryIndex != oldIndex : "this cannot happend and would create an endless collision link cycle";
+            if (value instanceof CollisionLink) {
+                CollisionLink collisionLink = (CollisionLink) value;
+                setRawValue(entryIndex, new CollisionLink(collisionLink.value, oldIndex));
+            } else {
+                setRawValue(entryIndex, new CollisionLink(getRawValue(entryIndex), oldIndex));
+            }
+        } else {
+            if (value instanceof CollisionLink) {
+                CollisionLink collisionLink = (CollisionLink) value;
+                setRawValue(entryIndex, collisionLink.value);
+            }
+        }
+    }
+
+    @Override
+    public int size() {
+        return totalEntries - deletedEntries;
+    }
+
+    @Override
+    public boolean containsKey(K key) {
+        return find(key) != -1;
+    }
+
+    @Override
+    public void clear() {
+        entries = null;
+        hashArray = null;
+        totalEntries = deletedEntries = 0;
+    }
+
+    private boolean hasHashArray() {
+        return hashArray != null;
+    }
+
+    @SuppressWarnings("unchecked")
+    @Override
+    public V removeKey(K key) {
+        if (key == null) {
+            throw new UnsupportedOperationException("null not supported as key!");
+        }
+        int index;
+        if (hasHashArray()) {
+            index = this.findAndRemoveHash(key);
+        } else {
+            index = this.findLinear(key);
+        }
+
+        if (index != -1) {
+            Object value = getValue(index);
+            remove(index);
+            return (V) value;
+        }
+        return null;
+    }
+
+    /**
+     * Removes the element at the specific index and returns the index of the next element. This can
+     * be a different value if graph compression was triggered.
+     */
+    private int remove(int indexToRemove) {
+        int index = indexToRemove;
+        int entriesAfterIndex = totalEntries - index - 1;
+        int result = index + 1;
+
+        // Without hash array, compress immediately.
+        if (entriesAfterIndex <= COMPRESS_IMMEDIATE_CAPACITY && !hasHashArray()) {
+            while (index < totalEntries - 1) {
+                setKey(index, getKey(index + 1));
+                setRawValue(index, getRawValue(index + 1));
+                index++;
+            }
+            result--;
+        }
+
+        setKey(index, null);
+        setRawValue(index, null);
+        if (index == totalEntries - 1) {
+            // Make sure last element is always non-null.
+            totalEntries--;
+            while (index > 0 && getKey(index - 1) == null) {
+                totalEntries--;
+                deletedEntries--;
+                index--;
+            }
+        } else {
+            deletedEntries++;
+            result = maybeCompress(result);
+        }
+
+        return result;
+    }
+
+    private abstract class SparseMapIterator<E> implements Iterator<E> {
+
+        protected int current;
+
+        @Override
+        public boolean hasNext() {
+            return current < totalEntries;
+        }
+
+        @Override
+        public void remove() {
+            if (hasHashArray()) {
+                EconomicMapImpl.this.findAndRemoveHash(getKey(current - 1));
+            }
+            current = EconomicMapImpl.this.remove(current - 1);
+        }
+    }
+
+    @Override
+    public Iterable<V> getValues() {
+        return new Iterable<V>() {
+            @Override
+            public Iterator<V> iterator() {
+                return new SparseMapIterator<V>() {
+                    @SuppressWarnings("unchecked")
+                    @Override
+                    public V next() {
+                        Object result;
+                        while (true) {
+                            result = getValue(current);
+                            if (result == null && getKey(current) == null) {
+                                // values can be null, double-check if key is also null
+                                current++;
+                            } else {
+                                current++;
+                                break;
+                            }
+                        }
+                        return (V) result;
+                    }
+                };
+            }
+        };
+    }
+
+    @Override
+    public Iterable<K> getKeys() {
+        return this;
+    }
+
+    @Override
+    public boolean isEmpty() {
+        return this.size() == 0;
+    }
+
+    @Override
+    public MapCursor<K, V> getEntries() {
+        return new MapCursor<K, V>() {
+            int current = -1;
+
+            @Override
+            public boolean advance() {
+                current++;
+                if (current >= totalEntries) {
+                    return false;
+                } else {
+                    while (EconomicMapImpl.this.getKey(current) == null) {
+                        // Skip over null entries
+                        current++;
+                    }
+                    return true;
+                }
+            }
+
+            @SuppressWarnings("unchecked")
+            @Override
+            public K getKey() {
+                return (K) EconomicMapImpl.this.getKey(current);
+            }
+
+            @SuppressWarnings("unchecked")
+            @Override
+            public V getValue() {
+                return (V) EconomicMapImpl.this.getValue(current);
+            }
+
+            @Override
+            public void remove() {
+                if (hasHashArray()) {
+                    EconomicMapImpl.this.findAndRemoveHash(EconomicMapImpl.this.getKey(current));
+                }
+                current = EconomicMapImpl.this.remove(current) - 1;
+            }
+        };
+    }
+
+    @SuppressWarnings("unchecked")
+    @Override
+    public void replaceAll(BiFunction<? super K, ? super V, ? extends V> function) {
+        for (int i = 0; i < totalEntries; i++) {
+            Object entryKey = getKey(i);
+            if (entryKey != null) {
+                Object newValue = function.apply((K) entryKey, (V) getValue(i));
+                setValue(i, newValue);
+            }
+        }
+    }
+
+    private Object getKey(int index) {
+        return entries[index << 1];
+    }
+
+    private void setKey(int index, Object newValue) {
+        entries[index << 1] = newValue;
+    }
+
+    private void setValue(int index, Object newValue) {
+        Object oldValue = getRawValue(index);
+        if (oldValue instanceof CollisionLink) {
+            CollisionLink collisionLink = (CollisionLink) oldValue;
+            setRawValue(index, new CollisionLink(newValue, collisionLink.next));
+        } else {
+            setRawValue(index, newValue);
+        }
+    }
+
+    private void setRawValue(int index, Object newValue) {
+        entries[(index << 1) + 1] = newValue;
+    }
+
+    private Object getRawValue(int index) {
+        return entries[(index << 1) + 1];
+    }
+
+    private Object getValue(int index) {
+        Object object = getRawValue(index);
+        if (object instanceof CollisionLink) {
+            return ((CollisionLink) object).value;
+        }
+        return object;
+    }
+
+    private final boolean isSet;
+
+    @Override
+    public String toString() {
+        StringBuilder builder = new StringBuilder();
+        builder.append(isSet ? "set(size=" : "map(size=").append(size()).append(", {");
+        String sep = "";
+        MapCursor<K, V> cursor = getEntries();
+        while (cursor.advance()) {
+            builder.append(sep);
+            if (isSet) {
+                builder.append(cursor.getKey());
+            } else {
+                builder.append("(").append(cursor.getKey()).append(",").append(cursor.getValue()).append(")");
+            }
+            sep = ",";
+        }
+        builder.append("})");
+        return builder.toString();
+    }
+
+    @Override
+    public Iterator<K> iterator() {
+        return new SparseMapIterator<K>() {
+            @SuppressWarnings("unchecked")
+            @Override
+            public K next() {
+                Object result;
+                while ((result = getKey(current++)) == null) {
+                    // skip null entries
+                }
+                return (K) result;
+            }
+        };
+    }
+
+    @Override
+    public boolean contains(K element) {
+        return containsKey(element);
+    }
+
+    @SuppressWarnings("unchecked")
+    @Override
+    public boolean add(K element) {
+        return put(element, (V) element) == null;
+    }
+
+    @Override
+    public void remove(K element) {
+        removeKey(element);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.collections/src/org/graalvm/collections/EconomicSet.java	Fri Feb 16 13:49:07 2018 -0800
@@ -0,0 +1,193 @@
+/*
+ * Copyright (c) 2017, 2017, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.collections;
+
+import java.util.Iterator;
+
+/**
+ * Memory efficient set data structure.
+ *
+ * @since 1.0
+ */
+public interface EconomicSet<E> extends UnmodifiableEconomicSet<E> {
+
+    /**
+     * Adds {@code element} to this set if it is not already present.
+     *
+     * @return {@code true} if this set did not already contain {@code element}.
+     * @since 1.0
+     */
+    boolean add(E element);
+
+    /**
+     * Removes {@code element} from this set if it is present. This set will not contain
+     * {@code element} once the call returns.
+     *
+     * @since 1.0
+     */
+    void remove(E element);
+
+    /**
+     * Removes all of the elements from this set. The set will be empty after this call returns.
+     *
+     * @since 1.0
+     */
+    void clear();
+
+    /**
+     * Adds all of the elements in {@code other} to this set if they're not already present.
+     *
+     * @since 1.0
+     */
+    default void addAll(EconomicSet<E> other) {
+        addAll(other.iterator());
+    }
+
+    /**
+     * Adds all of the elements in {@code values} to this set if they're not already present.
+     *
+     * @since 1.0
+     */
+    default void addAll(Iterable<E> values) {
+        addAll(values.iterator());
+    }
+
+    /**
+     * Adds all of the elements enumerated by {@code iterator} to this set if they're not already
+     * present.
+     *
+     * @since 1.0
+     */
+    default void addAll(Iterator<E> iterator) {
+        while (iterator.hasNext()) {
+            add(iterator.next());
+        }
+    }
+
+    /**
+     * Removes from this set all of its elements that are contained in {@code other}.
+     *
+     * @since 1.0
+     */
+    default void removeAll(EconomicSet<E> other) {
+        removeAll(other.iterator());
+    }
+
+    /**
+     * Removes from this set all of its elements that are contained in {@code values}.
+     *
+     * @since 1.0
+     */
+    default void removeAll(Iterable<E> values) {
+        removeAll(values.iterator());
+    }
+
+    /**
+     * Removes from this set all of its elements that are enumerated by {@code iterator}.
+     *
+     * @since 1.0
+     */
+    default void removeAll(Iterator<E> iterator) {
+        while (iterator.hasNext()) {
+            remove(iterator.next());
+        }
+    }
+
+    /**
+     * Removes from this set all of its elements that are not contained in {@code other}.
+     *
+     * @since 1.0
+     */
+    default void retainAll(EconomicSet<E> other) {
+        Iterator<E> iterator = iterator();
+        while (iterator.hasNext()) {
+            E key = iterator.next();
+            if (!other.contains(key)) {
+                iterator.remove();
+            }
+        }
+    }
+
+    /**
+     * Creates a new set guaranteeing insertion order when iterating over its elements with the
+     * default {@link Equivalence#DEFAULT} comparison strategy.
+     *
+     * @since 1.0
+     */
+    static <E> EconomicSet<E> create() {
+        return EconomicSet.create(Equivalence.DEFAULT);
+    }
+
+    /**
+     * Creates a new set guaranteeing insertion order when iterating over its elements.
+     *
+     * @since 1.0
+     */
+    static <E> EconomicSet<E> create(Equivalence strategy) {
+        return EconomicMapImpl.create(strategy, true);
+    }
+
+    /**
+     * Creates a new set guaranteeing insertion order when iterating over its elements with the
+     * default {@link Equivalence#DEFAULT} comparison strategy and inserts all elements of the
+     * specified collection.
+     *
+     * @since 1.0
+     */
+    static <E> EconomicSet<E> create(int initialCapacity) {
+        return EconomicSet.create(Equivalence.DEFAULT, initialCapacity);
+    }
+
+    /**
+     * Creates a new set guaranteeing insertion order when iterating over its elements with the
+     * default {@link Equivalence#DEFAULT} comparison strategy and inserts all elements of the
+     * specified collection.
+     *
+     * @since 1.0
+     */
+    static <E> EconomicSet<E> create(UnmodifiableEconomicSet<E> c) {
+        return EconomicSet.create(Equivalence.DEFAULT, c);
+    }
+
+    /**
+     * Creates a new set guaranteeing insertion order when iterating over its elements and
+     * initializes with the given capacity.
+     *
+     * @since 1.0
+     */
+    static <E> EconomicSet<E> create(Equivalence strategy, int initialCapacity) {
+        return EconomicMapImpl.create(strategy, initialCapacity, true);
+    }
+
+    /**
+     * Creates a new set guaranteeing insertion order when iterating over its elements and inserts
+     * all elements of the specified collection.
+     *
+     * @since 1.0
+     */
+    static <E> EconomicSet<E> create(Equivalence strategy, UnmodifiableEconomicSet<E> c) {
+        return EconomicMapImpl.create(strategy, c, true);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.collections/src/org/graalvm/collections/Equivalence.java	Fri Feb 16 13:49:07 2018 -0800
@@ -0,0 +1,116 @@
+/*
+ * Copyright (c) 2017, 2017, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.collections;
+
+/**
+ * Strategy for comparing two objects. Default predefined strategies are {@link #DEFAULT},
+ * {@link #IDENTITY}, and {@link #IDENTITY_WITH_SYSTEM_HASHCODE}.
+ *
+ * @since 1.0
+ */
+public abstract class Equivalence {
+
+    /**
+     * Default equivalence calling {@link #equals(Object)} to check equality and {@link #hashCode()}
+     * for obtaining hash values. Do not change the logic of this class as it may be inlined in
+     * other places.
+     *
+     * @since 1.0
+     */
+    public static final Equivalence DEFAULT = new Equivalence() {
+
+        @Override
+        public boolean equals(Object a, Object b) {
+            return a.equals(b);
+        }
+
+        @Override
+        public int hashCode(Object o) {
+            return o.hashCode();
+        }
+    };
+
+    /**
+     * Identity equivalence using {@code ==} to check equality and {@link #hashCode()} for obtaining
+     * hash values. Do not change the logic of this class as it may be inlined in other places.
+     *
+     * @since 1.0
+     */
+    public static final Equivalence IDENTITY = new Equivalence() {
+
+        @Override
+        public boolean equals(Object a, Object b) {
+            return a == b;
+        }
+
+        @Override
+        public int hashCode(Object o) {
+            return o.hashCode();
+        }
+    };
+
+    /**
+     * Identity equivalence using {@code ==} to check equality and
+     * {@link System#identityHashCode(Object)} for obtaining hash values. Do not change the logic of
+     * this class as it may be inlined in other places.
+     *
+     * @since 1.0
+     */
+    public static final Equivalence IDENTITY_WITH_SYSTEM_HASHCODE = new Equivalence() {
+
+        @Override
+        public boolean equals(Object a, Object b) {
+            return a == b;
+        }
+
+        @Override
+        public int hashCode(Object o) {
+            return System.identityHashCode(o);
+        }
+    };
+
+    /**
+     * Subclass for creating custom equivalence definitions.
+     *
+     * @since 1.0
+     */
+    protected Equivalence() {
+    }
+
+    /**
+     * Returns {@code true} if the non-{@code null} arguments are equal to each other and
+     * {@code false} otherwise.
+     *
+     * @since 1.0
+     */
+    public abstract boolean equals(Object a, Object b);
+
+    /**
+     * Returns the hash code of a non-{@code null} argument {@code o}.
+     *
+     * @since 1.0
+     */
+    public abstract int hashCode(Object o);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.collections/src/org/graalvm/collections/MapCursor.java	Fri Feb 16 13:49:07 2018 -0800
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2017, 2017, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.collections;
+
+/**
+ * Cursor to iterate over a mutable map.
+ *
+ * @since 1.0
+ */
+public interface MapCursor<K, V> extends UnmodifiableMapCursor<K, V> {
+    /**
+     * Remove the current entry from the map. May only be called once. After calling
+     * {@link #remove()}, it is no longer valid to call {@link #getKey()} or {@link #getValue()} on
+     * the current entry.
+     *
+     * @since 1.0
+     */
+    void remove();
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.collections/src/org/graalvm/collections/Pair.java	Fri Feb 16 13:49:07 2018 -0800
@@ -0,0 +1,158 @@
+/*
+ * Copyright (c) 2017, 2017, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.collections;
+
+import java.util.Objects;
+
+/**
+ * Utility class representing a pair of values.
+ *
+ * @since 1.0
+ */
+public final class Pair<L, R> {
+
+    private static final Pair<Object, Object> EMPTY = new Pair<>(null, null);
+
+    private final L left;
+    private final R right;
+
+    /**
+     * Returns an empty pair.
+     *
+     * @since 1.0
+     */
+    @SuppressWarnings("unchecked")
+    public static <L, R> Pair<L, R> empty() {
+        return (Pair<L, R>) EMPTY;
+    }
+
+    /**
+     * Constructs a pair with its left value being {@code left}, or returns an empty pair if
+     * {@code left} is null.
+     *
+     * @return the constructed pair or an empty pair if {@code left} is null.
+     * @since 1.0
+     */
+    public static <L, R> Pair<L, R> createLeft(L left) {
+        if (left == null) {
+            return empty();
+        } else {
+            return new Pair<>(left, null);
+        }
+    }
+
+    /**
+     * Constructs a pair with its right value being {@code right}, or returns an empty pair if
+     * {@code right} is null.
+     *
+     * @return the constructed pair or an empty pair if {@code right} is null.
+     * @since 1.0
+     */
+    public static <L, R> Pair<L, R> createRight(R right) {
+        if (right == null) {
+            return empty();
+        } else {
+            return new Pair<>(null, right);
+        }
+    }
+
+    /**
+     * Constructs a pair with its left value being {@code left}, and its right value being
+     * {@code right}, or returns an empty pair if both inputs are null.
+     *
+     * @return the constructed pair or an empty pair if both inputs are null.
+     * @since 1.0
+     */
+    public static <L, R> Pair<L, R> create(L left, R right) {
+        if (right == null && left == null) {
+            return empty();
+        } else {
+            return new Pair<>(left, right);
+        }
+    }
+
+    private Pair(L left, R right) {
+        this.left = left;
+        this.right = right;
+    }
+
+    /**
+     * Returns the left value of this pair.
+     *
+     * @since 1.0
+     */
+    public L getLeft() {
+        return left;
+    }
+
+    /**
+     * Returns the right value of this pair.
+     *
+     * @since 1.0
+     */
+    public R getRight() {
+        return right;
+    }
+
+    /**
+     * {@inheritDoc}
+     *
+     * @since 1.0
+     */
+    @Override
+    public int hashCode() {
+        return Objects.hashCode(left) + 31 * Objects.hashCode(right);
+    }
+
+    /**
+     * {@inheritDoc}
+     *
+     * @since 1.0
+     */
+    @SuppressWarnings("unchecked")
+    @Override
+    public boolean equals(Object obj) {
+        if (obj == this) {
+            return true;
+        }
+
+        if (obj instanceof Pair) {
+            Pair<L, R> pair = (Pair<L, R>) obj;
+            return Objects.equals(left, pair.left) && Objects.equals(right, pair.right);
+        }
+
+        return false;
+    }
+
+    /**
+     * {@inheritDoc}
+     *
+     * @since 1.0
+     */
+    @Override
+    public String toString() {
+        return String.format("(%s, %s)", left, right);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.collections/src/org/graalvm/collections/UnmodifiableEconomicMap.java	Fri Feb 16 13:49:07 2018 -0800
@@ -0,0 +1,97 @@
+/*
+ * Copyright (c) 2017, 2017, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.collections;
+
+/**
+ * Unmodifiable memory efficient map data structure.
+ *
+ * @since 1.0
+ */
+public interface UnmodifiableEconomicMap<K, V> {
+
+    /**
+     * Returns the value to which {@code key} is mapped, or {@code null} if this map contains no
+     * mapping for {@code key}.
+     *
+     * @since 1.0
+     */
+    V get(K key);
+
+    /**
+     * Returns the value to which {@code key} is mapped, or {@code defaultValue} if this map
+     * contains no mapping for {@code key}.
+     *
+     * @since 1.0
+     */
+    default V get(K key, V defaultValue) {
+        V v = get(key);
+        if (v == null) {
+            return defaultValue;
+        }
+        return v;
+    }
+
+    /**
+     * Returns {@code true} if this map contains a mapping for {@code key}.
+     *
+     * @since 1.0
+     */
+    boolean containsKey(K key);
+
+    /**
+     * Returns the number of key-value mappings in this map.
+     *
+     * @since 1.0
+     */
+    int size();
+
+    /**
+     * Returns {@code true} if this map contains no key-value mappings.
+     *
+     * @since 1.0
+     */
+    boolean isEmpty();
+
+    /**
+     * Returns a {@link Iterable} view of the values contained in this map.
+     *
+     * @since 1.0
+     */
+    Iterable<V> getValues();
+
+    /**
+     * Returns a {@link Iterable} view of the keys contained in this map.
+     *
+     * @since 1.0
+     */
+    Iterable<K> getKeys();
+
+    /**
+     * Returns a {@link UnmodifiableMapCursor} view of the mappings contained in this map.
+     *
+     * @since 1.0
+     */
+    UnmodifiableMapCursor<K, V> getEntries();
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.collections/src/org/graalvm/collections/UnmodifiableEconomicSet.java	Fri Feb 16 13:49:07 2018 -0800
@@ -0,0 +1,77 @@
+/*
+ * Copyright (c) 2017, 2017, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.collections;
+
+/**
+ * Unmodifiable memory efficient set data structure.
+ *
+ * @since 1.0
+ */
+public interface UnmodifiableEconomicSet<E> extends Iterable<E> {
+
+    /**
+     * Returns {@code true} if this set contains a mapping for the {@code element}.
+     *
+     * @since 1.0
+     */
+    boolean contains(E element);
+
+    /**
+     * Returns the number of elements in this set.
+     *
+     * @since 1.0
+     */
+    int size();
+
+    /**
+     * Returns {@code true} if this set contains no elements.
+     *
+     * @since 1.0
+     */
+    boolean isEmpty();
+
+    /**
+     * Stores all of the elements in this set into {@code target}. An
+     * {@link UnsupportedOperationException} will be thrown if the length of {@code target} does not
+     * match the size of this set.
+     *
+     * @return an array containing all the elements in this set.
+     * @throws UnsupportedOperationException if the length of {@code target} does not equal the size
+     *             of this set.
+     * @since 1.0
+     */
+    default E[] toArray(E[] target) {
+        if (target.length != size()) {
+            throw new UnsupportedOperationException("Length of target array must equal the size of the set.");
+        }
+
+        int index = 0;
+        for (E element : this) {
+            target[index++] = element;
+        }
+
+        return target;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.collections/src/org/graalvm/collections/UnmodifiableMapCursor.java	Fri Feb 16 13:49:07 2018 -0800
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 2017, 2017, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.collections;
+
+/**
+ * Cursor to iterate over a map without changing its contents.
+ *
+ * @since 1.0
+ */
+public interface UnmodifiableMapCursor<K, V> {
+    /**
+     * Advances to the next entry.
+     *
+     * @return {@code true} if a next entry exists, {@code false} if there is no next entry.
+     * @since 1.0
+     */
+    boolean advance();
+
+    /**
+     * The key of the current entry.
+     *
+     * @since 1.0
+     */
+    K getKey();
+
+    /**
+     * The value of the current entry.
+     *
+     * @since 1.0
+     */
+    V getValue();
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.collections/src/org/graalvm/collections/package-info.java	Fri Feb 16 13:49:07 2018 -0800
@@ -0,0 +1,33 @@
+/*
+ * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  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.
+ */
+/**
+ * The Graal-SDK collections package contains memory efficient data structures.
+ *
+ * @see org.graalvm.collections.EconomicMap
+ * @see org.graalvm.collections.EconomicSet
+ *
+ * @since 1.0
+ */
+package org.graalvm.collections;
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.api.directives.test/src/org/graalvm/compiler/api/directives/test/ProbabilityDirectiveTest.java	Fri Feb 16 12:24:38 2018 -0800
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.api.directives.test/src/org/graalvm/compiler/api/directives/test/ProbabilityDirectiveTest.java	Fri Feb 16 13:49:07 2018 -0800
@@ -50,6 +50,21 @@
         test("branchProbabilitySnippet", 5);
     }
 
+    public static int branchProbabilitySnippet2(int arg) {
+        if (!GraalDirectives.injectBranchProbability(0.125, arg <= 0)) {
+            GraalDirectives.controlFlowAnchor(); // prevent removal of the if
+            return 2;
+        } else {
+            GraalDirectives.controlFlowAnchor(); // prevent removal of the if
+            return 1;
+        }
+    }
+
+    @Test
+    public void testBranchProbability2() {
+        test("branchProbabilitySnippet2", 5);
+    }
+
     @Override
     protected boolean checkLowTierGraph(StructuredGraph graph) {
         NodeIterable<IfNode> ifNodes = graph.getNodes(IfNode.TYPE);
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.api.directives/src/org/graalvm/compiler/api/directives/GraalDirectives.java	Fri Feb 16 12:24:38 2018 -0800
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.api.directives/src/org/graalvm/compiler/api/directives/GraalDirectives.java	Fri Feb 16 13:49:07 2018 -0800
@@ -50,6 +50,13 @@
     }
 
     /**
+     * Directive for the compiler to fall back to the bytecode interpreter at this point, invalidate
+     * the compiled code, record a speculation and reprofile the method.
+     */
+    public static void deoptimizeAndInvalidateWithSpeculation() {
+    }
+
+    /**
      * Returns a boolean value indicating whether the method is executed in Graal-compiled code.
      */
     public static boolean inCompiledCode() {
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.api.replacements/src/org/graalvm/compiler/api/replacements/MethodSubstitution.java	Fri Feb 16 12:24:38 2018 -0800
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.api.replacements/src/org/graalvm/compiler/api/replacements/MethodSubstitution.java	Fri Feb 16 13:49:07 2018 -0800
@@ -26,15 +26,52 @@
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 import java.lang.annotation.Target;
+import java.lang.reflect.Array;
 
 import jdk.vm.ci.meta.Signature;
 
 /**
  * Denotes a method whose body is used by a compiler as the substitute (or intrinsification) of
- * another method. The exact method used to do the substitution is compiler dependent but every
+ * another method. The exact mechanism used to do the substitution is compiler dependent but every
  * compiler should require substitute methods to be annotated with {@link MethodSubstitution}. In
  * addition, a compiler is recommended to implement {@link MethodSubstitutionRegistry} to advertise
  * the mechanism by which it supports registration of method substitutes.
+ *
+ * A compiler may support partial intrinsification where only a part of a method is implemented by
+ * the compiler. The unsupported path is expressed by a call to either the original or substitute
+ * method from within the substitute method. Such as call is a <i>partial intrinsic exit</i>.
+ *
+ * For example, here's a HotSpot specific intrinsic for {@link Array#newInstance(Class, int)} that
+ * only handles the case where the VM representation of the array class to be instantiated already
+ * exists:
+ *
+ * <pre>
+ * &#64;MethodSubstitution
+ * public static Object newInstance(Class<?> componentType, int length) {
+ *     if (componentType == null || loadKlassFromObject(componentType, arrayKlassOffset(INJECTED_VMCONFIG), CLASS_ARRAY_KLASS_LOCATION).isNull()) {
+ *         // Array class not yet created - exit the intrinsic and call the original method
+ *         return newInstance(componentType, length);
+ *     }
+ *     return DynamicNewArrayNode.newArray(GraalDirectives.guardingNonNull(componentType), length, JavaKind.Object);
+ * }
+ * </pre>
+ *
+ * Here's the same intrinsification where the exit is expressed as a call to the original method:
+ *
+ * <pre>
+ * &#64;MethodSubstitution
+ * public static Object newInstance(Class<?> componentType, int length) {
+ *     if (componentType == null || loadKlassFromObject(componentType, arrayKlassOffset(INJECTED_VMCONFIG), CLASS_ARRAY_KLASS_LOCATION).isNull()) {
+ *         // Array class not yet created - exit the intrinsic and call the original method
+ *         return java.lang.reflect.newInstance(componentType, length);
+ *     }
+ *     return DynamicNewArrayNode.newArray(GraalDirectives.guardingNonNull(componentType), length, JavaKind.Object);
+ * }
+ * </pre>
+ *
+ * A condition for a partial intrinsic exit is that it is uses the unmodified parameters of the
+ * substitute as arguments to the partial intrinsic exit call. There must also be no side effecting
+ * instruction between the start of the substitute method and the partial intrinsic exit.
  */
 @Retention(RetentionPolicy.RUNTIME)
 @Target(ElementType.METHOD)
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.api.replacements/src/org/graalvm/compiler/api/replacements/SnippetReflectionProvider.java	Fri Feb 16 12:24:38 2018 -0800
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.api.replacements/src/org/graalvm/compiler/api/replacements/SnippetReflectionProvider.java	Fri Feb 16 13:49:07 2018 -0800
@@ -90,4 +90,12 @@
      *         if this provider cannot provide a value of the requested type
      */
     <T> T getInjectedNodeIntrinsicParameter(Class<T> type);
+
+    /**
+     * Get the original Java class corresponding to a {@link ResolvedJavaType}.
+     *
+     * @param type the type for which the original Java class is requested
+     * @return the original Java class corresponding to the {@code type} parameter
+     */
+    Class<?> originalClass(ResolvedJavaType type);
 }
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.api.runtime/src/org/graalvm/compiler/api/runtime/GraalRuntime.java	Fri Feb 16 12:24:38 2018 -0800
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.api.runtime/src/org/graalvm/compiler/api/runtime/GraalRuntime.java	Fri Feb 16 13:49:07 2018 -0800
@@ -22,9 +22,19 @@
  */
 package org.graalvm.compiler.api.runtime;
 
+import jdk.vm.ci.common.JVMCIError;
+
 public interface GraalRuntime {
 
     String getName();
 
     <T> T getCapability(Class<T> clazz);
+
+    default <T> T getRequiredCapability(Class<T> clazz) {
+        T ret = getCapability(clazz);
+        if (ret == null) {
+            throw new JVMCIError("The VM does not expose the required Graal capability %s.", clazz.getName());
+        }
+        return ret;
+    }
 }
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.asm.amd64/src/org/graalvm/compiler/asm/amd64/AMD64Assembler.java	Fri Feb 16 12:24:38 2018 -0800
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.asm.amd64/src/org/graalvm/compiler/asm/amd64/AMD64Assembler.java	Fri Feb 16 13:49:07 2018 -0800
@@ -208,7 +208,6 @@
     }
 
     private static class VexOpcode {
-        private static final int VEX_OPCODE_NONE = 0x0;
         private static final int VEX_OPCODE_0F = 0x1;
         private static final int VEX_OPCODE_0F_38 = 0x2;
         private static final int VEX_OPCODE_0F_3A = 0x3;
@@ -861,9 +860,26 @@
                     break;
             }
 
+            int opc = 0;
+            if (isSimd) {
+                switch (prefix2) {
+                    case P_0F:
+                        opc = VexOpcode.VEX_OPCODE_0F;
+                        break;
+                    case P_0F38:
+                        opc = VexOpcode.VEX_OPCODE_0F_38;
+                        break;
+                    case P_0F3A:
+                        opc = VexOpcode.VEX_OPCODE_0F_3A;
+                        break;
+                    default:
+                        isSimd = false;
+                        break;
+                }
+            }
+
             if (isSimd) {
                 int pre;
-                int opc;
                 boolean rexVexW = (size == QWORD) ? true : false;
                 AMD64InstructionAttr attributes = new AMD64InstructionAttr(AvxVectorLen.AVX_128bit, rexVexW, /* legacyMode */ false, /* noMaskReg */ false, /* usesVl */ false, asm.target);
                 int curPrefix = size.sizePrefix | prefix1;
@@ -881,20 +897,6 @@
                         pre = VexSimdPrefix.VEX_SIMD_NONE;
                         break;
                 }
-                switch (prefix2) {
-                    case P_0F:
-                        opc = VexOpcode.VEX_OPCODE_0F;
-                        break;
-                    case P_0F38:
-                        opc = VexOpcode.VEX_OPCODE_0F_38;
-                        break;
-                    case P_0F3A:
-                        opc = VexOpcode.VEX_OPCODE_0F_3A;
-                        break;
-                    default:
-                        opc = VexOpcode.VEX_OPCODE_NONE;
-                        break;
-                }
                 int encode;
                 if (noNds) {
                     encode = asm.simdPrefixAndEncode(dst, Register.None, src, pre, opc, attributes);
@@ -938,9 +940,26 @@
                     break;
             }
 
+            int opc = 0;
+            if (isSimd) {
+                switch (prefix2) {
+                    case P_0F:
+                        opc = VexOpcode.VEX_OPCODE_0F;
+                        break;
+                    case P_0F38:
+                        opc = VexOpcode.VEX_OPCODE_0F_38;
+                        break;
+                    case P_0F3A:
+                        opc = VexOpcode.VEX_OPCODE_0F_3A;
+                        break;
+                    default:
+                        isSimd = false;
+                        break;
+                }
+            }
+
             if (isSimd) {
                 int pre;
-                int opc;
                 boolean rexVexW = (size == QWORD) ? true : false;
                 AMD64InstructionAttr attributes = new AMD64InstructionAttr(AvxVectorLen.AVX_128bit, rexVexW, /* legacyMode */ false, /* noMaskReg */ false, /* usesVl */ false, asm.target);
                 int curPrefix = size.sizePrefix | prefix1;
@@ -958,20 +977,6 @@
                         pre = VexSimdPrefix.VEX_SIMD_NONE;
                         break;
                 }
-                switch (prefix2) {
-                    case P_0F:
-                        opc = VexOpcode.VEX_OPCODE_0F;
-                        break;
-                    case P_0F38:
-                        opc = VexOpcode.VEX_OPCODE_0F_38;
-                        break;
-                    case P_0F3A:
-                        opc = VexOpcode.VEX_OPCODE_0F_3A;
-                        break;
-                    default:
-                        opc = VexOpcode.VEX_OPCODE_NONE;
-                        break;
-                }
                 if (noNds) {
                     asm.simdPrefix(dst, Register.None, src, pre, opc, attributes);
                 } else {
@@ -1055,8 +1060,7 @@
                     opc = VexOpcode.VEX_OPCODE_0F_3A;
                     break;
                 default:
-                    opc = VexOpcode.VEX_OPCODE_NONE;
-                    break;
+                    throw GraalError.shouldNotReachHere("invalid VEX instruction prefix");
             }
             int encode;
             encode = asm.simdPrefixAndEncode(dst, nds, src, pre, opc, attributes);
@@ -1096,8 +1100,7 @@
                     opc = VexOpcode.VEX_OPCODE_0F_3A;
                     break;
                 default:
-                    opc = VexOpcode.VEX_OPCODE_NONE;
-                    break;
+                    throw GraalError.shouldNotReachHere("invalid VEX instruction prefix");
             }
             asm.simdPrefix(dst, nds, src, pre, opc, attributes);
             asm.emitByte(op);
@@ -1163,9 +1166,26 @@
                     break;
             }
 
+            int opc = 0;
+            if (isSimd) {
+                switch (prefix2) {
+                    case P_0F:
+                        opc = VexOpcode.VEX_OPCODE_0F;
+                        break;
+                    case P_0F38:
+                        opc = VexOpcode.VEX_OPCODE_0F_38;
+                        break;
+                    case P_0F3A:
+                        opc = VexOpcode.VEX_OPCODE_0F_3A;
+                        break;
+                    default:
+                        isSimd = false;
+                        break;
+                }
+            }
+
             if (isSimd) {
                 int pre;
-                int opc;
                 boolean rexVexW = (size == QWORD) ? true : false;
                 AMD64InstructionAttr attributes = new AMD64InstructionAttr(AvxVectorLen.AVX_128bit, rexVexW, /* legacyMode */ false, /* noMaskReg */ false, /* usesVl */ false, asm.target);
                 int curPrefix = size.sizePrefix | prefix1;
@@ -1183,20 +1203,6 @@
                         pre = VexSimdPrefix.VEX_SIMD_NONE;
                         break;
                 }
-                switch (prefix2) {
-                    case P_0F:
-                        opc = VexOpcode.VEX_OPCODE_0F;
-                        break;
-                    case P_0F38:
-                        opc = VexOpcode.VEX_OPCODE_0F_38;
-                        break;
-                    case P_0F3A:
-                        opc = VexOpcode.VEX_OPCODE_0F_3A;
-                        break;
-                    default:
-                        opc = VexOpcode.VEX_OPCODE_NONE;
-                        break;
-                }
                 int encode;
                 if (noNds) {
                     encode = asm.simdPrefixAndEncode(src, Register.None, dst, pre, opc, attributes);
@@ -1222,9 +1228,26 @@
                     break;
             }
 
+            int opc = 0;
+            if (isSimd) {
+                switch (prefix2) {
+                    case P_0F:
+                        opc = VexOpcode.VEX_OPCODE_0F;
+                        break;
+                    case P_0F38:
+                        opc = VexOpcode.VEX_OPCODE_0F_38;
+                        break;
+                    case P_0F3A:
+                        opc = VexOpcode.VEX_OPCODE_0F_3A;
+                        break;
+                    default:
+                        isSimd = false;
+                        break;
+                }
+            }
+
             if (isSimd) {
                 int pre;
-                int opc;
                 boolean rexVexW = (size == QWORD) ? true : false;
                 AMD64InstructionAttr attributes = new AMD64InstructionAttr(AvxVectorLen.AVX_128bit, rexVexW, /* legacyMode */ false, /* noMaskReg */ false, /* usesVl */ false, asm.target);
                 int curPrefix = size.sizePrefix | prefix1;
@@ -1242,20 +1265,6 @@
                         pre = VexSimdPrefix.VEX_SIMD_NONE;
                         break;
                 }
-                switch (prefix2) {
-                    case P_0F:
-                        opc = VexOpcode.VEX_OPCODE_0F;
-                        break;
-                    case P_0F38:
-                        opc = VexOpcode.VEX_OPCODE_0F_38;
-                        break;
-                    case P_0F3A:
-                        opc = VexOpcode.VEX_OPCODE_0F_3A;
-                        break;
-                    default:
-                        opc = VexOpcode.VEX_OPCODE_NONE;
-                        break;
-                }
                 asm.simdPrefix(src, Register.None, dst, pre, opc, attributes);
                 asm.emitByte(op);
                 asm.emitOperandHelper(src, dst, 0);
@@ -1390,9 +1399,26 @@
                     break;
             }
 
+            int opc = 0;
+            if (isSimd) {
+                switch (prefix2) {
+                    case P_0F:
+                        opc = VexOpcode.VEX_OPCODE_0F;
+                        break;
+                    case P_0F38:
+                        opc = VexOpcode.VEX_OPCODE_0F_38;
+                        break;
+                    case P_0F3A:
+                        opc = VexOpcode.VEX_OPCODE_0F_3A;
+                        break;
+                    default:
+                        isSimd = false;
+                        break;
+                }
+            }
+
             if (isSimd) {
                 int pre;
-                int opc;
                 AMD64InstructionAttr attributes = new AMD64InstructionAttr(AvxVectorLen.AVX_128bit, /* rexVexW */ false, /* legacyMode */ false, /* noMaskReg */ false, /* usesVl */ false, asm.target);
                 int curPrefix = size.sizePrefix | prefix1;
                 switch (curPrefix) {
@@ -1409,20 +1435,6 @@
                         pre = VexSimdPrefix.VEX_SIMD_NONE;
                         break;
                 }
-                switch (prefix2) {
-                    case P_0F:
-                        opc = VexOpcode.VEX_OPCODE_0F;
-                        break;
-                    case P_0F38:
-                        opc = VexOpcode.VEX_OPCODE_0F_38;
-                        break;
-                    case P_0F3A:
-                        opc = VexOpcode.VEX_OPCODE_0F_3A;
-                        break;
-                    default:
-                        opc = VexOpcode.VEX_OPCODE_NONE;
-                        break;
-                }
                 int encode;
                 if (noNds) {
                     encode = asm.simdPrefixAndEncode(dst, Register.None, src, pre, opc, attributes);
@@ -1453,9 +1465,26 @@
                     break;
             }
 
+            int opc = 0;
+            if (isSimd) {
+                switch (prefix2) {
+                    case P_0F:
+                        opc = VexOpcode.VEX_OPCODE_0F;
+                        break;
+                    case P_0F38:
+                        opc = VexOpcode.VEX_OPCODE_0F_38;
+                        break;
+                    case P_0F3A:
+                        opc = VexOpcode.VEX_OPCODE_0F_3A;
+                        break;
+                    default:
+                        isSimd = false;
+                        break;
+                }
+            }
+
             if (isSimd) {
                 int pre;
-                int opc;
                 AMD64InstructionAttr attributes = new AMD64InstructionAttr(AvxVectorLen.AVX_128bit, /* rexVexW */ false, /* legacyMode */ false, /* noMaskReg */ false, /* usesVl */ false, asm.target);
                 int curPrefix = size.sizePrefix | prefix1;
                 switch (curPrefix) {
@@ -1472,21 +1501,6 @@
                         pre = VexSimdPrefix.VEX_SIMD_NONE;
                         break;
                 }
-                switch (prefix2) {
-                    case P_0F:
-                        opc = VexOpcode.VEX_OPCODE_0F;
-                        break;
-                    case P_0F38:
-                        opc = VexOpcode.VEX_OPCODE_0F_38;
-                        break;
-                    case P_0F3A:
-                        opc = VexOpcode.VEX_OPCODE_0F_3A;
-                        break;
-                    default:
-                        opc = VexOpcode.VEX_OPCODE_NONE;
-                        break;
-                }
-
                 if (noNds) {
                     asm.simdPrefix(dst, Register.None, src, pre, opc, attributes);
                 } else {
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.code/src/org/graalvm/compiler/code/CompilationResult.java	Fri Feb 16 12:24:38 2018 -0800
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.code/src/org/graalvm/compiler/code/CompilationResult.java	Fri Feb 16 13:49:07 2018 -0800
@@ -33,9 +33,9 @@
 import java.util.List;
 import java.util.Objects;
 
+import org.graalvm.collections.EconomicSet;
 import org.graalvm.compiler.core.common.CompilationIdentifier;
 import org.graalvm.compiler.graph.NodeSourcePosition;
-import org.graalvm.util.EconomicSet;
 
 import jdk.vm.ci.code.DebugInfo;
 import jdk.vm.ci.code.StackSlot;
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.code/src/org/graalvm/compiler/code/DataSection.java	Fri Feb 16 12:24:38 2018 -0800
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.code/src/org/graalvm/compiler/code/DataSection.java	Fri Feb 16 13:49:07 2018 -0800
@@ -40,7 +40,7 @@
 
     public interface Patches {
 
-        void registerPatch(VMConstant c);
+        void registerPatch(int position, VMConstant c);
     }
 
     public abstract static class Data {
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.amd64/src/org/graalvm/compiler/core/amd64/AMD64AddressLowering.java	Fri Feb 16 12:24:38 2018 -0800
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.amd64/src/org/graalvm/compiler/core/amd64/AMD64AddressLowering.java	Fri Feb 16 13:49:07 2018 -0800
@@ -27,7 +27,6 @@
 import org.graalvm.compiler.core.common.NumUtil;
 import org.graalvm.compiler.core.common.type.AbstractPointerStamp;
 import org.graalvm.compiler.core.common.type.IntegerStamp;
-import org.graalvm.compiler.core.common.type.PrimitiveStamp;
 import org.graalvm.compiler.debug.DebugContext;
 import org.graalvm.compiler.nodes.NodeView;
 import org.graalvm.compiler.nodes.StructuredGraph;
@@ -107,7 +106,9 @@
                 ret.setBase(add.getX());
                 ret.setIndex(considerNegation(graph, add.getY(), isBaseNegated));
                 return true;
-            } else if (ret.getBase() == null && ret.getIndex() instanceof AddNode) {
+            }
+
+            if (ret.getBase() == null && ret.getIndex() instanceof AddNode) {
                 AddNode add = (AddNode) ret.getIndex();
                 ret.setBase(considerNegation(graph, add.getX(), isIndexNegated));
                 ret.setIndex(add.getY());
@@ -188,7 +189,7 @@
             return improveConstDisp(address, node, c, null, shift, negateExtractedDisplacement);
         } else {
             if (node.stamp(NodeView.DEFAULT) instanceof IntegerStamp) {
-                assert PrimitiveStamp.getBits(node.stamp(NodeView.DEFAULT)) == ADDRESS_BITS;
+                assert IntegerStamp.getBits(node.stamp(NodeView.DEFAULT)) == ADDRESS_BITS;
 
                 /*
                  * we can't swallow zero-extends because of multiple reasons:
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.amd64/src/org/graalvm/compiler/core/amd64/AMD64CompressAddressLowering.java	Fri Feb 16 13:49:07 2018 -0800
@@ -0,0 +1,98 @@
+/*
+ * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package org.graalvm.compiler.core.amd64;
+
+import jdk.vm.ci.code.Register;
+import org.graalvm.compiler.asm.amd64.AMD64Address;
+import org.graalvm.compiler.core.common.LIRKind;
+import org.graalvm.compiler.core.common.type.StampFactory;
+import org.graalvm.compiler.debug.CounterKey;
+import org.graalvm.compiler.debug.DebugContext;
+import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodes.CompressionNode;
+import org.graalvm.compiler.nodes.NodeView;
+import org.graalvm.compiler.nodes.StructuredGraph;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.calc.FloatingNode;
+import org.graalvm.compiler.nodes.spi.LIRLowerable;
+import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool;
+
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_0;
+import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_0;
+
+public abstract class AMD64CompressAddressLowering extends AMD64AddressLowering {
+    private static final CounterKey counterFoldedUncompressDuringAddressLowering = DebugContext.counter("FoldedUncompressDuringAddressLowering");
+
+    @Override
+    protected final boolean improve(StructuredGraph graph, DebugContext debug, AMD64AddressNode addr, boolean isBaseNegated, boolean isIndexNegated) {
+        if (super.improve(graph, debug, addr, isBaseNegated, isIndexNegated)) {
+            return true;
+        }
+
+        if (!isBaseNegated && !isIndexNegated && addr.getScale() == AMD64Address.Scale.Times1) {
+            ValueNode base = addr.getBase();
+            ValueNode index = addr.getIndex();
+
+            if (tryToImproveUncompression(addr, index, base) || tryToImproveUncompression(addr, base, index)) {
+                counterFoldedUncompressDuringAddressLowering.increment(debug);
+                return true;
+            }
+        }
+
+        return false;
+    }
+
+    private boolean tryToImproveUncompression(AMD64AddressNode addr, ValueNode value, ValueNode other) {
+        if (value instanceof CompressionNode) {
+            CompressionNode compression = (CompressionNode) value;
+            if (compression.getOp() == CompressionNode.CompressionOp.Uncompress && improveUncompression(addr, compression, other)) {
+                return true;
+            }
+        }
+
+        return false;
+    }
+
+    protected abstract boolean improveUncompression(AMD64AddressNode addr, CompressionNode compression, ValueNode other);
+
+    @NodeInfo(cycles = CYCLES_0, size = SIZE_0)
+    public static class HeapBaseNode extends FloatingNode implements LIRLowerable {
+
+        public static final NodeClass<HeapBaseNode> TYPE = NodeClass.create(HeapBaseNode.class);
+
+        private final Register heapBaseRegister;
+
+        public HeapBaseNode(Register heapBaseRegister) {
+            super(TYPE, StampFactory.pointer());
+            this.heapBaseRegister = heapBaseRegister;
+        }
+
+        @Override
+        public void generate(NodeLIRBuilderTool generator) {
+            LIRKind kind = generator.getLIRGeneratorTool().getLIRKind(stamp(NodeView.DEFAULT));
+            generator.setResult(this, heapBaseRegister.asValue(kind));
+        }
+    }
+}
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.amd64/src/org/graalvm/compiler/core/amd64/AMD64MoveFactoryBase.java	Fri Feb 16 12:24:38 2018 -0800
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.amd64/src/org/graalvm/compiler/core/amd64/AMD64MoveFactoryBase.java	Fri Feb 16 13:49:07 2018 -0800
@@ -26,14 +26,14 @@
 import static org.graalvm.compiler.asm.amd64.AMD64Assembler.OperandSize.QWORD;
 import static org.graalvm.compiler.asm.amd64.AMD64Assembler.OperandSize.WORD;
 
+import org.graalvm.collections.EconomicMap;
+import org.graalvm.collections.Equivalence;
 import org.graalvm.compiler.core.common.LIRKind;
 import org.graalvm.compiler.lir.VirtualStackSlot;
 import org.graalvm.compiler.lir.amd64.AMD64LIRInstruction;
 import org.graalvm.compiler.lir.amd64.AMD64Move.AMD64PushPopStackMove;
 import org.graalvm.compiler.lir.framemap.FrameMapBuilder;
 import org.graalvm.compiler.lir.gen.LIRGeneratorTool.MoveFactory;
-import org.graalvm.util.Equivalence;
-import org.graalvm.util.EconomicMap;
 
 import jdk.vm.ci.amd64.AMD64Kind;
 import jdk.vm.ci.code.Architecture;
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.amd64/src/org/graalvm/compiler/core/amd64/AMD64NodeMatchRules.java	Fri Feb 16 12:24:38 2018 -0800
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.amd64/src/org/graalvm/compiler/core/amd64/AMD64NodeMatchRules.java	Fri Feb 16 13:49:07 2018 -0800
@@ -44,6 +44,7 @@
 import org.graalvm.compiler.asm.amd64.AMD64Assembler.SSEOp;
 import org.graalvm.compiler.core.common.LIRKind;
 import org.graalvm.compiler.core.common.NumUtil;
+import org.graalvm.compiler.core.common.calc.CanonicalCondition;
 import org.graalvm.compiler.core.common.calc.Condition;
 import org.graalvm.compiler.core.gen.NodeLIRBuilder;
 import org.graalvm.compiler.core.gen.NodeMatchRules;
@@ -128,7 +129,7 @@
     }
 
     protected ComplexMatchResult emitCompareBranchMemory(IfNode ifNode, CompareNode compare, ValueNode value, LIRLowerableAccess access) {
-        Condition cond = compare.condition();
+        Condition cond = compare.condition().asCondition();
         AMD64Kind kind = getMemoryKind(access);
         boolean matchedAsConstant = false; // For assertion checking
 
@@ -303,7 +304,7 @@
     @MatchRule("(If (FloatEquals=compare value ValueCompareAndSwap=cas))")
     @MatchRule("(If (IntegerEquals=compare value ValueCompareAndSwap=cas))")
     public ComplexMatchResult ifCompareValueCas(IfNode root, CompareNode compare, ValueNode value, ValueCompareAndSwapNode cas) {
-        assert compare.condition() == Condition.EQ;
+        assert compare.condition() == CanonicalCondition.EQ;
         if (value == cas.getExpectedValue() && cas.usages().count() == 1) {
             return builder -> {
                 LIRKind kind = getLirKind(cas);
@@ -326,7 +327,7 @@
     @MatchRule("(If (IntegerEquals=compare value LogicCompareAndSwap=cas))")
     public ComplexMatchResult ifCompareLogicCas(IfNode root, CompareNode compare, ValueNode value, LogicCompareAndSwapNode cas) {
         JavaConstant constant = value.asJavaConstant();
-        assert compare.condition() == Condition.EQ;
+        assert compare.condition() == CanonicalCondition.EQ;
         if (constant != null && cas.usages().count() == 1) {
             long constantValue = constant.asLong();
             boolean successIsTrue;
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/GraalOptions.java	Fri Feb 16 12:24:38 2018 -0800
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/GraalOptions.java	Fri Feb 16 13:49:07 2018 -0800
@@ -233,6 +233,9 @@
     public static final OptionKey<Boolean> OptScheduleOutOfLoops = new OptionKey<>(true);
 
     @Option(help = "", type = OptionType.Debug)
+    public static final OptionKey<Boolean> GuardPriorities = new OptionKey<>(true);
+
+    @Option(help = "", type = OptionType.Debug)
     public static final OptionKey<Boolean> OptEliminateGuards = new OptionKey<>(true);
 
     @Option(help = "", type = OptionType.Debug)
@@ -271,4 +274,7 @@
     @Option(help = "Enable experimental Trace Register Allocation.", type = OptionType.Debug)
     public static final OptionKey<Boolean> TraceRA = new OptionKey<>(false);
 
+    @Option(help = "How to trace inlining decisions, one of: None, Linear, Tree", type = OptionType.Debug)
+    public static final OptionKey<TraceInliningMode> TraceInlining = new OptionKey<>(TraceInliningMode.None);
+
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/TraceInliningMode.java	Fri Feb 16 13:49:07 2018 -0800
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.core.common;
+
+public enum TraceInliningMode {
+    None(false),
+    Linear(true),
+    Tree(true);
+
+    private final boolean tracing;
+
+    TraceInliningMode(boolean tracing) {
+        this.tracing = tracing;
+    }
+
+    public boolean isTracing() {
+        return tracing;
+    }
+}
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/alloc/RegisterAllocationConfig.java	Fri Feb 16 12:24:38 2018 -0800
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/alloc/RegisterAllocationConfig.java	Fri Feb 16 13:49:07 2018 -0800
@@ -22,9 +22,9 @@
  */
 package org.graalvm.compiler.core.common.alloc;
 
+import org.graalvm.collections.EconomicMap;
+import org.graalvm.collections.Equivalence;
 import org.graalvm.compiler.core.common.GraalOptions;
-import org.graalvm.util.EconomicMap;
-import org.graalvm.util.Equivalence;
 
 import jdk.vm.ci.code.Register;
 import jdk.vm.ci.code.Register.RegisterCategory;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/calc/CanonicalCondition.java	Fri Feb 16 13:49:07 2018 -0800
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2009, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.core.common.calc;
+
+import jdk.vm.ci.meta.Constant;
+import jdk.vm.ci.meta.ConstantReflectionProvider;
+import jdk.vm.ci.meta.PrimitiveConstant;
+
+public enum CanonicalCondition {
+    EQ(Condition.EQ),
+    LT(Condition.LT),
+    BT(Condition.BT);
+
+    private final Condition condition;
+
+    CanonicalCondition(Condition condition) {
+        assert condition.isCanonical();
+        this.condition = condition;
+    }
+
+    public Condition asCondition() {
+        return condition;
+    }
+
+    public boolean foldCondition(Constant lt, Constant rt, ConstantReflectionProvider constantReflection, boolean unorderedIsTrue) {
+        return asCondition().foldCondition(lt, rt, constantReflection, unorderedIsTrue);
+    }
+
+    public boolean foldCondition(PrimitiveConstant lp, PrimitiveConstant rp, boolean unorderedIsTrue) {
+        return asCondition().foldCondition(lp, rp, unorderedIsTrue);
+    }
+}
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/calc/Condition.java	Fri Feb 16 12:24:38 2018 -0800
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/calc/Condition.java	Fri Feb 16 13:49:07 2018 -0800
@@ -115,6 +115,55 @@
         throw new IllegalArgumentException(this.toString());
     }
 
+    public static final class CanonicalizedCondition {
+        private final CanonicalCondition canonicalCondition;
+        private final boolean mirror;
+        private final boolean negate;
+
+        private CanonicalizedCondition(CanonicalCondition canonicalCondition, boolean mirror, boolean negate) {
+            this.canonicalCondition = canonicalCondition;
+            this.mirror = mirror;
+            this.negate = negate;
+        }
+
+        public CanonicalCondition getCanonicalCondition() {
+            return canonicalCondition;
+        }
+
+        public boolean mustMirror() {
+            return mirror;
+        }
+
+        public boolean mustNegate() {
+            return negate;
+        }
+    }
+
+    public CanonicalizedCondition canonicalize() {
+        CanonicalCondition canonicalCondition;
+        switch (this) {
+            case EQ:
+            case NE:
+                canonicalCondition = CanonicalCondition.EQ;
+                break;
+            case LT:
+            case LE:
+            case GT:
+            case GE:
+                canonicalCondition = CanonicalCondition.LT;
+                break;
+            case BT:
+            case BE:
+            case AT:
+            case AE:
+                canonicalCondition = CanonicalCondition.BT;
+                break;
+            default:
+                throw new IllegalArgumentException(this.toString());
+        }
+        return new CanonicalizedCondition(canonicalCondition, canonicalMirror(), canonicalNegate());
+    }
+
     /**
      * Given a condition and its negation, this method returns true for one of the two and false for
      * the other one. This can be used to keep comparisons in a canonical form.
@@ -151,7 +200,7 @@
      * Returns true if the condition needs to be mirrored to get to a canonical condition. The
      * result of the mirroring operation might still need to be negated to achieve a canonical form.
      */
-    public boolean canonicalMirror() {
+    private boolean canonicalMirror() {
         switch (this) {
             case EQ:
                 return false;
@@ -181,7 +230,7 @@
      * Returns true if the condition needs to be negated to get to a canonical condition. The result
      * of the negation might still need to be mirrored to achieve a canonical form.
      */
-    public boolean canonicalNegate() {
+    private boolean canonicalNegate() {
         switch (this) {
             case EQ:
                 return false;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/spi/ArrayOffsetProvider.java	Fri Feb 16 13:49:07 2018 -0800
@@ -0,0 +1,32 @@
+/*
+ * Copyright (c) 2018, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.core.common.spi;
+
+import jdk.vm.ci.meta.JavaKind;
+
+public interface ArrayOffsetProvider {
+
+    int arrayBaseOffset(JavaKind elementKind);
+
+    int arrayScalingFactor(JavaKind elementKind);
+}
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/spi/CodeGenProviders.java	Fri Feb 16 12:24:38 2018 -0800
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/spi/CodeGenProviders.java	Fri Feb 16 13:49:07 2018 -0800
@@ -40,4 +40,5 @@
 
     ConstantReflectionProvider getConstantReflection();
 
+    ArrayOffsetProvider getArrayOffsetProvider();
 }
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/type/ArithmeticOpTable.java	Fri Feb 16 12:24:38 2018 -0800
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/type/ArithmeticOpTable.java	Fri Feb 16 13:49:07 2018 -0800
@@ -28,6 +28,9 @@
 import java.util.Objects;
 import java.util.function.Function;
 
+import jdk.vm.ci.meta.Constant;
+import jdk.vm.ci.meta.JavaKind;
+
 import org.graalvm.compiler.core.common.calc.FloatConvert;
 import org.graalvm.compiler.core.common.type.ArithmeticOpTable.BinaryOp.Add;
 import org.graalvm.compiler.core.common.type.ArithmeticOpTable.BinaryOp.And;
@@ -51,9 +54,6 @@
 import org.graalvm.compiler.core.common.type.ArithmeticOpTable.UnaryOp.Sqrt;
 import org.graalvm.util.CollectionsUtil;
 
-import jdk.vm.ci.meta.Constant;
-import jdk.vm.ci.meta.JavaKind;
-
 /**
  * Information about arithmetic operations.
  */
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/util/FrequencyEncoder.java	Fri Feb 16 12:24:38 2018 -0800
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.common/src/org/graalvm/compiler/core/common/util/FrequencyEncoder.java	Fri Feb 16 13:49:07 2018 -0800
@@ -25,8 +25,8 @@
 import java.util.ArrayList;
 import java.util.List;
 
-import org.graalvm.util.EconomicMap;
-import org.graalvm.util.Equivalence;
+import org.graalvm.collections.EconomicMap;
+import org.graalvm.collections.Equivalence;
 
 /**
  * Creates an array of T objects order by the occurrence frequency of each object. The most
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.match.processor/src/org/graalvm/compiler/core/match/processor/MatchProcessor.java	Fri Feb 16 12:24:38 2018 -0800
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.match.processor/src/org/graalvm/compiler/core/match/processor/MatchProcessor.java	Fri Feb 16 13:49:07 2018 -0800
@@ -58,6 +58,9 @@
 import javax.tools.JavaFileObject;
 import javax.tools.StandardLocation;
 
+import org.graalvm.collections.EconomicMap;
+import org.graalvm.collections.EconomicSet;
+import org.graalvm.collections.Equivalence;
 import org.graalvm.compiler.core.gen.NodeMatchRules;
 import org.graalvm.compiler.core.match.ComplexMatchResult;
 import org.graalvm.compiler.core.match.MatchRule;
@@ -70,9 +73,6 @@
 import org.graalvm.compiler.graph.Position;
 import org.graalvm.compiler.nodes.ValueNode;
 import org.graalvm.compiler.serviceprovider.ServiceProvider;
-import org.graalvm.util.Equivalence;
-import org.graalvm.util.EconomicMap;
-import org.graalvm.util.EconomicSet;
 
 /**
  * Processes classes annotated with {@link MatchRule}. A {@link MatchStatementSet} service is
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.sparc.test/src/org/graalvm/compiler/core/sparc/test/SPARCAllocatorTest.java	Fri Feb 16 12:24:38 2018 -0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,72 +0,0 @@
-/*
- * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package org.graalvm.compiler.core.sparc.test;
-
-import static org.graalvm.compiler.core.common.GraalOptions.RegisterPressure;
-import static org.graalvm.compiler.core.common.GraalOptions.TraceRA;
-import static org.junit.Assume.assumeTrue;
-
-import org.junit.Before;
-import org.junit.Test;
-
-import org.graalvm.compiler.core.test.backend.AllocatorTest;
-
-import jdk.vm.ci.sparc.SPARC;
-
-public class SPARCAllocatorTest extends AllocatorTest {
-
-    @Before
-    public void checkSPARC() {
-        assumeTrue("skipping SPARC specific test", getTarget().arch instanceof SPARC);
-        assumeTrue("RegisterPressure is set -> skip", RegisterPressure.getValue(getInitialOptions()) == null);
-        assumeTrue("TraceRA is set -> skip", !TraceRA.getValue(getInitialOptions()));
-    }
-
-    @Test
-    public void test1() {
-        testAllocation("test1snippet", 2, 0, 0);
-    }
-
-    public static long test1snippet(long x) {
-        return x + 41;
-    }
-
-    @Test
-    public void test2() {
-        testAllocation("test2snippet", 2, 0, 0);
-    }
-
-    public static long test2snippet(long x) {
-        return x * 41;
-    }
-
-    @Test
-    public void test3() {
-        testAllocation("test3snippet", 4, 0, 0);
-    }
-
-    public static long test3snippet(long x) {
-        return x / 41 + x % 41;
-    }
-
-}
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.sparc/src/org/graalvm/compiler/core/sparc/SPARCNodeMatchRules.java	Fri Feb 16 12:24:38 2018 -0800
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.sparc/src/org/graalvm/compiler/core/sparc/SPARCNodeMatchRules.java	Fri Feb 16 13:49:07 2018 -0800
@@ -29,6 +29,7 @@
 import static jdk.vm.ci.sparc.SPARCKind.XWORD;
 
 import org.graalvm.compiler.core.common.LIRKind;
+import org.graalvm.compiler.core.common.calc.CanonicalCondition;
 import org.graalvm.compiler.core.common.calc.Condition;
 import org.graalvm.compiler.core.gen.NodeMatchRules;
 import org.graalvm.compiler.core.match.ComplexMatchResult;
@@ -147,7 +148,7 @@
     @MatchRule("(If (IntegerEquals=compare value LogicCompareAndSwap=cas))")
     public ComplexMatchResult ifCompareLogicCas(IfNode root, CompareNode compare, ValueNode value, LogicCompareAndSwapNode cas) {
         JavaConstant constant = value.asJavaConstant();
-        assert compare.condition() == Condition.EQ;
+        assert compare.condition() == CanonicalCondition.EQ;
         if (constant != null && cas.usages().count() == 1) {
             long constantValue = constant.asLong();
             boolean successIsTrue;
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ConditionalEliminationTest11.java	Fri Feb 16 12:24:38 2018 -0800
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ConditionalEliminationTest11.java	Fri Feb 16 13:49:07 2018 -0800
@@ -123,19 +123,19 @@
 
     public static int test6Snippet(int a) {
         if ((a & 8) != 0) {
-            GraalDirectives.deoptimizeAndInvalidate();
+            GraalDirectives.deoptimize();
         }
         if ((a & 15) != 15) {
-            GraalDirectives.deoptimizeAndInvalidate();
+            GraalDirectives.deoptimize();
         }
         return 0;
     }
 
     public static int reference6Snippet(int a) {
         if ((a & 8) != 0) {
-            GraalDirectives.deoptimizeAndInvalidate();
+            GraalDirectives.deoptimize();
         }
-        GraalDirectives.deoptimizeAndInvalidate();
+        GraalDirectives.deoptimize();
         return 0;
     }
 
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ConditionalEliminationTestBase.java	Fri Feb 16 12:24:38 2018 -0800
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ConditionalEliminationTestBase.java	Fri Feb 16 13:49:07 2018 -0800
@@ -74,7 +74,6 @@
             new IterativeConditionalEliminationPhase(canonicalizer, true).apply(graph, context);
             canonicalizer.apply(graph, context);
             canonicalizer.apply(graph, context);
-            new ConvertDeoptimizeToGuardPhase().apply(graph, context);
         } catch (Throwable t) {
             debug.handle(t);
         }
@@ -86,7 +85,6 @@
             }
             canonicalizer.apply(referenceGraph, context);
             canonicalizer.apply(referenceGraph, context);
-            new ConvertDeoptimizeToGuardPhase().apply(graph, context);
         } catch (Throwable t) {
             debug.handle(t);
         }
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/CountedLoopTest.java	Fri Feb 16 12:24:38 2018 -0800
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/CountedLoopTest.java	Fri Feb 16 13:49:07 2018 -0800
@@ -25,14 +25,12 @@
 import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_IGNORED;
 import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_IGNORED;
 
-import org.graalvm.compiler.nodes.NodeView;
-import org.junit.Test;
-
 import org.graalvm.compiler.api.directives.GraalDirectives;
 import org.graalvm.compiler.graph.NodeClass;
 import org.graalvm.compiler.loop.InductionVariable;
 import org.graalvm.compiler.loop.LoopsData;
 import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.nodes.NodeView;
 import org.graalvm.compiler.nodes.StructuredGraph;
 import org.graalvm.compiler.nodes.ValueNode;
 import org.graalvm.compiler.nodes.calc.FloatingNode;
@@ -42,6 +40,7 @@
 import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugins.Registration;
 import org.graalvm.compiler.nodes.spi.LIRLowerable;
 import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool;
+import org.junit.Test;
 
 import jdk.vm.ci.meta.JavaKind;
 import jdk.vm.ci.meta.ResolvedJavaMethod;
@@ -117,6 +116,21 @@
         test("incrementSnippet", 0, 256, 3);
     }
 
+    @Test
+    public void increment4() {
+        test("incrementSnippet", -10, Integer.MAX_VALUE, 1);
+    }
+
+    @Test
+    public void increment5() {
+        test("incrementSnippet", 256, 256, 1);
+    }
+
+    @Test
+    public void increment6() {
+        test("incrementSnippet", 257, 256, 1);
+    }
+
     public static Result incrementEqSnippet(int start, int limit, int step) {
         int i;
         int inc = ((step - 1) & 0xFFFF) + 1; // make sure this value is always strictly positive
@@ -144,6 +158,21 @@
         test("incrementEqSnippet", 0, 256, 3);
     }
 
+    @Test
+    public void incrementEq4() {
+        test("incrementEqSnippet", -10, 0, Integer.MAX_VALUE);
+    }
+
+    @Test
+    public void incrementEq5() {
+        test("incrementEqSnippet", 256, 256, 1);
+    }
+
+    @Test
+    public void incrementEq6() {
+        test("incrementEqSnippet", 257, 256, 1);
+    }
+
     public static Result decrementSnippet(int start, int limit, int step) {
         int i;
         int dec = ((step - 1) & 0xFFFF) + 1; // make sure this value is always strictly positive
@@ -198,6 +227,11 @@
         test("decrementEqSnippet", 256, 0, 3);
     }
 
+    @Test
+    public void decrementEq4() {
+        test("decrementEqSnippet", -10, 0, Integer.MAX_VALUE);
+    }
+
     public static Result twoVariablesSnippet() {
         Result ret = new Result();
         int j = 0;
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/DumpPathTest.java	Fri Feb 16 12:24:38 2018 -0800
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/DumpPathTest.java	Fri Feb 16 13:49:07 2018 -0800
@@ -27,10 +27,10 @@
 import java.nio.file.Files;
 import java.nio.file.Path;
 
+import org.graalvm.collections.EconomicMap;
 import org.graalvm.compiler.debug.DebugOptions;
 import org.graalvm.compiler.options.OptionKey;
 import org.graalvm.compiler.options.OptionValues;
-import org.graalvm.util.EconomicMap;
 import org.junit.Test;
 
 /**
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/GraalCompilerTest.java	Fri Feb 16 12:24:38 2018 -0800
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/GraalCompilerTest.java	Fri Feb 16 13:49:07 2018 -0800
@@ -561,7 +561,7 @@
      * @return a scheduled textual dump of {@code graph} .
      */
     protected static String getScheduledGraphString(StructuredGraph graph) {
-        SchedulePhase schedule = new SchedulePhase(SchedulingStrategy.EARLIEST);
+        SchedulePhase schedule = new SchedulePhase(SchedulingStrategy.EARLIEST_WITH_GUARD_ORDER);
         schedule.apply(graph);
         ScheduleResult scheduleResult = graph.getLastSchedule();
 
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/GraphResetDebugTest.java	Fri Feb 16 12:24:38 2018 -0800
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/GraphResetDebugTest.java	Fri Feb 16 13:49:07 2018 -0800
@@ -22,14 +22,14 @@
  */
 package org.graalvm.compiler.core.test;
 
+import org.graalvm.collections.EconomicMap;
 import org.graalvm.compiler.debug.DebugContext;
+import org.graalvm.compiler.debug.DebugContext.Scope;
 import org.graalvm.compiler.debug.DebugOptions;
-import org.graalvm.compiler.debug.DebugContext.Scope;
 import org.graalvm.compiler.nodes.StructuredGraph;
 import org.graalvm.compiler.nodes.StructuredGraph.AllowAssumptions;
 import org.graalvm.compiler.options.OptionKey;
 import org.graalvm.compiler.options.OptionValues;
-import org.graalvm.util.EconomicMap;
 import org.junit.Assert;
 import org.junit.Test;
 
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/GraphScheduleTest.java	Fri Feb 16 12:24:38 2018 -0800
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/GraphScheduleTest.java	Fri Feb 16 13:49:07 2018 -0800
@@ -24,20 +24,29 @@
 
 import java.util.List;
 
-import org.junit.Assert;
-
 import org.graalvm.compiler.graph.Node;
 import org.graalvm.compiler.graph.NodeMap;
 import org.graalvm.compiler.nodes.StructuredGraph;
 import org.graalvm.compiler.nodes.StructuredGraph.ScheduleResult;
 import org.graalvm.compiler.nodes.cfg.Block;
 import org.graalvm.compiler.phases.schedule.SchedulePhase;
+import org.junit.Assert;
+
+import jdk.vm.ci.meta.SpeculationLog;
 
 public class GraphScheduleTest extends GraalCompilerTest {
 
     protected void assertOrderedAfterSchedule(StructuredGraph graph, Node a, Node b) {
-        SchedulePhase ibp = new SchedulePhase(SchedulePhase.SchedulingStrategy.LATEST);
+        assertOrderedAfterSchedule(graph, SchedulePhase.SchedulingStrategy.LATEST, a, b);
+    }
+
+    protected void assertOrderedAfterSchedule(StructuredGraph graph, SchedulePhase.SchedulingStrategy strategy, Node a, Node b) {
+        SchedulePhase ibp = new SchedulePhase(strategy);
         ibp.apply(graph);
+        assertOrderedAfterLastSchedule(graph, a, b);
+    }
+
+    protected void assertOrderedAfterLastSchedule(StructuredGraph graph, Node a, Node b) {
         assertOrderedAfterSchedule(graph.getLastSchedule(), a, b);
     }
 
@@ -48,7 +57,7 @@
 
         if (bBlock == aBlock) {
             List<Node> instructions = ibp.nodesFor(bBlock);
-            Assert.assertTrue(instructions.indexOf(b) > instructions.indexOf(a));
+            Assert.assertTrue(a + " should be before " + b, instructions.indexOf(b) > instructions.indexOf(a));
         } else {
             Block block = bBlock;
             while (block != null) {
@@ -60,4 +69,9 @@
             Assert.fail("block of A doesn't dominate the block of B");
         }
     }
+
+    @Override
+    protected SpeculationLog getSpeculationLog() {
+        return getCodeCache().createSpeculationLog();
+    }
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/GuardPrioritiesTest.java	Fri Feb 16 13:49:07 2018 -0800
@@ -0,0 +1,131 @@
+/*
+ * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.core.test;
+
+import static org.graalvm.compiler.graph.test.matchers.NodeIterableCount.hasCount;
+import static org.graalvm.compiler.graph.test.matchers.NodeIterableIsEmpty.isNotEmpty;
+import static org.junit.Assert.assertThat;
+import static org.junit.Assume.assumeThat;
+import static org.junit.Assume.assumeTrue;
+
+import java.util.Iterator;
+
+import org.graalvm.compiler.api.directives.GraalDirectives;
+import org.graalvm.compiler.core.common.GraalOptions;
+import org.graalvm.compiler.graph.iterators.NodeIterable;
+import org.graalvm.compiler.nodes.GuardNode;
+import org.graalvm.compiler.nodes.ParameterNode;
+import org.graalvm.compiler.nodes.StructuredGraph;
+import org.graalvm.compiler.nodes.calc.IntegerLowerThanNode;
+import org.graalvm.compiler.nodes.calc.IsNullNode;
+import org.graalvm.compiler.nodes.spi.LoweringTool;
+import org.graalvm.compiler.phases.common.CanonicalizerPhase;
+import org.graalvm.compiler.phases.common.ConvertDeoptimizeToGuardPhase;
+import org.graalvm.compiler.phases.common.FloatingReadPhase;
+import org.graalvm.compiler.phases.common.LoweringPhase;
+import org.graalvm.compiler.phases.schedule.SchedulePhase;
+import org.graalvm.compiler.phases.tiers.HighTierContext;
+import org.junit.Test;
+
+public class GuardPrioritiesTest extends GraphScheduleTest {
+    private int[] array;
+    private int size;
+
+    public void growing(int e) {
+        if (size >= array.length) {
+            // grow
+            GraalDirectives.deoptimizeAndInvalidateWithSpeculation();
+        }
+        array[size++] = e;
+    }
+
+    @Test
+    public void growingTest() {
+        assumeTrue("GuardPriorities must be turned one", GraalOptions.GuardPriorities.getValue(getInitialOptions()));
+        StructuredGraph graph = prepareGraph("growing");
+
+        NodeIterable<GuardNode> guards = graph.getNodes(GuardNode.TYPE).filter(n -> n.inputs().filter(i -> i instanceof IntegerLowerThanNode).isNotEmpty());
+        assertThat(guards, isNotEmpty());
+        assumeThat(guards, hasCount(2));
+
+        Iterator<GuardNode> iterator = guards.iterator();
+        GuardNode g1 = iterator.next();
+        GuardNode g2 = iterator.next();
+        assertTrue("There should be one guard with speculation, the other one without", g1.getSpeculation().isNull() ^ g2.getSpeculation().isNull());
+        GuardNode withSpeculation = g1.getSpeculation().isNull() ? g2 : g1;
+        GuardNode withoutSpeculation = g1.getSpeculation().isNull() ? g1 : g2;
+
+        assertOrderedAfterSchedule(graph, SchedulePhase.SchedulingStrategy.EARLIEST_WITH_GUARD_ORDER, withSpeculation, withoutSpeculation);
+    }
+
+    private StructuredGraph prepareGraph(String method) {
+        StructuredGraph graph = parseEager(method, StructuredGraph.AllowAssumptions.YES);
+        HighTierContext highTierContext = getDefaultHighTierContext();
+        CanonicalizerPhase canonicalizer = new CanonicalizerPhase();
+        new ConvertDeoptimizeToGuardPhase().apply(graph, highTierContext);
+        new LoweringPhase(canonicalizer, LoweringTool.StandardLoweringStage.HIGH_TIER).apply(graph, highTierContext);
+        new FloatingReadPhase().apply(graph);
+        return graph;
+    }
+
+    public int unknownCondition(Integer c, Object o, int[] a, Integer i) {
+        if (o != null) {
+            GraalDirectives.deoptimizeAndInvalidate();
+        }
+        if (i > 5560) {
+            GraalDirectives.deoptimizeAndInvalidate();
+        }
+        if (c >= 10) {
+            GraalDirectives.deoptimizeAndInvalidateWithSpeculation();
+        }
+        return array[8] + a[i];
+    }
+
+    @Test
+    public void unknownTest() {
+        assumeTrue("GuardPriorities must be turned one", GraalOptions.GuardPriorities.getValue(getInitialOptions()));
+        StructuredGraph graph = prepareGraph("unknownCondition");
+
+        new SchedulePhase(SchedulePhase.SchedulingStrategy.EARLIEST_WITH_GUARD_ORDER).apply(graph);
+        for (GuardNode g1 : graph.getNodes(GuardNode.TYPE)) {
+            for (GuardNode g2 : graph.getNodes(GuardNode.TYPE)) {
+                if (g1.getSpeculation().isNull() ^ g2.getSpeculation().isNull()) {
+                    GuardNode withSpeculation = g1.getSpeculation().isNull() ? g2 : g1;
+                    GuardNode withoutSpeculation = g1.getSpeculation().isNull() ? g1 : g2;
+
+                    if (withoutSpeculation.isNegated() && withoutSpeculation.getCondition() instanceof IsNullNode) {
+                        IsNullNode isNullNode = (IsNullNode) withoutSpeculation.getCondition();
+                        if (isNullNode.getValue() instanceof ParameterNode && ((ParameterNode) isNullNode.getValue()).index() == 1) {
+                            // this is the null check before the speculative guard, it's the only
+                            // one that should be above
+                            assertOrderedAfterLastSchedule(graph, withoutSpeculation, withSpeculation);
+                            continue;
+                        }
+                    }
+
+                    assertOrderedAfterLastSchedule(graph, withSpeculation, withoutSpeculation);
+                }
+            }
+        }
+    }
+}
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/LongNodeChainTest.java	Fri Feb 16 12:24:38 2018 -0800
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/LongNodeChainTest.java	Fri Feb 16 13:49:07 2018 -0800
@@ -44,7 +44,7 @@
 
     public static final int N = 10000;
 
-    private static final SchedulingStrategy[] Strategies = new SchedulingStrategy[]{SchedulingStrategy.EARLIEST};
+    private static final SchedulingStrategy[] Strategies = new SchedulingStrategy[]{SchedulingStrategy.EARLIEST_WITH_GUARD_ORDER};
 
     @Test
     public void testLongAddChain() {
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ReflectionOptionDescriptors.java	Fri Feb 16 12:24:38 2018 -0800
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/ReflectionOptionDescriptors.java	Fri Feb 16 13:49:07 2018 -0800
@@ -31,13 +31,13 @@
 import java.util.Map;
 import java.util.Properties;
 
+import org.graalvm.collections.EconomicMap;
+import org.graalvm.collections.MapCursor;
 import org.graalvm.compiler.options.Option;
 import org.graalvm.compiler.options.OptionDescriptor;
 import org.graalvm.compiler.options.OptionDescriptors;
 import org.graalvm.compiler.options.OptionKey;
 import org.graalvm.compiler.options.OptionValues;
-import org.graalvm.util.EconomicMap;
-import org.graalvm.util.MapCursor;
 
 /**
  * An implementation of {@link OptionDescriptor} that uses reflection to create descriptors from a
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/SchedulingTest2.java	Fri Feb 16 12:24:38 2018 -0800
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/SchedulingTest2.java	Fri Feb 16 13:49:07 2018 -0800
@@ -70,7 +70,7 @@
         returnNode.replaceAtPredecessor(beginNode);
         beginNode.setNext(returnNode);
         debug.dump(DebugContext.BASIC_LEVEL, graph, "Graph");
-        SchedulePhase schedulePhase = new SchedulePhase(SchedulingStrategy.EARLIEST);
+        SchedulePhase schedulePhase = new SchedulePhase(SchedulingStrategy.EARLIEST_WITH_GUARD_ORDER);
         schedulePhase.apply(graph);
         ScheduleResult schedule = graph.getLastSchedule();
         BlockMap<List<Node>> blockToNodesMap = schedule.getBlockToNodesMap();
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/TrivialInliningExplosionTest.java	Fri Feb 16 13:49:07 2018 -0800
@@ -0,0 +1,82 @@
+/*
+ * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.core.test;
+
+import org.graalvm.compiler.core.common.CompilationIdentifier;
+import org.graalvm.compiler.core.common.GraalOptions;
+import org.graalvm.compiler.java.BytecodeParserOptions;
+import org.graalvm.compiler.nodes.StructuredGraph;
+import org.graalvm.compiler.options.OptionValues;
+import org.junit.Assert;
+import org.junit.Test;
+
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+
+/**
+ * Tests that the defaults for {@link GraalOptions#TrivialInliningSize} and
+ * {@link BytecodeParserOptions#InlineDuringParsingMaxDepth} prevent explosive graph growth for code
+ * with small recursive methods.
+ */
+public class TrivialInliningExplosionTest extends GraalCompilerTest {
+
+    public static void trivial() {
+        trivial();
+        trivial();
+        trivial();
+    }
+
+    public static void main() {
+        trivial();
+        trivial();
+        trivial();
+        trivial();
+        trivial();
+        trivial();
+        trivial();
+        trivial();
+        trivial();
+    }
+
+    private int afterParseSize;
+
+    @Override
+    protected StructuredGraph parseForCompile(ResolvedJavaMethod method, CompilationIdentifier compilationId, OptionValues options) {
+        final StructuredGraph graph = super.parseForCompile(method, compilationId, options);
+        this.afterParseSize = graph.getNodeCount();
+        return graph;
+    }
+
+    @Test
+    public void test() {
+        ResolvedJavaMethod methodm0 = getResolvedJavaMethod("trivial");
+        Assert.assertTrue(methodm0.getCodeSize() <= GraalOptions.TrivialInliningSize.getValue(getInitialOptions()));
+        test("main");
+        int afterCompileSize = lastCompiledGraph.getNodeCount();
+
+        // The values of afterParseSize and afterCompileSize when this
+        // test was written were 849 and 848 respectively.
+        Assert.assertTrue(afterParseSize < 2000);
+        Assert.assertTrue(afterCompileSize < 2000);
+
+    }
+}
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/inlining/NestedLoopEffectsPhaseComplexityTest.java	Fri Feb 16 12:24:38 2018 -0800
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core.test/src/org/graalvm/compiler/core/test/inlining/NestedLoopEffectsPhaseComplexityTest.java	Fri Feb 16 13:49:07 2018 -0800
@@ -24,6 +24,7 @@
 
 import static org.graalvm.compiler.phases.common.DeadCodeEliminationPhase.Optionality.Optional;
 
+import org.graalvm.collections.EconomicSet;
 import org.graalvm.compiler.core.test.GraalCompilerTest;
 import org.graalvm.compiler.debug.DebugContext;
 import org.graalvm.compiler.debug.TTY;
@@ -43,7 +44,6 @@
 import org.graalvm.compiler.phases.tiers.PhaseContext;
 import org.graalvm.compiler.virtual.phases.ea.EarlyReadEliminationPhase;
 import org.graalvm.compiler.virtual.phases.ea.PartialEscapePhase;
-import org.graalvm.util.EconomicSet;
 import org.junit.Test;
 
 import jdk.vm.ci.meta.ResolvedJavaMethod;
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/GraalCompiler.java	Fri Feb 16 12:24:38 2018 -0800
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/GraalCompiler.java	Fri Feb 16 13:49:07 2018 -0800
@@ -25,6 +25,7 @@
 import java.util.Collection;
 import java.util.List;
 
+import org.graalvm.collections.EconomicSet;
 import org.graalvm.compiler.code.CompilationResult;
 import org.graalvm.compiler.core.LIRGenerationPhase.LIRGenerationContext;
 import org.graalvm.compiler.core.common.GraalOptions;
@@ -64,7 +65,6 @@
 import org.graalvm.compiler.phases.tiers.Suites;
 import org.graalvm.compiler.phases.tiers.TargetProvider;
 import org.graalvm.compiler.phases.util.Providers;
-import org.graalvm.util.EconomicSet;
 
 import jdk.vm.ci.code.RegisterConfig;
 import jdk.vm.ci.code.TargetDescription;
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/gen/DebugInfoBuilder.java	Fri Feb 16 12:24:38 2018 -0800
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/gen/DebugInfoBuilder.java	Fri Feb 16 13:49:07 2018 -0800
@@ -26,6 +26,8 @@
 import java.util.Arrays;
 import java.util.Queue;
 
+import org.graalvm.collections.EconomicMap;
+import org.graalvm.collections.Equivalence;
 import org.graalvm.compiler.debug.CounterKey;
 import org.graalvm.compiler.debug.DebugContext;
 import org.graalvm.compiler.debug.GraalError;
@@ -42,8 +44,6 @@
 import org.graalvm.compiler.nodes.virtual.VirtualObjectNode;
 import org.graalvm.compiler.virtual.nodes.MaterializedObjectState;
 import org.graalvm.compiler.virtual.nodes.VirtualObjectState;
-import org.graalvm.util.EconomicMap;
-import org.graalvm.util.Equivalence;
 
 import jdk.vm.ci.code.BytecodeFrame;
 import jdk.vm.ci.code.VirtualObject;
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/gen/NodeLIRBuilder.java	Fri Feb 16 12:24:38 2018 -0800
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/gen/NodeLIRBuilder.java	Fri Feb 16 13:49:07 2018 -0800
@@ -33,6 +33,8 @@
 import java.util.Collection;
 import java.util.List;
 
+import org.graalvm.collections.EconomicMap;
+import org.graalvm.collections.UnmodifiableMapCursor;
 import org.graalvm.compiler.core.common.LIRKind;
 import org.graalvm.compiler.core.common.calc.Condition;
 import org.graalvm.compiler.core.common.cfg.AbstractBlockBase;
@@ -100,8 +102,6 @@
 import org.graalvm.compiler.nodes.spi.NodeValueMap;
 import org.graalvm.compiler.nodes.virtual.VirtualObjectNode;
 import org.graalvm.compiler.options.OptionValues;
-import org.graalvm.util.EconomicMap;
-import org.graalvm.util.UnmodifiableMapCursor;
 
 import jdk.vm.ci.code.CallingConvention;
 import jdk.vm.ci.code.StackSlot;
@@ -538,7 +538,8 @@
 
     public void emitCompareBranch(CompareNode compare, LabelRef trueSuccessor, LabelRef falseSuccessor, double trueSuccessorProbability) {
         PlatformKind kind = gen.getLIRKind(compare.getX().stamp(NodeView.DEFAULT)).getPlatformKind();
-        gen.emitCompareBranch(kind, operand(compare.getX()), operand(compare.getY()), compare.condition(), compare.unorderedIsTrue(), trueSuccessor, falseSuccessor, trueSuccessorProbability);
+        gen.emitCompareBranch(kind, operand(compare.getX()), operand(compare.getY()), compare.condition().asCondition(), compare.unorderedIsTrue(), trueSuccessor, falseSuccessor,
+                        trueSuccessorProbability);
     }
 
     public void emitIntegerTestBranch(IntegerTestNode test, LabelRef trueSuccessor, LabelRef falseSuccessor, double trueSuccessorProbability) {
@@ -566,7 +567,7 @@
         } else if (node instanceof CompareNode) {
             CompareNode compare = (CompareNode) node;
             PlatformKind kind = gen.getLIRKind(compare.getX().stamp(NodeView.DEFAULT)).getPlatformKind();
-            return gen.emitConditionalMove(kind, operand(compare.getX()), operand(compare.getY()), compare.condition(), compare.unorderedIsTrue(), trueValue, falseValue);
+            return gen.emitConditionalMove(kind, operand(compare.getX()), operand(compare.getY()), compare.condition().asCondition(), compare.unorderedIsTrue(), trueValue, falseValue);
         } else if (node instanceof LogicConstantNode) {
             return gen.emitMove(((LogicConstantNode) node).getValue() ? trueValue : falseValue);
         } else if (node instanceof IntegerTestNode) {
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/match/MatchContext.java	Fri Feb 16 12:24:38 2018 -0800
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/match/MatchContext.java	Fri Feb 16 13:49:07 2018 -0800
@@ -28,6 +28,8 @@
 import java.util.Arrays;
 import java.util.List;
 
+import org.graalvm.collections.EconomicMap;
+import org.graalvm.collections.Equivalence;
 import org.graalvm.compiler.core.gen.NodeLIRBuilder;
 import org.graalvm.compiler.core.match.MatchPattern.Result;
 import org.graalvm.compiler.debug.DebugContext;
@@ -35,8 +37,6 @@
 import org.graalvm.compiler.graph.Node;
 import org.graalvm.compiler.nodes.calc.FloatingNode;
 import org.graalvm.compiler.nodes.virtual.VirtualObjectNode;
-import org.graalvm.util.EconomicMap;
-import org.graalvm.util.Equivalence;
 
 /**
  * Container for state captured during a match.
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/match/MatchRuleRegistry.java	Fri Feb 16 12:24:38 2018 -0800
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/match/MatchRuleRegistry.java	Fri Feb 16 13:49:07 2018 -0800
@@ -27,6 +27,9 @@
 import java.util.ArrayList;
 import java.util.List;
 
+import org.graalvm.collections.EconomicMap;
+import org.graalvm.collections.Equivalence;
+import org.graalvm.collections.MapCursor;
 import org.graalvm.compiler.core.gen.NodeMatchRules;
 import org.graalvm.compiler.debug.DebugContext;
 import org.graalvm.compiler.debug.GraalError;
@@ -36,9 +39,6 @@
 import org.graalvm.compiler.graph.Position;
 import org.graalvm.compiler.options.OptionValues;
 import org.graalvm.compiler.serviceprovider.GraalServices;
-import org.graalvm.util.EconomicMap;
-import org.graalvm.util.Equivalence;
-import org.graalvm.util.MapCursor;
 
 public class MatchRuleRegistry {
 
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/phases/GraphChangeMonitoringPhase.java	Fri Feb 16 12:24:38 2018 -0800
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/phases/GraphChangeMonitoringPhase.java	Fri Feb 16 13:49:07 2018 -0800
@@ -22,6 +22,8 @@
  */
 package org.graalvm.compiler.core.phases;
 
+import org.graalvm.collections.EconomicSet;
+import org.graalvm.collections.Equivalence;
 import org.graalvm.compiler.debug.DebugContext;
 import org.graalvm.compiler.graph.Graph.NodeEvent;
 import org.graalvm.compiler.graph.Graph.NodeEventScope;
@@ -32,8 +34,6 @@
 import org.graalvm.compiler.phases.PhaseSuite;
 import org.graalvm.compiler.phases.common.util.HashSetNodeEventListener;
 import org.graalvm.compiler.phases.tiers.PhaseContext;
-import org.graalvm.util.EconomicSet;
-import org.graalvm.util.Equivalence;
 
 /**
  * A utility phase for detecting when a phase would change the graph and reporting extra information
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/target/Backend.java	Fri Feb 16 12:24:38 2018 -0800
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.core/src/org/graalvm/compiler/core/target/Backend.java	Fri Feb 16 13:49:07 2018 -0800
@@ -24,6 +24,7 @@
 
 import java.util.ArrayList;
 
+import org.graalvm.collections.EconomicSet;
 import org.graalvm.compiler.asm.Assembler;
 import org.graalvm.compiler.code.CompilationResult;
 import org.graalvm.compiler.core.common.CompilationIdentifier;
@@ -44,7 +45,6 @@
 import org.graalvm.compiler.phases.tiers.SuitesProvider;
 import org.graalvm.compiler.phases.tiers.TargetProvider;
 import org.graalvm.compiler.phases.util.Providers;
-import org.graalvm.util.EconomicSet;
 
 import jdk.vm.ci.code.BailoutException;
 import jdk.vm.ci.code.CodeCacheProvider;
@@ -204,31 +204,48 @@
         }
         try (DebugContext.Scope s2 = debug.scope("CodeInstall", debugContext);
                         DebugContext.Activation a = debug.activate()) {
-            for (CodeInstallationTask task : tasks) {
-                task.preProcess(compilationResult);
+            preCodeInstallationTasks(tasks, compilationResult);
+
+            InstalledCode installedCode;
+            try {
+                CompiledCode compiledCode = createCompiledCode(method, compilationRequest, compilationResult);
+                installedCode = getProviders().getCodeCache().installCode(method, compiledCode, predefinedInstalledCode, speculationLog, isDefault);
+            } catch (Throwable t) {
+                failCodeInstallationTasks(tasks, t);
+                throw t;
             }
 
-            CompiledCode compiledCode = createCompiledCode(method, compilationRequest, compilationResult);
-            InstalledCode installedCode = getProviders().getCodeCache().installCode(method, compiledCode, predefinedInstalledCode, speculationLog, isDefault);
+            postCodeInstallationTasks(tasks, installedCode);
 
-            // Run post-code installation tasks.
-            try {
-                for (CodeInstallationTask task : tasks) {
-                    task.postProcess(installedCode);
-                }
-                for (CodeInstallationTask task : tasks) {
-                    task.releaseInstallation(installedCode);
-                }
-            } catch (Throwable t) {
-                installedCode.invalidate();
-                throw t;
-            }
             return installedCode;
         } catch (Throwable e) {
             throw debug.handle(e);
         }
     }
 
+    private static void failCodeInstallationTasks(CodeInstallationTask[] tasks, Throwable t) {
+        for (CodeInstallationTask task : tasks) {
+            task.installFailed(t);
+        }
+    }
+
+    private static void preCodeInstallationTasks(CodeInstallationTask[] tasks, CompilationResult compilationResult) {
+        for (CodeInstallationTask task : tasks) {
+            task.preProcess(compilationResult);
+        }
+    }
+
+    private static void postCodeInstallationTasks(CodeInstallationTask[] tasks, InstalledCode installedCode) {
+        try {
+            for (CodeInstallationTask task : tasks) {
+                task.postProcess(installedCode);
+            }
+        } catch (Throwable t) {
+            installedCode.invalidate();
+            throw t;
+        }
+    }
+
     /**
      * Installs code based on a given compilation result.
      *
@@ -301,11 +318,10 @@
         }
 
         /**
-         * Task to run after all the post-code installation tasks are complete, used to release the
-         * installed code.
+         * Invoked after {@link #preProcess} when code installation fails.
          */
         @SuppressWarnings("unused")
-        public void releaseInstallation(InstalledCode installedCode) {
+        public void installFailed(Throwable t) {
         }
     }
 
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.debug.test/src/org/graalvm/compiler/debug/test/DebugContextTest.java	Fri Feb 16 12:24:38 2018 -0800
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.debug.test/src/org/graalvm/compiler/debug/test/DebugContextTest.java	Fri Feb 16 13:49:07 2018 -0800
@@ -34,6 +34,7 @@
 import java.util.Formatter;
 import java.util.List;
 
+import org.graalvm.collections.EconomicMap;
 import org.graalvm.compiler.debug.Assertions;
 import org.graalvm.compiler.debug.CounterKey;
 import org.graalvm.compiler.debug.DebugCloseable;
@@ -46,7 +47,6 @@
 import org.graalvm.compiler.debug.DebugVerifyHandler;
 import org.graalvm.compiler.options.OptionKey;
 import org.graalvm.compiler.options.OptionValues;
-import org.graalvm.util.EconomicMap;
 import org.junit.Assert;
 import org.junit.Assume;
 import org.junit.Test;
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.debug.test/src/org/graalvm/compiler/debug/test/TimerKeyTest.java	Fri Feb 16 12:24:38 2018 -0800
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.debug.test/src/org/graalvm/compiler/debug/test/TimerKeyTest.java	Fri Feb 16 13:49:07 2018 -0800
@@ -30,6 +30,7 @@
 
 import java.lang.management.ThreadMXBean;
 
+import org.graalvm.collections.EconomicMap;
 import org.graalvm.compiler.debug.DebugCloseable;
 import org.graalvm.compiler.debug.DebugContext;
 import org.graalvm.compiler.debug.DebugOptions;
@@ -37,7 +38,6 @@
 import org.graalvm.compiler.debug.TimerKey;
 import org.graalvm.compiler.options.OptionKey;
 import org.graalvm.compiler.options.OptionValues;
-import org.graalvm.util.EconomicMap;
 import org.junit.Assume;
 import org.junit.Before;
 import org.junit.Test;
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/CounterKeyImpl.java	Fri Feb 16 12:24:38 2018 -0800
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/CounterKeyImpl.java	Fri Feb 16 13:49:07 2018 -0800
@@ -22,7 +22,7 @@
  */
 package org.graalvm.compiler.debug;
 
-import org.graalvm.util.Pair;
+import org.graalvm.collections.Pair;
 
 class CounterKeyImpl extends AbstractKey implements CounterKey {
 
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/DebugContext.java	Fri Feb 16 12:24:38 2018 -0800
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/DebugContext.java	Fri Feb 16 13:49:07 2018 -0800
@@ -56,12 +56,12 @@
 import java.util.SortedMap;
 import java.util.TreeMap;
 
+import org.graalvm.collections.EconomicMap;
+import org.graalvm.collections.EconomicSet;
+import org.graalvm.collections.Pair;
 import org.graalvm.compiler.options.OptionKey;
 import org.graalvm.compiler.options.OptionValues;
 import org.graalvm.graphio.GraphOutput;
-import org.graalvm.util.EconomicMap;
-import org.graalvm.util.EconomicSet;
-import org.graalvm.util.Pair;
 
 import jdk.vm.ci.meta.JavaMethod;
 
@@ -1937,10 +1937,17 @@
         if (description != null) {
             printMetrics(description);
         }
-        if (metricsEnabled && globalMetrics != null && metricValues != null) {
+        if (metricsEnabled && metricValues != null && globalMetrics != null) {
             globalMetrics.add(this);
         }
         metricValues = null;
+        if (sharedChannel != null) {
+            try {
+                sharedChannel.realClose();
+            } catch (IOException ex) {
+                // ignore.
+            }
+        }
     }
 
     public void closeDumpHandlers(boolean ignoreErrors) {
@@ -2022,7 +2029,6 @@
                 }
             }
         }
-
     }
 
     /**
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/DebugOptions.java	Fri Feb 16 12:24:38 2018 -0800
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/DebugOptions.java	Fri Feb 16 13:49:07 2018 -0800
@@ -27,11 +27,11 @@
 import java.nio.file.Path;
 import java.nio.file.Paths;
 
+import org.graalvm.collections.EconomicMap;
 import org.graalvm.compiler.options.Option;
 import org.graalvm.compiler.options.OptionKey;
 import org.graalvm.compiler.options.OptionType;
 import org.graalvm.compiler.options.OptionValues;
-import org.graalvm.util.EconomicMap;
 
 /**
  * Options that configure a {@link DebugContext} and related functionality.
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/GlobalMetrics.java	Fri Feb 16 12:24:38 2018 -0800
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/GlobalMetrics.java	Fri Feb 16 13:49:07 2018 -0800
@@ -29,10 +29,10 @@
 import java.util.Collections;
 import java.util.List;
 
+import org.graalvm.collections.EconomicMap;
+import org.graalvm.collections.MapCursor;
+import org.graalvm.collections.Pair;
 import org.graalvm.compiler.options.OptionValues;
-import org.graalvm.util.EconomicMap;
-import org.graalvm.util.MapCursor;
-import org.graalvm.util.Pair;
 
 /**
  * Metric values that can be {@linkplain #add(DebugContext) updated} by multiple threads.
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/KeyRegistry.java	Fri Feb 16 12:24:38 2018 -0800
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/KeyRegistry.java	Fri Feb 16 13:49:07 2018 -0800
@@ -25,7 +25,7 @@
 import java.util.ArrayList;
 import java.util.List;
 
-import org.graalvm.util.EconomicMap;
+import org.graalvm.collections.EconomicMap;
 
 /**
  * Registry for allocating a globally unique integer id to each {@link AbstractKey}.
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/MemUseTrackerKeyImpl.java	Fri Feb 16 12:24:38 2018 -0800
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/MemUseTrackerKeyImpl.java	Fri Feb 16 13:49:07 2018 -0800
@@ -24,7 +24,7 @@
 
 import static org.graalvm.compiler.debug.DebugCloseable.VOID_CLOSEABLE;
 
-import org.graalvm.util.Pair;
+import org.graalvm.collections.Pair;
 
 class MemUseTrackerKeyImpl extends AccumulatedKey implements MemUseTrackerKey {
 
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/MetricKey.java	Fri Feb 16 12:24:38 2018 -0800
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/MetricKey.java	Fri Feb 16 13:49:07 2018 -0800
@@ -24,7 +24,7 @@
 
 import java.util.Comparator;
 
-import org.graalvm.util.Pair;
+import org.graalvm.collections.Pair;
 
 /**
  * A key for a metric.
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/TimerKeyImpl.java	Fri Feb 16 12:24:38 2018 -0800
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.debug/src/org/graalvm/compiler/debug/TimerKeyImpl.java	Fri Feb 16 13:49:07 2018 -0800
@@ -26,7 +26,7 @@
 
 import java.util.concurrent.TimeUnit;
 
-import org.graalvm.util.Pair;
+import org.graalvm.collections.Pair;
 
 final class TimerKeyImpl extends AccumulatedKey implements TimerKey {
     static class FlatTimer extends AbstractKey implements TimerKey {
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/CachedGraph.java	Fri Feb 16 12:24:38 2018 -0800
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/CachedGraph.java	Fri Feb 16 13:49:07 2018 -0800
@@ -24,7 +24,7 @@
 
 import java.util.function.Consumer;
 
-import org.graalvm.util.UnmodifiableEconomicMap;
+import org.graalvm.collections.UnmodifiableEconomicMap;
 
 /**
  * This class is a container of a graph that needs to be readonly and optionally a lazily created
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/Graph.java	Fri Feb 16 12:24:38 2018 -0800
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/Graph.java	Fri Feb 16 13:49:07 2018 -0800
@@ -30,6 +30,9 @@
 import java.util.Iterator;
 import java.util.function.Consumer;
 
+import org.graalvm.collections.EconomicMap;
+import org.graalvm.collections.Equivalence;
+import org.graalvm.collections.UnmodifiableEconomicMap;
 import org.graalvm.compiler.debug.CounterKey;
 import org.graalvm.compiler.debug.DebugCloseable;
 import org.graalvm.compiler.debug.DebugContext;
@@ -41,9 +44,6 @@
 import org.graalvm.compiler.options.OptionKey;
 import org.graalvm.compiler.options.OptionType;
 import org.graalvm.compiler.options.OptionValues;
-import org.graalvm.util.EconomicMap;
-import org.graalvm.util.Equivalence;
-import org.graalvm.util.UnmodifiableEconomicMap;
 
 /**
  * This class is a graph container, it contains the set of nodes that belong to this graph.
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/NodeBitMap.java	Fri Feb 16 12:24:38 2018 -0800
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/NodeBitMap.java	Fri Feb 16 13:49:07 2018 -0800
@@ -160,6 +160,12 @@
         }
     }
 
+    public void invert() {
+        for (int i = 0; i < bits.length; i++) {
+            bits[i] = ~bits[i];
+        }
+    }
+
     public void grow() {
         nodeCount = Math.max(nodeCount, graph().nodeIdCount());
         int newLength = sizeForNodeCount(nodeCount);
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/NodeClass.java	Fri Feb 16 12:24:38 2018 -0800
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/NodeClass.java	Fri Feb 16 13:49:07 2018 -0800
@@ -42,6 +42,8 @@
 import java.util.Objects;
 import java.util.concurrent.atomic.AtomicInteger;
 
+import org.graalvm.collections.EconomicMap;
+import org.graalvm.collections.Equivalence;
 import org.graalvm.compiler.core.common.FieldIntrospection;
 import org.graalvm.compiler.core.common.Fields;
 import org.graalvm.compiler.core.common.FieldsScanner;
@@ -65,8 +67,6 @@
 import org.graalvm.compiler.nodeinfo.NodeInfo;
 import org.graalvm.compiler.nodeinfo.NodeSize;
 import org.graalvm.compiler.nodeinfo.Verbosity;
-import org.graalvm.util.EconomicMap;
-import org.graalvm.util.Equivalence;
 
 /**
  * Metadata for every {@link Node} type. The metadata includes:
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/NodeMap.java	Fri Feb 16 12:24:38 2018 -0800
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/NodeMap.java	Fri Feb 16 13:49:07 2018 -0800
@@ -26,8 +26,8 @@
 import java.util.Iterator;
 import java.util.function.BiFunction;
 
-import org.graalvm.util.EconomicMap;
-import org.graalvm.util.MapCursor;
+import org.graalvm.collections.EconomicMap;
+import org.graalvm.collections.MapCursor;
 
 public class NodeMap<T> extends NodeIdAccessor implements EconomicMap<Node, T> {
 
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/NodeStack.java	Fri Feb 16 12:24:38 2018 -0800
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.graph/src/org/graalvm/compiler/graph/NodeStack.java	Fri Feb 16 13:49:07 2018 -0800
@@ -74,6 +74,10 @@
         return tos == 0;
     }
 
+    public void clear() {
+        tos = 0;
+    }
+
     @Override
     public String toString() {
         if (tos == 0) {
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.aarch64/src/org/graalvm/compiler/hotspot/aarch64/AArch64HotSpotBackend.java	Fri Feb 16 12:24:38 2018 -0800
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.aarch64/src/org/graalvm/compiler/hotspot/aarch64/AArch64HotSpotBackend.java	Fri Feb 16 13:49:07 2018 -0800
@@ -22,7 +22,6 @@
  */
 package org.graalvm.compiler.hotspot.aarch64;
 
-import static org.graalvm.compiler.core.common.GraalOptions.ZapStackOnMethodEntry;
 import static java.lang.reflect.Modifier.isStatic;
 import static jdk.vm.ci.aarch64.AArch64.lr;
 import static jdk.vm.ci.aarch64.AArch64.r10;
@@ -30,7 +29,9 @@
 import static jdk.vm.ci.aarch64.AArch64.zr;
 import static jdk.vm.ci.code.ValueUtil.asRegister;
 import static jdk.vm.ci.hotspot.aarch64.AArch64HotSpotRegisterConfig.fp;
+import static org.graalvm.compiler.core.common.GraalOptions.ZapStackOnMethodEntry;
 
+import org.graalvm.collections.EconomicSet;
 import org.graalvm.compiler.asm.Assembler;
 import org.graalvm.compiler.asm.Label;
 import org.graalvm.compiler.asm.aarch64.AArch64Address;
@@ -42,11 +43,11 @@
 import org.graalvm.compiler.core.common.CompilationIdentifier;
 import org.graalvm.compiler.core.common.alloc.RegisterAllocationConfig;
 import org.graalvm.compiler.core.common.spi.ForeignCallLinkage;
+import org.graalvm.compiler.hotspot.GraalHotSpotVMConfig;
 import org.graalvm.compiler.hotspot.HotSpotDataBuilder;
 import org.graalvm.compiler.hotspot.HotSpotGraalRuntimeProvider;
 import org.graalvm.compiler.hotspot.HotSpotHostBackend;
 import org.graalvm.compiler.hotspot.HotSpotLIRGenerationResult;
-import org.graalvm.compiler.hotspot.GraalHotSpotVMConfig;
 import org.graalvm.compiler.hotspot.meta.HotSpotForeignCallsProvider;
 import org.graalvm.compiler.hotspot.meta.HotSpotProviders;
 import org.graalvm.compiler.hotspot.stubs.Stub;
@@ -64,7 +65,6 @@
 import org.graalvm.compiler.lir.gen.LIRGeneratorTool;
 import org.graalvm.compiler.nodes.StructuredGraph;
 import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool;
-import org.graalvm.util.EconomicSet;
 
 import jdk.vm.ci.code.CallingConvention;
 import jdk.vm.ci.code.Register;
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.aarch64/src/org/graalvm/compiler/hotspot/aarch64/AArch64HotSpotBackendFactory.java	Fri Feb 16 12:24:38 2018 -0800
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.aarch64/src/org/graalvm/compiler/hotspot/aarch64/AArch64HotSpotBackendFactory.java	Fri Feb 16 13:49:07 2018 -0800
@@ -49,6 +49,7 @@
 import org.graalvm.compiler.hotspot.meta.HotSpotSuitesProvider;
 import org.graalvm.compiler.hotspot.word.HotSpotWordTypes;
 import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration.Plugins;
+import org.graalvm.compiler.nodes.spi.LoweringProvider;
 import org.graalvm.compiler.options.OptionValues;
 import org.graalvm.compiler.phases.tiers.CompilerConfiguration;
 import org.graalvm.compiler.phases.util.Providers;
@@ -136,7 +137,7 @@
                 replacements = createReplacements(graalRuntime.getOptions(), p, snippetReflection, bytecodeProvider);
             }
             try (InitTimer rt = timer("create GraphBuilderPhase plugins")) {
-                plugins = createGraphBuilderPlugins(compilerConfiguration, config, constantReflection, foreignCalls, metaAccess, snippetReflection, replacements, wordTypes, stampProvider);
+                plugins = createGraphBuilderPlugins(compilerConfiguration, config, constantReflection, foreignCalls, lowerer, metaAccess, snippetReflection, replacements, wordTypes, stampProvider);
                 replacements.setGraphBuilderPlugins(plugins);
             }
             try (InitTimer rt = timer("create Suites provider")) {
@@ -152,9 +153,10 @@
     }
 
     protected Plugins createGraphBuilderPlugins(CompilerConfiguration compilerConfiguration, GraalHotSpotVMConfig config, HotSpotConstantReflectionProvider constantReflection,
-                    HotSpotHostForeignCallsProvider foreignCalls, HotSpotMetaAccessProvider metaAccess, HotSpotSnippetReflectionProvider snippetReflection, HotSpotReplacementsImpl replacements,
-                    HotSpotWordTypes wordTypes, HotSpotStampProvider stampProvider) {
-        Plugins plugins = HotSpotGraphBuilderPlugins.create(compilerConfiguration, config, wordTypes, metaAccess, constantReflection, snippetReflection, foreignCalls, stampProvider, replacements);
+                    HotSpotHostForeignCallsProvider foreignCalls, LoweringProvider lowerer, HotSpotMetaAccessProvider metaAccess, HotSpotSnippetReflectionProvider snippetReflection,
+                    HotSpotReplacementsImpl replacements, HotSpotWordTypes wordTypes, HotSpotStampProvider stampProvider) {
+        Plugins plugins = HotSpotGraphBuilderPlugins.create(compilerConfiguration, config, wordTypes, metaAccess, constantReflection, snippetReflection, foreignCalls, lowerer, stampProvider,
+                        replacements);
         AArch64GraphBuilderPlugins.register(plugins, replacements.getDefaultReplacementBytecodeProvider());
         return plugins;
     }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64.test/src/org/graalvm/compiler/hotspot/amd64/test/ArrayAccessInLoopToAddressTest.java	Fri Feb 16 13:49:07 2018 -0800
@@ -0,0 +1,64 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.hotspot.amd64.test;
+
+import jdk.vm.ci.hotspot.HotSpotSpeculationLog;
+import jdk.vm.ci.meta.SpeculationLog;
+
+import org.graalvm.compiler.core.test.GraalCompilerTest;
+import org.junit.Test;
+
+public class ArrayAccessInLoopToAddressTest extends GraalCompilerTest {
+
+    public static int positiveInductionVariable(short[] array) {
+        int sum = 0;
+        for (int i = 0; i < array.length - 1; i++) {
+            sum += array[i + 1];
+        }
+        return sum;
+    }
+
+    @Test
+    public void testPositiveInductionVariable() {
+        test("positiveInductionVariable", new short[]{1, 3, 7, 9});
+    }
+
+    public static int negativeInductionVariable(short[] array) {
+        int sum = 0;
+        for (int i = -array.length; i < array.length - 4; i++) {
+            sum += array[i + 4];
+        }
+        return sum;
+    }
+
+    @Test
+    public void testNegativeInductionVariable() {
+        test("negativeInductionVariable", new short[]{1, 3, 7, 9});
+    }
+
+    @Override
+    protected SpeculationLog getSpeculationLog() {
+        return new HotSpotSpeculationLog();
+    }
+
+}
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotAddressLowering.java	Fri Feb 16 12:24:38 2018 -0800
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotAddressLowering.java	Fri Feb 16 13:49:07 2018 -0800
@@ -24,64 +24,50 @@
 package org.graalvm.compiler.hotspot.amd64;
 
 import static org.graalvm.compiler.core.common.GraalOptions.GeneratePIC;
-import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_0;
-import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_0;
 
+import org.graalvm.collections.EconomicMap;
 import org.graalvm.compiler.asm.amd64.AMD64Address.Scale;
-import org.graalvm.compiler.core.amd64.AMD64AddressLowering;
 import org.graalvm.compiler.core.amd64.AMD64AddressNode;
+import org.graalvm.compiler.core.amd64.AMD64CompressAddressLowering;
 import org.graalvm.compiler.core.common.CompressEncoding;
-import org.graalvm.compiler.core.common.LIRKind;
+import org.graalvm.compiler.core.common.type.IntegerStamp;
 import org.graalvm.compiler.core.common.type.ObjectStamp;
-import org.graalvm.compiler.core.common.type.StampFactory;
-import org.graalvm.compiler.debug.CounterKey;
-import org.graalvm.compiler.debug.DebugContext;
-import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.graph.Node;
 import org.graalvm.compiler.hotspot.GraalHotSpotVMConfig;
 import org.graalvm.compiler.hotspot.nodes.GraalHotSpotVMConfigNode;
 import org.graalvm.compiler.hotspot.nodes.type.KlassPointerStamp;
-import org.graalvm.compiler.nodeinfo.NodeInfo;
+import org.graalvm.compiler.loop.BasicInductionVariable;
+import org.graalvm.compiler.loop.CountedLoopInfo;
+import org.graalvm.compiler.loop.DerivedInductionVariable;
+import org.graalvm.compiler.loop.InductionVariable;
+import org.graalvm.compiler.loop.LoopEx;
+import org.graalvm.compiler.loop.LoopsData;
 import org.graalvm.compiler.nodes.CompressionNode;
-import org.graalvm.compiler.nodes.CompressionNode.CompressionOp;
+import org.graalvm.compiler.nodes.ConstantNode;
 import org.graalvm.compiler.nodes.NodeView;
+import org.graalvm.compiler.nodes.PhiNode;
 import org.graalvm.compiler.nodes.StructuredGraph;
 import org.graalvm.compiler.nodes.ValueNode;
-import org.graalvm.compiler.nodes.calc.FloatingNode;
-import org.graalvm.compiler.nodes.spi.LIRLowerable;
-import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool;
+import org.graalvm.compiler.nodes.calc.AddNode;
+import org.graalvm.compiler.nodes.calc.SignExtendNode;
+import org.graalvm.compiler.nodes.calc.ZeroExtendNode;
+import org.graalvm.compiler.nodes.memory.address.AddressNode;
+import org.graalvm.compiler.nodes.memory.address.OffsetAddressNode;
 import org.graalvm.compiler.options.OptionValues;
 
 import jdk.vm.ci.code.Register;
 import jdk.vm.ci.meta.JavaKind;
 
-public class AMD64HotSpotAddressLowering extends AMD64AddressLowering {
+public class AMD64HotSpotAddressLowering extends AMD64CompressAddressLowering {
 
-    private static final CounterKey counterFoldedUncompressDuringAddressLowering = DebugContext.counter("FoldedUncompressDuringAddressLowering");
+    private static final int ADDRESS_BITS = 64;
+    private static final int INT_BITS = 32;
 
     private final long heapBase;
     private final Register heapBaseRegister;
     private final GraalHotSpotVMConfig config;
     private final boolean generatePIC;
 
-    @NodeInfo(cycles = CYCLES_0, size = SIZE_0)
-    public static class HeapBaseNode extends FloatingNode implements LIRLowerable {
-
-        public static final NodeClass<HeapBaseNode> TYPE = NodeClass.create(HeapBaseNode.class);
-
-        private final Register heapBaseRegister;
-
-        public HeapBaseNode(Register heapBaseRegister) {
-            super(TYPE, StampFactory.pointer());
-            this.heapBaseRegister = heapBaseRegister;
-        }
-
-        @Override
-        public void generate(NodeLIRBuilderTool generator) {
-            LIRKind kind = generator.getLIRGeneratorTool().getLIRKind(stamp(NodeView.DEFAULT));
-            generator.setResult(this, heapBaseRegister.asValue(kind));
-        }
-    }
-
     public AMD64HotSpotAddressLowering(GraalHotSpotVMConfig config, Register heapBaseRegister, OptionValues options) {
         this.heapBase = config.getOopEncoding().getBase();
         this.config = config;
@@ -94,35 +80,7 @@
     }
 
     @Override
-    protected boolean improve(StructuredGraph graph, DebugContext debug, AMD64AddressNode addr, boolean isBaseNegated, boolean isIndexNegated) {
-        if (super.improve(graph, debug, addr, isBaseNegated, isIndexNegated)) {
-            return true;
-        }
-
-        if (addr.getScale() == Scale.Times1) {
-            if (addr.getIndex() instanceof CompressionNode) {
-                if (improveUncompression(addr, (CompressionNode) addr.getIndex(), addr.getBase(), isBaseNegated, isIndexNegated)) {
-                    counterFoldedUncompressDuringAddressLowering.increment(debug);
-                    return true;
-                }
-            }
-
-            if (addr.getBase() instanceof CompressionNode) {
-                if (improveUncompression(addr, (CompressionNode) addr.getBase(), addr.getIndex(), isBaseNegated, isIndexNegated)) {
-                    counterFoldedUncompressDuringAddressLowering.increment(debug);
-                    return true;
-                }
-            }
-        }
-
-        return false;
-    }
-
-    private boolean improveUncompression(AMD64AddressNode addr, CompressionNode compression, ValueNode other, boolean isBaseNegated, boolean isIndexNegated) {
-        if (isBaseNegated || isIndexNegated || compression.getOp() != CompressionOp.Uncompress) {
-            return false;
-        }
-
+    protected final boolean improveUncompression(AMD64AddressNode addr, CompressionNode compression, ValueNode other) {
         CompressEncoding encoding = compression.getEncoding();
         Scale scale = Scale.fromShift(encoding.getShift());
         if (scale == null) {
@@ -147,7 +105,7 @@
                     return false;
                 }
             } else {
-                if (updateDisplacement(addr, encoding.getBase(), isBaseNegated)) {
+                if (updateDisplacement(addr, encoding.getBase(), false)) {
                     addr.setBase(other);
                 } else {
                     return false;
@@ -161,4 +119,117 @@
         addr.setIndex(compression.getValue());
         return true;
     }
+
+    @Override
+    public void preProcess(StructuredGraph graph) {
+        if (graph.hasLoops()) {
+            LoopsData loopsData = new LoopsData(graph);
+            loopsData.detectedCountedLoops();
+            for (LoopEx loop : loopsData.countedLoops()) {
+                for (OffsetAddressNode offsetAdressNode : loop.whole().nodes().filter(OffsetAddressNode.class)) {
+                    tryOptimize(offsetAdressNode, loop);
+                }
+            }
+        }
+    }
+
+    @Override
+    public void postProcess(AddressNode lowered) {
+        // Allow implicit zero extend for always positive input. This
+        // assumes that the upper bits of the operand is zero out by
+        // the backend.
+        AMD64AddressNode address = (AMD64AddressNode) lowered;
+        address.setBase(tryImplicitZeroExtend(address.getBase()));
+        address.setIndex(tryImplicitZeroExtend(address.getIndex()));
+    }
+
+    private static void tryOptimize(OffsetAddressNode offsetAddress, LoopEx loop) {
+        EconomicMap<Node, InductionVariable> ivs = loop.getInductionVariables();
+        InductionVariable currentIV = ivs.get(offsetAddress.getOffset());
+        while (currentIV != null) {
+            if (!(currentIV instanceof DerivedInductionVariable)) {
+                break;
+            }
+            ValueNode currentValue = currentIV.valueNode();
+            if (currentValue.isDeleted()) {
+                break;
+            }
+
+            if (currentValue instanceof ZeroExtendNode) {
+                ZeroExtendNode zeroExtendNode = (ZeroExtendNode) currentValue;
+                if (applicableToImplicitZeroExtend(zeroExtendNode)) {
+                    ValueNode input = zeroExtendNode.getValue();
+                    if (input instanceof AddNode) {
+                        AddNode add = (AddNode) input;
+                        if (add.getX().isConstant()) {
+                            optimizeAdd(zeroExtendNode, (ConstantNode) add.getX(), add.getY(), loop);
+                        } else if (add.getY().isConstant()) {
+                            optimizeAdd(zeroExtendNode, (ConstantNode) add.getY(), add.getX(), loop);
+                        }
+                    }
+                }
+            }
+
+            currentIV = ((DerivedInductionVariable) currentIV).getBase();
+        }
+    }
+
+    /**
+     * Given that Add(a, cst) is always positive, performs the following: ZeroExtend(Add(a, cst)) ->
+     * Add(SignExtend(a), SignExtend(cst)).
+     */
+    private static void optimizeAdd(ZeroExtendNode zeroExtendNode, ConstantNode constant, ValueNode other, LoopEx loop) {
+        StructuredGraph graph = zeroExtendNode.graph();
+        AddNode addNode = graph.unique(new AddNode(signExtend(other, loop), ConstantNode.forLong(constant.asJavaConstant().asInt(), graph)));
+        zeroExtendNode.replaceAtUsages(addNode);
+    }
+
+    /**
+     * Create a sign extend for {@code input}, or zero extend if {@code input} can be proven
+     * positive.
+     */
+    private static ValueNode signExtend(ValueNode input, LoopEx loop) {
+        StructuredGraph graph = input.graph();
+        if (input instanceof PhiNode) {
+            EconomicMap<Node, InductionVariable> ivs = loop.getInductionVariables();
+            InductionVariable inductionVariable = ivs.get(input);
+            if (inductionVariable != null && inductionVariable instanceof BasicInductionVariable) {
+                CountedLoopInfo countedLoopInfo = loop.counted();
+                IntegerStamp initStamp = (IntegerStamp) inductionVariable.initNode().stamp(NodeView.DEFAULT);
+                if (initStamp.isPositive()) {
+                    if (inductionVariable.isConstantExtremum()) {
+                        long init = inductionVariable.constantInit();
+                        long stride = inductionVariable.constantStride();
+                        long extremum = inductionVariable.constantExtremum();
+
+                        if (init >= 0 && extremum >= 0) {
+                            long shortestTrip = (extremum - init) / stride + 1;
+                            if (shortestTrip == countedLoopInfo.constantMaxTripCount()) {
+                                return graph.unique(new ZeroExtendNode(input, INT_BITS, ADDRESS_BITS, true));
+                            }
+                        }
+                    }
+                    if (countedLoopInfo.getCounter() == inductionVariable && inductionVariable.direction() == InductionVariable.Direction.Up && countedLoopInfo.getOverFlowGuard() != null) {
+                        return graph.unique(new ZeroExtendNode(input, INT_BITS, ADDRESS_BITS, true));
+                    }
+                }
+            }
+        }
+        return input.graph().maybeAddOrUnique(SignExtendNode.create(input, ADDRESS_BITS, NodeView.DEFAULT));
+    }
+
+    private static boolean applicableToImplicitZeroExtend(ZeroExtendNode zeroExtendNode) {
+        return zeroExtendNode.isInputAlwaysPositive() && zeroExtendNode.getInputBits() == INT_BITS && zeroExtendNode.getResultBits() == ADDRESS_BITS;
+    }
+
+    private static ValueNode tryImplicitZeroExtend(ValueNode input) {
+        if (input instanceof ZeroExtendNode) {
+            ZeroExtendNode zeroExtendNode = (ZeroExtendNode) input;
+            if (applicableToImplicitZeroExtend(zeroExtendNode)) {
+                return zeroExtendNode.getValue();
+            }
+        }
+        return input;
+    }
+
 }
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotBackend.java	Fri Feb 16 12:24:38 2018 -0800
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotBackend.java	Fri Feb 16 13:49:07 2018 -0800
@@ -30,6 +30,7 @@
 import static org.graalvm.compiler.core.common.GraalOptions.GeneratePIC;
 import static org.graalvm.compiler.core.common.GraalOptions.ZapStackOnMethodEntry;
 
+import org.graalvm.collections.EconomicSet;
 import org.graalvm.compiler.asm.Assembler;
 import org.graalvm.compiler.asm.Label;
 import org.graalvm.compiler.asm.amd64.AMD64Address;
@@ -66,7 +67,6 @@
 import org.graalvm.compiler.nodes.StructuredGraph;
 import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool;
 import org.graalvm.compiler.options.OptionValues;
-import org.graalvm.util.EconomicSet;
 
 import jdk.vm.ci.amd64.AMD64;
 import jdk.vm.ci.amd64.AMD64Kind;
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotBackendFactory.java	Fri Feb 16 12:24:38 2018 -0800
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotBackendFactory.java	Fri Feb 16 13:49:07 2018 -0800
@@ -49,6 +49,7 @@
 import org.graalvm.compiler.hotspot.meta.HotSpotSuitesProvider;
 import org.graalvm.compiler.hotspot.word.HotSpotWordTypes;
 import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderConfiguration.Plugins;
+import org.graalvm.compiler.nodes.spi.LoweringProvider;
 import org.graalvm.compiler.nodes.spi.Replacements;
 import org.graalvm.compiler.options.OptionValues;
 import org.graalvm.compiler.phases.tiers.CompilerConfiguration;
@@ -137,7 +138,7 @@
                 replacements = createReplacements(options, p, snippetReflection, bytecodeProvider);
             }
             try (InitTimer rt = timer("create GraphBuilderPhase plugins")) {
-                plugins = createGraphBuilderPlugins(compilerConfiguration, config, options, target, constantReflection, foreignCalls, metaAccess, snippetReflection, replacements, wordTypes,
+                plugins = createGraphBuilderPlugins(compilerConfiguration, config, options, target, constantReflection, foreignCalls, lowerer, metaAccess, snippetReflection, replacements, wordTypes,
                                 stampProvider);
                 replacements.setGraphBuilderPlugins(plugins);
             }
@@ -154,9 +155,10 @@
     }
 
     protected Plugins createGraphBuilderPlugins(CompilerConfiguration compilerConfiguration, GraalHotSpotVMConfig config, OptionValues options, TargetDescription target,
-                    HotSpotConstantReflectionProvider constantReflection, HotSpotHostForeignCallsProvider foreignCalls, HotSpotMetaAccessProvider metaAccess,
+                    HotSpotConstantReflectionProvider constantReflection, HotSpotHostForeignCallsProvider foreignCalls, LoweringProvider lowerer, HotSpotMetaAccessProvider metaAccess,
                     HotSpotSnippetReflectionProvider snippetReflection, HotSpotReplacementsImpl replacements, HotSpotWordTypes wordTypes, HotSpotStampProvider stampProvider) {
-        Plugins plugins = HotSpotGraphBuilderPlugins.create(compilerConfiguration, config, wordTypes, metaAccess, constantReflection, snippetReflection, foreignCalls, stampProvider, replacements);
+        Plugins plugins = HotSpotGraphBuilderPlugins.create(compilerConfiguration, config, wordTypes, metaAccess, constantReflection, snippetReflection, foreignCalls, lowerer, stampProvider,
+                        replacements);
         AMD64GraphBuilderPlugins.register(plugins, replacements.getDefaultReplacementBytecodeProvider(), (AMD64) target.arch, GraalArithmeticStubs.getValue(options));
         return plugins;
     }
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotLIRGenerator.java	Fri Feb 16 12:24:38 2018 -0800
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotLIRGenerator.java	Fri Feb 16 13:49:07 2018 -0800
@@ -572,7 +572,7 @@
         if (inputKind.isReference(0)) {
             // oop
             Variable result = newVariable(lirKindTool.getNarrowOopKind());
-            append(new AMD64Move.CompressPointer(result, asAllocatable(pointer), getProviders().getRegisters().getHeapBaseRegister().asValue(), encoding, nonNull, getLIRKindTool()));
+            append(new AMD64Move.CompressPointerOp(result, asAllocatable(pointer), getProviders().getRegisters().getHeapBaseRegister().asValue(), encoding, nonNull, getLIRKindTool()));
             return result;
         } else {
             // metaspace pointer
@@ -589,7 +589,7 @@
                     base = emitLoadConstant(lirKindTool.getWordKind(), JavaConstant.forLong(encoding.getBase()));
                 }
             }
-            append(new AMD64Move.CompressPointer(result, asAllocatable(pointer), base, encoding, nonNull, getLIRKindTool()));
+            append(new AMD64Move.CompressPointerOp(result, asAllocatable(pointer), base, encoding, nonNull, getLIRKindTool()));
             return result;
         }
     }
@@ -602,7 +602,7 @@
         if (inputKind.isReference(0)) {
             // oop
             Variable result = newVariable(lirKindTool.getObjectKind());
-            append(new AMD64Move.UncompressPointer(result, asAllocatable(pointer), getProviders().getRegisters().getHeapBaseRegister().asValue(), encoding, nonNull, lirKindTool));
+            append(new AMD64Move.UncompressPointerOp(result, asAllocatable(pointer), getProviders().getRegisters().getHeapBaseRegister().asValue(), encoding, nonNull, lirKindTool));
             return result;
         } else {
             // metaspace pointer
@@ -620,7 +620,7 @@
                     base = emitLoadConstant(uncompressedKind, JavaConstant.forLong(encoding.getBase()));
                 }
             }
-            append(new AMD64Move.UncompressPointer(result, asAllocatable(pointer), base, encoding, nonNull, lirKindTool));
+            append(new AMD64Move.UncompressPointerOp(result, asAllocatable(pointer), base, encoding, nonNull, lirKindTool));
             return result;
         }
     }
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotLoweringProvider.java	Fri Feb 16 12:24:38 2018 -0800
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotSpotLoweringProvider.java	Fri Feb 16 13:49:07 2018 -0800
@@ -67,7 +67,8 @@
     public void initialize(OptionValues options, Iterable<DebugHandlersFactory> factories, HotSpotProviders providers, GraalHotSpotVMConfig config) {
         convertSnippets = new AMD64ConvertSnippets.Templates(options, factories, providers, providers.getSnippetReflection(), providers.getCodeCache().getTarget());
         profileSnippets = ProfileNode.Options.ProbabilisticProfiling.getValue(options)
-                        ? new ProbabilisticProfileSnippets.Templates(options, factories, providers, providers.getCodeCache().getTarget()) : null;
+                        ? new ProbabilisticProfileSnippets.Templates(options, factories, providers, providers.getCodeCache().getTarget())
+                        : null;
         super.initialize(options, factories, providers, config);
     }
 
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotspotDirectVirtualCallOp.java	Fri Feb 16 12:24:38 2018 -0800
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64HotspotDirectVirtualCallOp.java	Fri Feb 16 13:49:07 2018 -0800
@@ -60,6 +60,7 @@
         crb.recordMark(invokeKind == InvokeKind.Virtual ? config.MARKID_INVOKEVIRTUAL : config.MARKID_INVOKEINTERFACE);
         // This must be emitted exactly like this to ensure it's patchable
         masm.movq(AMD64.rax, config.nonOopBits);
-        super.emitCode(crb, masm);
+        int offset = super.emitCall(crb, masm);
+        crb.recordInvokeVirtualOrInterfaceCallOp(offset, getPosition());
     }
 }
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64IndirectCallOp.java	Fri Feb 16 12:24:38 2018 -0800
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.amd64/src/org/graalvm/compiler/hotspot/amd64/AMD64IndirectCallOp.java	Fri Feb 16 13:49:07 2018 -0800
@@ -70,7 +70,8 @@
         crb.recordMark(config.MARKID_INLINE_INVOKE);
         Register callReg = asRegister(targetAddress);
         assert !callReg.equals(METHOD);
-        AMD64Call.indirectCall(crb, masm, callReg, callTarget, state);
+        int pcOffset = AMD64Call.indirectCall(crb, masm, callReg, callTarget, state);
+        crb.recordInlineInvokeCallOp(pcOffset, getPosition());
     }
 
     @Override
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sparc.test/src/org/graalvm/compiler/core/sparc/test/SPARCAllocatorTest.java	Fri Feb 16 13:49:07 2018 -0800
@@ -0,0 +1,75 @@
+/*
+ * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.core.sparc.test;
+
+import static org.graalvm.compiler.core.common.GraalOptions.RegisterPressure;
+import static org.graalvm.compiler.core.common.GraalOptions.TraceRA;
+import static org.junit.Assume.assumeTrue;
+
+import org.graalvm.compiler.core.test.backend.AllocatorTest;
+import org.graalvm.compiler.hotspot.GraalHotSpotVMConfig;
+import org.graalvm.compiler.hotspot.HotSpotBackend;
+import org.junit.Before;
+import org.junit.Test;
+
+import jdk.vm.ci.sparc.SPARC;
+
+public class SPARCAllocatorTest extends AllocatorTest {
+
+    private final GraalHotSpotVMConfig config = ((HotSpotBackend) getBackend()).getRuntime().getVMConfig();
+
+    @Before
+    public void checkSPARC() {
+        assumeTrue("skipping SPARC specific test", getTarget().arch instanceof SPARC);
+        assumeTrue("RegisterPressure is set -> skip", RegisterPressure.getValue(getInitialOptions()) == null);
+        assumeTrue("TraceRA is set -> skip", !TraceRA.getValue(getInitialOptions()));
+    }
+
+    @Test
+    public void test1() {
+        testAllocation("test1snippet", config.threadLocalHandshakes ? 1 : 2, 0, 0);
+    }
+
+    public static long test1snippet(long x) {
+        return x + 41;
+    }
+
+    @Test
+    public void test2() {
+        testAllocation("test2snippet", config.threadLocalHandshakes ? 1 : 2, 0, 0);
+    }
+
+    public static long test2snippet(long x) {
+        return x * 41;
+    }
+
+    @Test
+    public void test3() {
+        testAllocation("test3snippet", config.threadLocalHandshakes ? 3 : 4, 0, 0);
+    }
+
+    public static long test3snippet(long x) {
+        return x / 41 + x % 41;
+    }
+
+}
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sparc/src/org/graalvm/compiler/hotspot/sparc/SPARCHotSpotBackend.java	Fri Feb 16 12:24:38 2018 -0800
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sparc/src/org/graalvm/compiler/hotspot/sparc/SPARCHotSpotBackend.java	Fri Feb 16 13:49:07 2018 -0800
@@ -46,6 +46,9 @@
 import java.util.Set;
 import java.util.concurrent.ConcurrentHashMap;
 
+import org.graalvm.collections.EconomicMap;
+import org.graalvm.collections.EconomicSet;
+import org.graalvm.collections.Equivalence;
 import org.graalvm.compiler.asm.Assembler;
 import org.graalvm.compiler.asm.Label;
 import org.graalvm.compiler.asm.sparc.SPARCAddress;
@@ -92,9 +95,6 @@
 import org.graalvm.compiler.nodes.StructuredGraph;
 import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool;
 import org.graalvm.compiler.options.OptionValues;
-import org.graalvm.util.EconomicMap;
-import org.graalvm.util.EconomicSet;
-import org.graalvm.util.Equivalence;
 
 import jdk.vm.ci.code.CallingConvention;
 import jdk.vm.ci.code.Register;
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sparc/src/org/graalvm/compiler/hotspot/sparc/SPARCHotSpotBackendFactory.java	Fri Feb 16 12:24:38 2018 -0800
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.sparc/src/org/graalvm/compiler/hotspot/sparc/SPARCHotSpotBackendFactory.java	Fri Feb 16 13:49:07 2018 -0800
@@ -101,7 +101,7 @@
         HotSpotSnippetReflectionProvider snippetReflection = new HotSpotSnippetReflectionProvider(runtime, constantReflection, wordTypes);
         BytecodeProvider bytecodeProvider = new ClassfileBytecodeProvider(metaAccess, snippetReflection);
         HotSpotReplacementsImpl replacements = new HotSpotReplacementsImpl(runtime.getOptions(), p, snippetReflection, bytecodeProvider, target);
-        Plugins plugins = createGraphBuilderPlugins(compilerConfiguration, config, metaAccess, constantReflection, foreignCalls, stampProvider, snippetReflection, replacements, wordTypes);
+        Plugins plugins = createGraphBuilderPlugins(compilerConfiguration, config, metaAccess, constantReflection, foreignCalls, lowerer, stampProvider, snippetReflection, replacements, wordTypes);
         replacements.setGraphBuilderPlugins(plugins);
         HotSpotSuitesProvider suites = createSuites(config, runtime, compilerConfiguration, plugins, replacements);
         HotSpotProviders providers = new HotSpotProviders(metaAccess, codeCache, constantReflection, constantFieldProvider, foreignCalls, lowerer, replacements, suites, registers,
@@ -112,9 +112,10 @@
     }
 
     protected Plugins createGraphBuilderPlugins(CompilerConfiguration compilerConfiguration, GraalHotSpotVMConfig config, HotSpotMetaAccessProvider metaAccess,
-                    HotSpotConstantReflectionProvider constantReflection, HotSpotForeignCallsProvider foreignCalls, HotSpotStampProvider stampProvider,
+                    HotSpotConstantReflectionProvider constantReflection, HotSpotForeignCallsProvider foreignCalls, LoweringProvider lowerer, HotSpotStampProvider stampProvider,
                     HotSpotSnippetReflectionProvider snippetReflection, HotSpotReplacementsImpl replacements, HotSpotWordTypes wordTypes) {
-        Plugins plugins = HotSpotGraphBuilderPlugins.create(compilerConfiguration, config, wordTypes, metaAccess, constantReflection, snippetReflection, foreignCalls, stampProvider, replacements);
+        Plugins plugins = HotSpotGraphBuilderPlugins.create(compilerConfiguration, config, wordTypes, metaAccess, constantReflection, snippetReflection, foreignCalls, lowerer, stampProvider,
+                        replacements);
         SPARCGraphBuilderPlugins.register(plugins, replacements.getDefaultReplacementBytecodeProvider());
         return plugins;
     }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/ArrayNewInstanceTest.java	Fri Feb 16 13:49:07 2018 -0800
@@ -0,0 +1,107 @@
+/*
+ * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.hotspot.test;
+
+import java.lang.reflect.Array;
+import java.util.ArrayList;
+
+import org.graalvm.compiler.api.directives.GraalDirectives;
+import org.graalvm.compiler.core.test.GraalCompilerTest;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameters;
+
+@RunWith(Parameterized.class)
+public class ArrayNewInstanceTest extends GraalCompilerTest {
+
+    @Parameters(name = "{index}: class {0} length {1}")
+    public static Iterable<Object[]> data() {
+        ArrayList<Object[]> parameters = new ArrayList<>();
+        Class<?>[] classesToTest = new Class<?>[]{
+                        byte.class,
+                        boolean.class,
+                        short.class,
+                        char.class,
+                        int.class,
+                        long.class,
+                        Void.class,
+                        ArrayNewInstanceTest.class
+        };
+        for (Class<?> clazz : classesToTest) {
+            // Negative sizes always deopt
+            parameters.add(new Object[]{clazz, -1, true});
+            parameters.add(new Object[]{clazz, 0, false});
+            parameters.add(new Object[]{clazz, 42, false});
+        }
+        // The void type always throws an exception where graal deopts
+        parameters.add(new Object[]{void.class, -1, true});
+        parameters.add(new Object[]{void.class, 0, true});
+        parameters.add(new Object[]{void.class, 42, true});
+        return parameters;
+    }
+
+    private final Class<?> type;
+    private final int length;
+    private final boolean shouldDeopt;
+    private final DeoptimizationBox box = new DeoptimizationBox();
+
+    public ArrayNewInstanceTest(Class<?> type, int length, boolean shouldDeopt) {
+        super();
+        this.type = type;
+        this.length = length;
+        this.shouldDeopt = shouldDeopt;
+    }
+
+    public static Object newArray(Class<?> klass, int length, DeoptimizationBox box) {
+        Object result = Array.newInstance(klass, length);
+        box.inCompiledCode = GraalDirectives.inCompiledCode();
+        return result;
+    }
+
+    @Test
+    public void testNewArray() {
+        test("newArray", type, length, box);
+        assertTrue(box.inCompiledCode != shouldDeopt);
+    }
+
+    public static Object newArrayInLoop(Class<?> klass, int length, int iterations, DeoptimizationBox box) {
+        Object o = null;
+        for (int i = 0; i < iterations; i++) {
+            o = Array.newInstance(klass, length);
+        }
+        box.inCompiledCode = GraalDirectives.inCompiledCode();
+        return o;
+    }
+
+    @Test
+    public void testNewArrayInLoop() {
+        test("newArrayInLoop", type, length, 2, box);
+        assertTrue(box.inCompiledCode != shouldDeopt);
+    }
+
+    private static class DeoptimizationBox {
+        volatile boolean inCompiledCode = false;
+    }
+
+}
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/CheckGraalIntrinsics.java	Fri Feb 16 12:24:38 2018 -0800
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/CheckGraalIntrinsics.java	Fri Feb 16 13:49:07 2018 -0800
@@ -32,6 +32,8 @@
 import java.util.TreeSet;
 import java.util.stream.Collectors;
 
+import org.graalvm.collections.EconomicMap;
+import org.graalvm.collections.MapCursor;
 import org.graalvm.compiler.api.test.Graal;
 import org.graalvm.compiler.hotspot.GraalHotSpotVMConfig;
 import org.graalvm.compiler.hotspot.HotSpotGraalRuntimeProvider;
@@ -43,8 +45,6 @@
 import org.graalvm.compiler.runtime.RuntimeProvider;
 import org.graalvm.compiler.serviceprovider.JDK9Method;
 import org.graalvm.compiler.test.GraalTest;
-import org.graalvm.util.EconomicMap;
-import org.graalvm.util.MapCursor;
 import org.junit.Test;
 
 import jdk.vm.ci.hotspot.HotSpotVMConfigStore;
@@ -416,6 +416,12 @@
                             "java/lang/StringUTF16.toBytes([CII)[B");
         }
 
+        if (isJDK10OrHigher()) {
+            add(TO_BE_INVESTIGATED,
+                            "java/lang/Math.multiplyHigh(JJ)J",
+                            "jdk/internal/util/ArraysSupport.vectorizedMismatch(Ljava/lang/Object;JLjava/lang/Object;JII)I");
+        }
+
         if (!getHostArchitectureName().equals("amd64")) {
             // Can we implement these on non-AMD64 platforms? C2 seems to.
             add(TO_BE_INVESTIGATED,
@@ -539,6 +545,10 @@
         return JDK9Method.JAVA_SPECIFICATION_VERSION >= 9;
     }
 
+    private static boolean isJDK10OrHigher() {
+        return JDK9Method.JAVA_SPECIFICATION_VERSION >= 10;
+    }
+
     private static String getHostArchitectureName() {
         String arch = System.getProperty("os.arch");
         if (arch.equals("x86_64")) {
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/CompileTheWorld.java	Fri Feb 16 12:24:38 2018 -0800
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/CompileTheWorld.java	Fri Feb 16 13:49:07 2018 -0800
@@ -68,6 +68,8 @@
 import java.util.jar.JarFile;
 import java.util.stream.Collectors;
 
+import org.graalvm.collections.EconomicMap;
+import org.graalvm.collections.UnmodifiableEconomicMap;
 import org.graalvm.compiler.api.replacements.Snippet;
 import org.graalvm.compiler.bytecode.Bytecodes;
 import org.graalvm.compiler.core.CompilerThreadFactory;
@@ -85,8 +87,6 @@
 import org.graalvm.compiler.options.OptionValues;
 import org.graalvm.compiler.options.OptionsParser;
 import org.graalvm.compiler.serviceprovider.JDK9Method;
-import org.graalvm.util.EconomicMap;
-import org.graalvm.util.UnmodifiableEconomicMap;
 
 import jdk.vm.ci.hotspot.HotSpotCodeCacheProvider;
 import jdk.vm.ci.hotspot.HotSpotCompilationRequest;
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/CompileTheWorldTest.java	Fri Feb 16 12:24:38 2018 -0800
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/CompileTheWorldTest.java	Fri Feb 16 13:49:07 2018 -0800
@@ -25,12 +25,12 @@
 import static org.graalvm.compiler.core.GraalCompilerOptions.CompilationBailoutAction;
 import static org.graalvm.compiler.core.GraalCompilerOptions.CompilationFailureAction;
 
+import org.graalvm.collections.EconomicMap;
 import org.graalvm.compiler.core.CompilationWrapper.ExceptionAction;
 import org.graalvm.compiler.core.test.GraalCompilerTest;
 import org.graalvm.compiler.hotspot.HotSpotGraalCompiler;
 import org.graalvm.compiler.options.OptionKey;
 import org.graalvm.compiler.options.OptionValues;
-import org.graalvm.util.EconomicMap;
 import org.junit.Test;
 
 import jdk.vm.ci.hotspot.HotSpotJVMCIRuntime;
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/GraalOSRLockTest.java	Fri Feb 16 12:24:38 2018 -0800
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/GraalOSRLockTest.java	Fri Feb 16 13:49:07 2018 -0800
@@ -32,6 +32,7 @@
 import java.util.HashSet;
 import java.util.List;
 
+import org.graalvm.collections.EconomicMap;
 import org.graalvm.compiler.api.directives.GraalDirectives;
 import org.graalvm.compiler.core.phases.HighTier;
 import org.graalvm.compiler.debug.DebugContext;
@@ -40,13 +41,12 @@
 import org.graalvm.compiler.hotspot.phases.OnStackReplacementPhase;
 import org.graalvm.compiler.options.OptionKey;
 import org.graalvm.compiler.options.OptionValues;
-import org.graalvm.util.EconomicMap;
 import org.junit.Assert;
+import org.junit.Assume;
+import org.junit.BeforeClass;
 import org.junit.Test;
 
 import jdk.vm.ci.meta.ResolvedJavaMethod;
-import org.junit.Assume;
-import org.junit.BeforeClass;
 
 /**
  * Test on-stack-replacement with locks.
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/HotSpotGraalMBeanTest.java	Fri Feb 16 12:24:38 2018 -0800
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/HotSpotGraalMBeanTest.java	Fri Feb 16 13:49:07 2018 -0800
@@ -31,8 +31,8 @@
 
 import java.lang.management.ManagementFactory;
 import java.lang.reflect.Field;
+import java.util.Arrays;
 
-import java.util.Arrays;
 import javax.management.Attribute;
 import javax.management.MBeanAttributeInfo;
 import javax.management.MBeanInfo;
@@ -41,11 +41,11 @@
 import javax.management.ObjectInstance;
 import javax.management.ObjectName;
 
+import org.graalvm.collections.EconomicMap;
 import org.graalvm.compiler.debug.DebugOptions;
 import org.graalvm.compiler.hotspot.HotSpotGraalMBean;
 import org.graalvm.compiler.options.OptionValues;
 import org.graalvm.compiler.test.GraalTest;
-import org.graalvm.util.EconomicMap;
 import org.junit.Assume;
 import org.junit.Test;
 
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/TestIntrinsicCompiles.java	Fri Feb 16 12:24:38 2018 -0800
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/TestIntrinsicCompiles.java	Fri Feb 16 13:49:07 2018 -0800
@@ -23,8 +23,10 @@
 package org.graalvm.compiler.hotspot.test;
 
 import static org.graalvm.compiler.core.common.CompilationIdentifier.INVALID_COMPILATION_ID;
+
 import java.util.List;
 
+import org.graalvm.collections.EconomicMap;
 import org.graalvm.compiler.api.test.Graal;
 import org.graalvm.compiler.core.test.GraalCompilerTest;
 import org.graalvm.compiler.debug.DebugContext;
@@ -36,10 +38,9 @@
 import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugin;
 import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugins;
 import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugins.Binding;
+import org.graalvm.compiler.nodes.graphbuilderconf.MethodSubstitutionPlugin;
 import org.graalvm.compiler.options.OptionValues;
-import org.graalvm.compiler.nodes.graphbuilderconf.MethodSubstitutionPlugin;
 import org.graalvm.compiler.runtime.RuntimeProvider;
-import org.graalvm.util.EconomicMap;
 import org.junit.Test;
 
 import jdk.vm.ci.hotspot.HotSpotVMConfigStore;
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/WriteBarrierVerificationTest.java	Fri Feb 16 12:24:38 2018 -0800
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot.test/src/org/graalvm/compiler/hotspot/test/WriteBarrierVerificationTest.java	Fri Feb 16 13:49:07 2018 -0800
@@ -24,6 +24,7 @@
 
 import java.util.List;
 
+import org.graalvm.collections.EconomicMap;
 import org.graalvm.compiler.debug.DebugCloseable;
 import org.graalvm.compiler.debug.DebugContext;
 import org.graalvm.compiler.debug.DebugContext.Scope;
@@ -58,7 +59,6 @@
 import org.graalvm.compiler.phases.graph.ReentrantNodeIterator.NodeIteratorClosure;
 import org.graalvm.compiler.phases.tiers.HighTierContext;
 import org.graalvm.compiler.phases.tiers.MidTierContext;
-import org.graalvm.util.EconomicMap;
 import org.graalvm.word.LocationIdentity;
 import org.junit.Assert;
 import org.junit.Test;
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/CompilationTask.java	Fri Feb 16 12:24:38 2018 -0800
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/CompilationTask.java	Fri Feb 16 13:49:07 2018 -0800
@@ -29,6 +29,7 @@
 
 import java.util.List;
 
+import org.graalvm.collections.EconomicMap;
 import org.graalvm.compiler.api.replacements.SnippetReflectionProvider;
 import org.graalvm.compiler.code.CompilationResult;
 import org.graalvm.compiler.core.CompilationPrinter;
@@ -45,7 +46,6 @@
 import org.graalvm.compiler.options.OptionKey;
 import org.graalvm.compiler.options.OptionValues;
 import org.graalvm.compiler.printer.GraalDebugHandlersFactory;
-import org.graalvm.util.EconomicMap;
 
 import jdk.vm.ci.code.BailoutException;
 import jdk.vm.ci.code.CodeCacheProvider;
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/CompilerConfigurationFactory.java	Fri Feb 16 12:24:38 2018 -0800
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/CompilerConfigurationFactory.java	Fri Feb 16 13:49:07 2018 -0800
@@ -29,6 +29,7 @@
 import java.util.List;
 import java.util.stream.Collectors;
 
+import org.graalvm.collections.EconomicMap;
 import org.graalvm.compiler.debug.GraalError;
 import org.graalvm.compiler.options.Option;
 import org.graalvm.compiler.options.OptionKey;
@@ -36,7 +37,6 @@
 import org.graalvm.compiler.options.OptionValues;
 import org.graalvm.compiler.phases.tiers.CompilerConfiguration;
 import org.graalvm.compiler.serviceprovider.GraalServices;
-import org.graalvm.util.EconomicMap;
 
 import jdk.vm.ci.code.Architecture;
 import jdk.vm.ci.common.InitTimer;
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotBackend.java	Fri Feb 16 12:24:38 2018 -0800
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotBackend.java	Fri Feb 16 13:49:07 2018 -0800
@@ -64,10 +64,10 @@
 import org.graalvm.compiler.options.OptionValues;
 import org.graalvm.compiler.phases.tiers.SuitesProvider;
 import org.graalvm.compiler.word.Word;
-import org.graalvm.util.EconomicMap;
-import org.graalvm.util.EconomicSet;
-import org.graalvm.util.Equivalence;
-import org.graalvm.util.MapCursor;
+import org.graalvm.collections.EconomicMap;
+import org.graalvm.collections.EconomicSet;
+import org.graalvm.collections.Equivalence;
+import org.graalvm.collections.MapCursor;
 import org.graalvm.word.Pointer;
 
 import jdk.vm.ci.code.CompilationRequest;
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotCompiledCodeBuilder.java	Fri Feb 16 12:24:38 2018 -0800
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotCompiledCodeBuilder.java	Fri Feb 16 13:49:07 2018 -0800
@@ -98,8 +98,8 @@
 
         ByteBuffer buffer = ByteBuffer.wrap(dataSection).order(ByteOrder.nativeOrder());
         Builder<DataPatch> patchBuilder = Stream.builder();
-        data.buildDataSection(buffer, vmConstant -> {
-            patchBuilder.accept(new DataPatch(buffer.position(), new ConstantReference(vmConstant)));
+        data.buildDataSection(buffer, (position, vmConstant) -> {
+            patchBuilder.accept(new DataPatch(position, new ConstantReference(vmConstant)));
         });
 
         int dataSectionAlignment = data.getSectionAlignment();
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotCounterOp.java	Fri Feb 16 12:24:38 2018 -0800
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotCounterOp.java	Fri Feb 16 13:49:07 2018 -0800
@@ -22,11 +22,13 @@
  */
 package org.graalvm.compiler.hotspot;
 
+import static jdk.vm.ci.code.ValueUtil.isRegister;
 import static org.graalvm.compiler.lir.LIRValueUtil.asJavaConstant;
 import static org.graalvm.compiler.lir.LIRValueUtil.isJavaConstant;
-import static jdk.vm.ci.code.ValueUtil.isRegister;
 
 import java.util.Arrays;
+
+import org.graalvm.collections.EconomicMap;
 import org.graalvm.compiler.asm.Assembler;
 import org.graalvm.compiler.core.common.NumUtil;
 import org.graalvm.compiler.debug.GraalError;
@@ -34,7 +36,6 @@
 import org.graalvm.compiler.hotspot.meta.HotSpotRegistersProvider;
 import org.graalvm.compiler.lir.LIRInstruction;
 import org.graalvm.compiler.lir.LIRInstructionClass;
-import org.graalvm.util.EconomicMap;
 
 import jdk.vm.ci.code.Register;
 import jdk.vm.ci.code.TargetDescription;
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotDataBuilder.java	Fri Feb 16 12:24:38 2018 -0800
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotDataBuilder.java	Fri Feb 16 13:49:07 2018 -0800
@@ -56,41 +56,30 @@
 
     @Override
     public Data createDataItem(Constant constant) {
-        int size;
-        if (constant instanceof VMConstant) {
+        if (JavaConstant.isNull(constant)) {
+            boolean compressed = COMPRESSED_NULL.equals(constant);
+            int size = compressed ? 4 : target.wordSize;
+            return ZeroData.create(size, size);
+        } else if (constant instanceof VMConstant) {
             VMConstant vmConstant = (VMConstant) constant;
-            boolean compressed;
-            if (constant instanceof HotSpotConstant) {
-                HotSpotConstant c = (HotSpotConstant) vmConstant;
-                compressed = c.isCompressed();
-            } else {
+            if (!(constant instanceof HotSpotConstant)) {
                 throw new GraalError(String.valueOf(constant));
             }
 
-            size = compressed ? 4 : target.wordSize;
-            if (size == 4) {
-                return new Data(size, size) {
-
-                    @Override
-                    protected void emit(ByteBuffer buffer, Patches patches) {
-                        patches.registerPatch(vmConstant);
+            HotSpotConstant c = (HotSpotConstant) vmConstant;
+            int size = c.isCompressed() ? 4 : target.wordSize;
+            return new Data(size, size) {
+                @Override
+                protected void emit(ByteBuffer buffer, Patches patches) {
+                    int position = buffer.position();
+                    if (getSize() == Integer.BYTES) {
                         buffer.putInt(0xDEADDEAD);
-                    }
-                };
-            } else {
-                return new Data(size, size) {
-
-                    @Override
-                    protected void emit(ByteBuffer buffer, Patches patches) {
-                        patches.registerPatch(vmConstant);
+                    } else {
                         buffer.putLong(0xDEADDEADDEADDEADL);
                     }
-                };
-            }
-        } else if (JavaConstant.isNull(constant)) {
-            boolean compressed = COMPRESSED_NULL.equals(constant);
-            size = compressed ? 4 : target.wordSize;
-            return ZeroData.create(size, size);
+                    patches.registerPatch(position, vmConstant);
+                }
+            };
         } else if (constant instanceof SerializableConstant) {
             SerializableConstant s = (SerializableConstant) constant;
             return new SerializableData(s);
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotForeignCallLinkageImpl.java	Fri Feb 16 12:24:38 2018 -0800
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotForeignCallLinkageImpl.java	Fri Feb 16 13:49:07 2018 -0800
@@ -22,15 +22,15 @@
  */
 package org.graalvm.compiler.hotspot;
 
+import static jdk.vm.ci.hotspot.HotSpotJVMCIRuntime.runtime;
 import static org.graalvm.compiler.hotspot.HotSpotForeignCallLinkage.RegisterEffect.DESTROYS_REGISTERS;
-import static jdk.vm.ci.hotspot.HotSpotJVMCIRuntime.runtime;
 
+import org.graalvm.collections.EconomicSet;
 import org.graalvm.compiler.core.common.spi.ForeignCallDescriptor;
 import org.graalvm.compiler.core.target.Backend;
 import org.graalvm.compiler.hotspot.meta.HotSpotForeignCallsProvider;
 import org.graalvm.compiler.hotspot.stubs.Stub;
 import org.graalvm.compiler.word.WordTypes;
-import org.graalvm.util.EconomicSet;
 import org.graalvm.word.LocationIdentity;
 
 import jdk.vm.ci.code.CallingConvention;
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotGraalMBean.java	Fri Feb 16 12:24:38 2018 -0800
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotGraalMBean.java	Fri Feb 16 13:49:07 2018 -0800
@@ -44,10 +44,10 @@
 import org.graalvm.compiler.options.OptionKey;
 import org.graalvm.compiler.options.OptionValues;
 import org.graalvm.compiler.options.OptionsParser;
-import org.graalvm.util.EconomicMap;
-import org.graalvm.util.EconomicSet;
-import org.graalvm.util.Equivalence;
-import org.graalvm.util.UnmodifiableEconomicMap;
+import org.graalvm.collections.EconomicMap;
+import org.graalvm.collections.EconomicSet;
+import org.graalvm.collections.Equivalence;
+import org.graalvm.collections.UnmodifiableEconomicMap;
 
 public final class HotSpotGraalMBean implements javax.management.DynamicMBean {
     private static Object mBeanServerField;
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotGraalOptionValues.java	Fri Feb 16 12:24:38 2018 -0800
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotGraalOptionValues.java	Fri Feb 16 13:49:07 2018 -0800
@@ -30,6 +30,7 @@
 import java.util.Map;
 import java.util.Properties;
 
+import org.graalvm.collections.EconomicMap;
 import org.graalvm.compiler.options.Option;
 import org.graalvm.compiler.options.OptionDescriptors;
 import org.graalvm.compiler.options.OptionKey;
@@ -37,7 +38,6 @@
 import org.graalvm.compiler.options.OptionValuesAccess;
 import org.graalvm.compiler.options.OptionsParser;
 import org.graalvm.compiler.serviceprovider.ServiceProvider;
-import org.graalvm.util.EconomicMap;
 
 import jdk.vm.ci.common.InitTimer;
 
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotGraalRuntime.java	Fri Feb 16 12:24:38 2018 -0800
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotGraalRuntime.java	Fri Feb 16 13:49:07 2018 -0800
@@ -34,6 +34,8 @@
 import java.util.List;
 import java.util.Map;
 
+import org.graalvm.collections.EconomicMap;
+import org.graalvm.collections.Equivalence;
 import org.graalvm.compiler.api.replacements.SnippetReflectionProvider;
 import org.graalvm.compiler.api.runtime.GraalRuntime;
 import org.graalvm.compiler.core.CompilationWrapper.ExceptionAction;
@@ -57,8 +59,6 @@
 import org.graalvm.compiler.replacements.SnippetCounter;
 import org.graalvm.compiler.replacements.SnippetCounter.Group;
 import org.graalvm.compiler.runtime.RuntimeProvider;
-import org.graalvm.util.EconomicMap;
-import org.graalvm.util.Equivalence;
 
 import jdk.vm.ci.code.Architecture;
 import jdk.vm.ci.code.stack.StackIntrospection;
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotLIRGenerationResult.java	Fri Feb 16 12:24:38 2018 -0800
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/HotSpotLIRGenerationResult.java	Fri Feb 16 13:49:07 2018 -0800
@@ -22,6 +22,8 @@
  */
 package org.graalvm.compiler.hotspot;
 
+import org.graalvm.collections.EconomicMap;
+import org.graalvm.collections.Equivalence;
 import org.graalvm.compiler.core.common.CompilationIdentifier;
 import org.graalvm.compiler.hotspot.stubs.Stub;
 import org.graalvm.compiler.lir.LIR;
@@ -29,8 +31,6 @@
 import org.graalvm.compiler.lir.StandardOp.SaveRegistersOp;
 import org.graalvm.compiler.lir.framemap.FrameMapBuilder;
 import org.graalvm.compiler.lir.gen.LIRGenerationResult;
-import org.graalvm.util.Equivalence;
-import org.graalvm.util.EconomicMap;
 
 import jdk.vm.ci.code.CallingConvention;
 import jdk.vm.ci.code.StackSlot;
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotForeignCallsProviderImpl.java	Fri Feb 16 12:24:38 2018 -0800
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotForeignCallsProviderImpl.java	Fri Feb 16 13:49:07 2018 -0800
@@ -30,6 +30,7 @@
 import java.util.ArrayList;
 import java.util.List;
 
+import org.graalvm.collections.EconomicMap;
 import org.graalvm.compiler.core.common.LIRKind;
 import org.graalvm.compiler.core.common.spi.ForeignCallDescriptor;
 import org.graalvm.compiler.hotspot.HotSpotForeignCallLinkage;
@@ -42,7 +43,6 @@
 import org.graalvm.compiler.options.OptionValues;
 import org.graalvm.compiler.word.Word;
 import org.graalvm.compiler.word.WordTypes;
-import org.graalvm.util.EconomicMap;
 import org.graalvm.word.LocationIdentity;
 
 import jdk.vm.ci.code.CallingConvention;
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotGraphBuilderPlugins.java	Fri Feb 16 12:24:38 2018 -0800
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotGraphBuilderPlugins.java	Fri Feb 16 13:49:07 2018 -0800
@@ -31,6 +31,7 @@
 import java.lang.invoke.ConstantCallSite;
 import java.lang.invoke.MutableCallSite;
 import java.lang.invoke.VolatileCallSite;
+import java.lang.reflect.Array;
 import java.lang.reflect.Method;
 import java.lang.reflect.Modifier;
 import java.math.BigInteger;
@@ -39,17 +40,20 @@
 import org.graalvm.compiler.api.replacements.SnippetReflectionProvider;
 import org.graalvm.compiler.bytecode.BytecodeProvider;
 import org.graalvm.compiler.core.common.spi.ForeignCallsProvider;
+import org.graalvm.compiler.core.common.type.ObjectStamp;
 import org.graalvm.compiler.core.common.type.StampFactory;
+import org.graalvm.compiler.core.common.type.TypeReference;
 import org.graalvm.compiler.debug.GraalError;
 import org.graalvm.compiler.hotspot.GraalHotSpotVMConfig;
 import org.graalvm.compiler.hotspot.nodes.CurrentJavaThreadNode;
 import org.graalvm.compiler.hotspot.replacements.AESCryptSubstitutions;
 import org.graalvm.compiler.hotspot.replacements.BigIntegerSubstitutions;
+import org.graalvm.compiler.hotspot.replacements.CRC32CSubstitutions;
 import org.graalvm.compiler.hotspot.replacements.CRC32Substitutions;
-import org.graalvm.compiler.hotspot.replacements.CRC32CSubstitutions;
 import org.graalvm.compiler.hotspot.replacements.CallSiteTargetNode;
 import org.graalvm.compiler.hotspot.replacements.CipherBlockChainingSubstitutions;
 import org.graalvm.compiler.hotspot.replacements.ClassGetHubNode;
+import org.graalvm.compiler.hotspot.replacements.HotSpotArraySubstitutions;
 import org.graalvm.compiler.hotspot.replacements.HotSpotClassSubstitutions;
 import org.graalvm.compiler.hotspot.replacements.IdentityHashCodeNode;
 import org.graalvm.compiler.hotspot.replacements.ObjectCloneNode;
@@ -68,7 +72,6 @@
 import org.graalvm.compiler.nodes.LogicNode;
 import org.graalvm.compiler.nodes.NamedLocationIdentity;
 import org.graalvm.compiler.nodes.NodeView;
-import org.graalvm.compiler.nodes.PiNode;
 import org.graalvm.compiler.nodes.ValueNode;
 import org.graalvm.compiler.nodes.calc.AddNode;
 import org.graalvm.compiler.nodes.calc.IntegerConvertNode;
@@ -83,8 +86,10 @@
 import org.graalvm.compiler.nodes.graphbuilderconf.NodeIntrinsicPluginFactory;
 import org.graalvm.compiler.nodes.java.InstanceOfDynamicNode;
 import org.graalvm.compiler.nodes.memory.HeapAccess.BarrierType;
+import org.graalvm.compiler.nodes.memory.ReadNode;
 import org.graalvm.compiler.nodes.memory.address.AddressNode;
 import org.graalvm.compiler.nodes.memory.address.OffsetAddressNode;
+import org.graalvm.compiler.nodes.spi.LoweringProvider;
 import org.graalvm.compiler.nodes.spi.StampProvider;
 import org.graalvm.compiler.nodes.util.GraphUtil;
 import org.graalvm.compiler.options.OptionValues;
@@ -123,12 +128,12 @@
      * @param stampProvider
      */
     public static Plugins create(CompilerConfiguration compilerConfiguration, GraalHotSpotVMConfig config, HotSpotWordTypes wordTypes, MetaAccessProvider metaAccess,
-                    ConstantReflectionProvider constantReflection, SnippetReflectionProvider snippetReflection, ForeignCallsProvider foreignCalls, StampProvider stampProvider,
-                    ReplacementsImpl replacements) {
+                    ConstantReflectionProvider constantReflection, SnippetReflectionProvider snippetReflection, ForeignCallsProvider foreignCalls, LoweringProvider lowerer,
+                    StampProvider stampProvider, ReplacementsImpl replacements) {
         InvocationPlugins invocationPlugins = new HotSpotInvocationPlugins(config, compilerConfiguration);
 
         Plugins plugins = new Plugins(invocationPlugins);
-        NodeIntrinsificationProvider nodeIntrinsificationProvider = new NodeIntrinsificationProvider(metaAccess, snippetReflection, foreignCalls, wordTypes);
+        NodeIntrinsificationProvider nodeIntrinsificationProvider = new NodeIntrinsificationProvider(metaAccess, snippetReflection, foreignCalls, lowerer, wordTypes);
         HotSpotWordOperationPlugin wordOperationPlugin = new HotSpotWordOperationPlugin(snippetReflection, wordTypes);
         HotSpotNodePlugin nodePlugin = new HotSpotNodePlugin(wordOperationPlugin);
 
@@ -171,6 +176,7 @@
                 registerSHAPlugins(invocationPlugins, config, replacementBytecodeProvider);
                 registerUnsafePlugins(invocationPlugins, replacementBytecodeProvider);
                 StandardGraphBuilderPlugins.registerInvocationPlugins(metaAccess, snippetReflection, invocationPlugins, replacementBytecodeProvider, true);
+                registerArrayPlugins(invocationPlugins, replacementBytecodeProvider);
 
                 for (NodeIntrinsicPluginFactory factory : GraalServices.load(NodeIntrinsicPluginFactory.class)) {
                     factory.registerPlugins(invocationPlugins, nodeIntrinsificationProvider);
@@ -401,19 +407,23 @@
         });
     }
 
+    private static void registerArrayPlugins(InvocationPlugins plugins, BytecodeProvider bytecodeProvider) {
+        Registration r = new Registration(plugins, Array.class, bytecodeProvider);
+        r.setAllowOverwrite(true);
+        r.registerMethodSubstitution(HotSpotArraySubstitutions.class, "newInstance", Class.class, int.class);
+    }
+
     private static void registerThreadPlugins(InvocationPlugins plugins, MetaAccessProvider metaAccess, WordTypes wordTypes, GraalHotSpotVMConfig config, BytecodeProvider bytecodeProvider) {
         Registration r = new Registration(plugins, Thread.class, bytecodeProvider);
         r.register0("currentThread", new InvocationPlugin() {
             @Override
             public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver) {
                 CurrentJavaThreadNode thread = b.add(new CurrentJavaThreadNode(wordTypes.getWordKind()));
-                boolean compressible = false;
                 ValueNode offset = b.add(ConstantNode.forLong(config.threadObjectOffset));
                 AddressNode address = b.add(new OffsetAddressNode(thread, offset));
-                ValueNode javaThread = WordOperationPlugin.readOp(b, JavaKind.Object, address, JAVA_THREAD_THREAD_OBJECT_LOCATION, BarrierType.NONE, compressible);
-                boolean exactType = false;
-                boolean nonNull = true;
-                b.addPush(JavaKind.Object, new PiNode(javaThread, metaAccess.lookupJavaType(Thread.class), exactType, nonNull));
+                // JavaThread::_threadObj is never compressed
+                ObjectStamp stamp = StampFactory.objectNonNull(TypeReference.create(b.getAssumptions(), metaAccess.lookupJavaType(Thread.class)));
+                b.addPush(JavaKind.Object, new ReadNode(address, JAVA_THREAD_THREAD_OBJECT_LOCATION, stamp, BarrierType.NONE));
                 return true;
             }
         });
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotHostForeignCallsProvider.java	Fri Feb 16 12:24:38 2018 -0800
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotHostForeignCallsProvider.java	Fri Feb 16 13:49:07 2018 -0800
@@ -101,6 +101,7 @@
 
 import java.util.EnumMap;
 
+import org.graalvm.collections.EconomicMap;
 import org.graalvm.compiler.core.common.spi.ForeignCallDescriptor;
 import org.graalvm.compiler.core.common.spi.ForeignCallsProvider;
 import org.graalvm.compiler.debug.GraalError;
@@ -123,7 +124,6 @@
 import org.graalvm.compiler.options.OptionValues;
 import org.graalvm.compiler.word.Word;
 import org.graalvm.compiler.word.WordTypes;
-import org.graalvm.util.EconomicMap;
 import org.graalvm.word.LocationIdentity;
 
 import jdk.vm.ci.code.CodeCacheProvider;
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotInvocationPlugins.java	Fri Feb 16 12:24:38 2018 -0800
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotInvocationPlugins.java	Fri Feb 16 13:49:07 2018 -0800
@@ -27,6 +27,7 @@
 import java.lang.reflect.Type;
 import java.util.Set;
 
+import org.graalvm.collections.EconomicSet;
 import org.graalvm.compiler.core.common.GraalOptions;
 import org.graalvm.compiler.debug.GraalError;
 import org.graalvm.compiler.graph.Node;
@@ -42,7 +43,6 @@
 import org.graalvm.compiler.phases.tiers.CompilerConfiguration;
 import org.graalvm.compiler.replacements.nodes.MacroNode;
 import org.graalvm.compiler.serviceprovider.JDK9Method;
-import org.graalvm.util.EconomicSet;
 
 import jdk.vm.ci.hotspot.HotSpotResolvedJavaType;
 import jdk.vm.ci.meta.JavaKind;
@@ -122,7 +122,7 @@
      * of its module dependencies are trusted.
      */
     @Override
-    protected boolean canBeIntrinsified(ResolvedJavaType declaringClass) {
+    public boolean canBeIntrinsified(ResolvedJavaType declaringClass) {
         if (declaringClass instanceof HotSpotResolvedJavaType) {
             Class<?> javaClass = ((HotSpotResolvedJavaType) declaringClass).mirror();
             if (Java8OrEarlier) {
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotSnippetReflectionProvider.java	Fri Feb 16 12:24:38 2018 -0800
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/meta/HotSpotSnippetReflectionProvider.java	Fri Feb 16 13:49:07 2018 -0800
@@ -22,6 +22,7 @@
  */
 package org.graalvm.compiler.hotspot.meta;
 
+import jdk.vm.ci.hotspot.HotSpotResolvedJavaType;
 import org.graalvm.compiler.api.replacements.SnippetReflectionProvider;
 import org.graalvm.compiler.hotspot.HotSpotGraalRuntimeProvider;
 import org.graalvm.compiler.hotspot.GraalHotSpotVMConfig;
@@ -104,4 +105,9 @@
         }
         return null;
     }
+
+    @Override
+    public Class<?> originalClass(ResolvedJavaType type) {
+        return ((HotSpotResolvedJavaType) type).mirror();
+    }
 }
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/ArrayRangeWriteBarrier.java	Fri Feb 16 12:24:38 2018 -0800
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/ArrayRangeWriteBarrier.java	Fri Feb 16 13:49:07 2018 -0800
@@ -23,34 +23,37 @@
 package org.graalvm.compiler.hotspot.nodes;
 
 import org.graalvm.compiler.graph.NodeClass;
+import org.graalvm.compiler.nodeinfo.InputType;
 import org.graalvm.compiler.nodeinfo.NodeInfo;
 import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.memory.address.AddressNode;
 import org.graalvm.compiler.nodes.spi.Lowerable;
 
 @NodeInfo
 public abstract class ArrayRangeWriteBarrier extends WriteBarrier implements Lowerable {
 
     public static final NodeClass<ArrayRangeWriteBarrier> TYPE = NodeClass.create(ArrayRangeWriteBarrier.class);
-    @Input ValueNode object;
-    @Input ValueNode startIndex;
+    @Input(InputType.Association) AddressNode address;
     @Input ValueNode length;
 
-    protected ArrayRangeWriteBarrier(NodeClass<? extends ArrayRangeWriteBarrier> c, ValueNode object, ValueNode startIndex, ValueNode length) {
+    private final int elementStride;
+
+    protected ArrayRangeWriteBarrier(NodeClass<? extends ArrayRangeWriteBarrier> c, AddressNode address, ValueNode length, int elementStride) {
         super(c);
-        this.object = object;
-        this.startIndex = startIndex;
+        this.address = address;
         this.length = length;
+        this.elementStride = elementStride;
     }
 
-    public ValueNode getObject() {
-        return object;
-    }
-
-    public ValueNode getStartIndex() {
-        return startIndex;
+    public AddressNode getAddress() {
+        return address;
     }
 
     public ValueNode getLength() {
         return length;
     }
+
+    public int getElementStride() {
+        return elementStride;
+    }
 }
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/G1ArrayRangePostWriteBarrier.java	Fri Feb 16 12:24:38 2018 -0800
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/G1ArrayRangePostWriteBarrier.java	Fri Feb 16 13:49:07 2018 -0800
@@ -28,13 +28,14 @@
 import org.graalvm.compiler.graph.NodeClass;
 import org.graalvm.compiler.nodeinfo.NodeInfo;
 import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.memory.address.AddressNode;
 
 @NodeInfo(cycles = CYCLES_64, size = SIZE_64)
 public class G1ArrayRangePostWriteBarrier extends ArrayRangeWriteBarrier {
     public static final NodeClass<G1ArrayRangePostWriteBarrier> TYPE = NodeClass.create(G1ArrayRangePostWriteBarrier.class);
 
-    public G1ArrayRangePostWriteBarrier(ValueNode object, ValueNode startIndex, ValueNode length) {
-        super(TYPE, object, startIndex, length);
+    public G1ArrayRangePostWriteBarrier(AddressNode address, ValueNode length, int elementStride) {
+        super(TYPE, address, length, elementStride);
     }
 
 }
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/G1ArrayRangePreWriteBarrier.java	Fri Feb 16 12:24:38 2018 -0800
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/G1ArrayRangePreWriteBarrier.java	Fri Feb 16 13:49:07 2018 -0800
@@ -28,13 +28,14 @@
 import org.graalvm.compiler.graph.NodeClass;
 import org.graalvm.compiler.nodeinfo.NodeInfo;
 import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.memory.address.AddressNode;
 
 @NodeInfo(cycles = CYCLES_64, size = SIZE_64)
 public final class G1ArrayRangePreWriteBarrier extends ArrayRangeWriteBarrier {
     public static final NodeClass<G1ArrayRangePreWriteBarrier> TYPE = NodeClass.create(G1ArrayRangePreWriteBarrier.class);
 
-    public G1ArrayRangePreWriteBarrier(ValueNode object, ValueNode startIndex, ValueNode length) {
-        super(TYPE, object, startIndex, length);
+    public G1ArrayRangePreWriteBarrier(AddressNode address, ValueNode length, int elementStride) {
+        super(TYPE, address, length, elementStride);
     }
 
 }
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/SerialArrayRangeWriteBarrier.java	Fri Feb 16 12:24:38 2018 -0800
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/nodes/SerialArrayRangeWriteBarrier.java	Fri Feb 16 13:49:07 2018 -0800
@@ -28,14 +28,14 @@
 import org.graalvm.compiler.graph.NodeClass;
 import org.graalvm.compiler.nodeinfo.NodeInfo;
 import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.memory.address.AddressNode;
 
 @NodeInfo(cycles = CYCLES_8, size = SIZE_8)
 public final class SerialArrayRangeWriteBarrier extends ArrayRangeWriteBarrier {
-
     public static final NodeClass<SerialArrayRangeWriteBarrier> TYPE = NodeClass.create(SerialArrayRangeWriteBarrier.class);
 
-    public SerialArrayRangeWriteBarrier(ValueNode object, ValueNode startIndex, ValueNode length) {
-        super(TYPE, object, startIndex, length);
+    public SerialArrayRangeWriteBarrier(AddressNode address, ValueNode length, int elementStride) {
+        super(TYPE, address, length, elementStride);
     }
 
 }
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/phases/WriteBarrierAdditionPhase.java	Fri Feb 16 12:24:38 2018 -0800
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/phases/WriteBarrierAdditionPhase.java	Fri Feb 16 13:49:07 2018 -0800
@@ -34,7 +34,7 @@
 import org.graalvm.compiler.hotspot.nodes.SerialWriteBarrier;
 import org.graalvm.compiler.nodes.StructuredGraph;
 import org.graalvm.compiler.nodes.ValueNode;
-import org.graalvm.compiler.nodes.extended.ArrayRangeWriteNode;
+import org.graalvm.compiler.nodes.extended.ArrayRangeWrite;
 import org.graalvm.compiler.nodes.java.AbstractCompareAndSwapNode;
 import org.graalvm.compiler.nodes.java.LoweredAtomicReadAndWriteNode;
 import org.graalvm.compiler.nodes.memory.FixedAccessNode;
@@ -65,9 +65,9 @@
                 addAtomicReadWriteNodeBarriers(loweredAtomicReadAndWriteNode, graph);
             } else if (n instanceof AbstractCompareAndSwapNode) {
                 addCASBarriers((AbstractCompareAndSwapNode) n, graph);
-            } else if (n instanceof ArrayRangeWriteNode) {
-                ArrayRangeWriteNode node = (ArrayRangeWriteNode) n;
-                if (node.isObjectArray()) {
+            } else if (n instanceof ArrayRangeWrite) {
+                ArrayRangeWrite node = (ArrayRangeWrite) n;
+                if (node.writesObjectArray()) {
                     addArrayRangeBarriers(node, graph);
                 }
             }
@@ -171,17 +171,17 @@
         }
     }
 
-    private void addArrayRangeBarriers(ArrayRangeWriteNode node, StructuredGraph graph) {
+    private void addArrayRangeBarriers(ArrayRangeWrite write, StructuredGraph graph) {
         if (config.useG1GC) {
-            if (!node.isInitialization()) {
-                G1ArrayRangePreWriteBarrier g1ArrayRangePreWriteBarrier = graph.add(new G1ArrayRangePreWriteBarrier(node.getArray(), node.getIndex(), node.getLength()));
-                graph.addBeforeFixed(node, g1ArrayRangePreWriteBarrier);
+            if (!write.isInitialization()) {
+                G1ArrayRangePreWriteBarrier g1ArrayRangePreWriteBarrier = graph.add(new G1ArrayRangePreWriteBarrier(write.getAddress(), write.getLength(), write.getElementStride()));
+                graph.addBeforeFixed(write.asNode(), g1ArrayRangePreWriteBarrier);
             }
-            G1ArrayRangePostWriteBarrier g1ArrayRangePostWriteBarrier = graph.add(new G1ArrayRangePostWriteBarrier(node.getArray(), node.getIndex(), node.getLength()));
-            graph.addAfterFixed(node, g1ArrayRangePostWriteBarrier);
+            G1ArrayRangePostWriteBarrier g1ArrayRangePostWriteBarrier = graph.add(new G1ArrayRangePostWriteBarrier(write.getAddress(), write.getLength(), write.getElementStride()));
+            graph.addAfterFixed(write.asNode(), g1ArrayRangePostWriteBarrier);
         } else {
-            SerialArrayRangeWriteBarrier serialArrayRangeWriteBarrier = graph.add(new SerialArrayRangeWriteBarrier(node.getArray(), node.getIndex(), node.getLength()));
-            graph.addAfterFixed(node, serialArrayRangeWriteBarrier);
+            SerialArrayRangeWriteBarrier serialArrayRangeWriteBarrier = graph.add(new SerialArrayRangeWriteBarrier(write.getAddress(), write.getLength(), write.getElementStride()));
+            graph.addAfterFixed(write.asNode(), serialArrayRangeWriteBarrier);
         }
     }
 
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/phases/WriteBarrierVerificationPhase.java	Fri Feb 16 12:24:38 2018 -0800
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/phases/WriteBarrierVerificationPhase.java	Fri Feb 16 13:49:07 2018 -0800
@@ -39,7 +39,7 @@
 import org.graalvm.compiler.nodes.LoopBeginNode;
 import org.graalvm.compiler.nodes.StructuredGraph;
 import org.graalvm.compiler.nodes.ValueNode;
-import org.graalvm.compiler.nodes.extended.ArrayRangeWriteNode;
+import org.graalvm.compiler.nodes.extended.ArrayRangeWrite;
 import org.graalvm.compiler.nodes.java.LoweredAtomicReadAndWriteNode;
 import org.graalvm.compiler.nodes.java.LogicCompareAndSwapNode;
 import org.graalvm.compiler.nodes.memory.FixedAccessNode;
@@ -122,7 +122,7 @@
     private boolean hasAttachedBarrier(FixedWithNextNode node) {
         final Node next = node.next();
         final Node previous = node.predecessor();
-        boolean validatePreBarrier = useG1GC() && (isObjectWrite(node) || !((ArrayRangeWriteNode) node).isInitialization());
+        boolean validatePreBarrier = useG1GC() && (isObjectWrite(node) || !((ArrayRangeWrite) node).isInitialization());
         if (node instanceof WriteNode) {
             WriteNode writeNode = (WriteNode) node;
             if (writeNode.getLocationIdentity().isInit()) {
@@ -143,7 +143,7 @@
     }
 
     private static boolean isArrayBarrier(FixedWithNextNode node, final Node next) {
-        return (next instanceof ArrayRangeWriteBarrier) && ((ArrayRangeWriteNode) node).getArray() == ((ArrayRangeWriteBarrier) next).getObject();
+        return (next instanceof ArrayRangeWriteBarrier) && ((ArrayRangeWrite) node).getAddress() == ((ArrayRangeWriteBarrier) next).getAddress();
     }
 
     private static boolean isObjectWrite(Node node) {
@@ -152,7 +152,7 @@
     }
 
     private static boolean isObjectArrayRangeWrite(Node node) {
-        return node instanceof ArrayRangeWriteNode && ((ArrayRangeWriteNode) node).isObjectArray();
+        return node instanceof ArrayRangeWrite && ((ArrayRangeWrite) node).writesObjectArray();
     }
 
     private static void expandFrontier(NodeFlood frontier, Node node) {
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/phases/aot/EliminateRedundantInitializationPhase.java	Fri Feb 16 12:24:38 2018 -0800
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/phases/aot/EliminateRedundantInitializationPhase.java	Fri Feb 16 13:49:07 2018 -0800
@@ -28,6 +28,11 @@
 import java.util.Iterator;
 import java.util.List;
 
+import jdk.vm.ci.hotspot.HotSpotMetaspaceConstant;
+import jdk.vm.ci.meta.Constant;
+import jdk.vm.ci.meta.ResolvedJavaType;
+
+import org.graalvm.collections.EconomicSet;
 import org.graalvm.compiler.graph.Node;
 import org.graalvm.compiler.hotspot.nodes.aot.InitializeKlassNode;
 import org.graalvm.compiler.hotspot.nodes.aot.ResolveConstantNode;
@@ -40,11 +45,6 @@
 import org.graalvm.compiler.phases.graph.MergeableState;
 import org.graalvm.compiler.phases.graph.PostOrderNodeIterator;
 import org.graalvm.compiler.phases.tiers.PhaseContext;
-import org.graalvm.util.EconomicSet;
-
-import jdk.vm.ci.hotspot.HotSpotMetaspaceConstant;
-import jdk.vm.ci.meta.Constant;
-import jdk.vm.ci.meta.ResolvedJavaType;
 
 public class EliminateRedundantInitializationPhase extends BasePhase<PhaseContext> {
     /**
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/phases/aot/ReplaceConstantNodesPhase.java	Fri Feb 16 12:24:38 2018 -0800
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/phases/aot/ReplaceConstantNodesPhase.java	Fri Feb 16 13:49:07 2018 -0800
@@ -29,6 +29,7 @@
 import java.util.HashSet;
 import java.util.List;
 
+import org.graalvm.collections.EconomicMap;
 import org.graalvm.compiler.core.common.cfg.BlockMap;
 import org.graalvm.compiler.core.common.type.ObjectStamp;
 import org.graalvm.compiler.core.common.type.Stamp;
@@ -64,7 +65,6 @@
 import org.graalvm.compiler.phases.schedule.SchedulePhase;
 import org.graalvm.compiler.phases.schedule.SchedulePhase.SchedulingStrategy;
 import org.graalvm.compiler.phases.tiers.PhaseContext;
-import org.graalvm.util.EconomicMap;
 
 import jdk.vm.ci.code.BytecodeFrame;
 import jdk.vm.ci.hotspot.HotSpotMetaspaceConstant;
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/ClassGetHubNode.java	Fri Feb 16 12:24:38 2018 -0800
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/ClassGetHubNode.java	Fri Feb 16 13:49:07 2018 -0800
@@ -25,10 +25,7 @@
 import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_1;
 import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_1;
 
-import jdk.vm.ci.meta.JavaKind;
-import jdk.vm.ci.meta.ResolvedJavaMethod;
-
-import org.graalvm.compiler.core.common.calc.Condition;
+import org.graalvm.compiler.core.common.calc.CanonicalCondition;
 import org.graalvm.compiler.core.common.type.Stamp;
 import org.graalvm.compiler.graph.Node;
 import org.graalvm.compiler.graph.NodeClass;
@@ -56,7 +53,9 @@
 import jdk.vm.ci.meta.Constant;
 import jdk.vm.ci.meta.ConstantReflectionProvider;
 import jdk.vm.ci.meta.JavaConstant;
+import jdk.vm.ci.meta.JavaKind;
 import jdk.vm.ci.meta.MetaAccessProvider;
+import jdk.vm.ci.meta.ResolvedJavaMethod;
 import jdk.vm.ci.meta.ResolvedJavaType;
 
 /**
@@ -169,8 +168,8 @@
     }
 
     @Override
-    public boolean preservesOrder(Condition op, Constant value, ConstantReflectionProvider constantReflection) {
-        assert op == Condition.EQ || op == Condition.NE;
+    public boolean preservesOrder(CanonicalCondition op, Constant value, ConstantReflectionProvider constantReflection) {
+        assert op == CanonicalCondition.EQ;
         ResolvedJavaType exactType = constantReflection.asJavaType(value);
         return !exactType.isPrimitive();
     }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/HotSpotArraySubstitutions.java	Fri Feb 16 13:49:07 2018 -0800
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.hotspot.replacements;
+
+import static org.graalvm.compiler.hotspot.GraalHotSpotVMConfig.INJECTED_VMCONFIG;
+import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.CLASS_ARRAY_KLASS_LOCATION;
+import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.arrayKlassOffset;
+import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.loadKlassFromObject;
+
+import java.lang.reflect.Array;
+
+import org.graalvm.compiler.api.directives.GraalDirectives;
+import org.graalvm.compiler.api.replacements.ClassSubstitution;
+import org.graalvm.compiler.api.replacements.MethodSubstitution;
+import org.graalvm.compiler.nodes.java.DynamicNewArrayNode;
+
+// JaCoCo Exclude
+
+/**
+ * Substitutions for {@link Array} methods.
+ */
+@ClassSubstitution(Array.class)
+public class HotSpotArraySubstitutions {
+
+    @MethodSubstitution
+    public static Object newInstance(Class<?> componentType, int length) {
+        if (componentType == null || loadKlassFromObject(componentType, arrayKlassOffset(INJECTED_VMCONFIG), CLASS_ARRAY_KLASS_LOCATION).isNull()) {
+            // Exit the intrinsic here for the case where the array class does not exist
+            return newInstance(componentType, length);
+        }
+        return DynamicNewArrayNode.newArray(GraalDirectives.guardingNonNull(componentType), length);
+    }
+
+}
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/HotSpotReplacementsUtil.java	Fri Feb 16 12:24:38 2018 -0800
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/HotSpotReplacementsUtil.java	Fri Feb 16 13:49:07 2018 -0800
@@ -303,7 +303,11 @@
         return result;
     }
 
-    public static final LocationIdentity JAVA_THREAD_THREAD_OBJECT_LOCATION = NamedLocationIdentity.mutable("JavaThread::_threadObj");
+    /*
+     * As far as Java code is concerned this can be considered immutable: it is set just after the
+     * JavaThread is created, before it is published. After that, it is never changed.
+     */
+    public static final LocationIdentity JAVA_THREAD_THREAD_OBJECT_LOCATION = NamedLocationIdentity.immutable("JavaThread::_threadObj");
 
     @Fold
     public static int threadObjectOffset(@InjectedParameter GraalHotSpotVMConfig config) {
@@ -565,9 +569,20 @@
         return WordFactory.unsigned(ComputeObjectAddressNode.get(a, getArrayBaseOffset(JavaKind.Int)));
     }
 
+    /**
+     * Idiom for making {@link GraalHotSpotVMConfig} a constant.
+     */
     @Fold
-    public static int objectAlignment(@InjectedParameter GraalHotSpotVMConfig config) {
-        return config.objectAlignment;
+    public static GraalHotSpotVMConfig getConfig(@InjectedParameter GraalHotSpotVMConfig config) {
+        return config;
+    }
+
+    /**
+     * Calls {@link #arrayAllocationSize(int, int, int, GraalHotSpotVMConfig)} using an injected VM
+     * configuration object.
+     */
+    public static int arrayAllocationSize(int length, int headerSize, int log2ElementSize) {
+        return arrayAllocationSize(length, headerSize, log2ElementSize, getConfig(INJECTED_VMCONFIG));
     }
 
     /**
@@ -578,10 +593,12 @@
      * @param length the number of elements in the array
      * @param headerSize the size of the array header
      * @param log2ElementSize log2 of the size of an element in the array
+     * @param config the VM configuration providing the
+     *            {@linkplain GraalHotSpotVMConfig#objectAlignment object alignment requirement}
      * @return the size of the memory chunk
      */
-    public static int arrayAllocationSize(int length, int headerSize, int log2ElementSize) {
-        int alignment = objectAlignment(INJECTED_VMCONFIG);
+    public static int arrayAllocationSize(int length, int headerSize, int log2ElementSize, GraalHotSpotVMConfig config) {
+        int alignment = config.objectAlignment;
         int size = (length << log2ElementSize) + headerSize + (alignment - 1);
         int mask = ~(alignment - 1);
         return size & mask;
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/NewObjectSnippets.java	Fri Feb 16 12:24:38 2018 -0800
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/NewObjectSnippets.java	Fri Feb 16 13:49:07 2018 -0800
@@ -62,6 +62,7 @@
 import static org.graalvm.compiler.nodes.extended.BranchProbabilityNode.SLOW_PATH_PROBABILITY;
 import static org.graalvm.compiler.nodes.extended.BranchProbabilityNode.probability;
 import static org.graalvm.compiler.replacements.ReplacementsUtil.REPLACEMENTS_ASSERTIONS_ENABLED;
+import static org.graalvm.compiler.replacements.ReplacementsUtil.runtimeAssert;
 import static org.graalvm.compiler.replacements.ReplacementsUtil.staticAssert;
 import static org.graalvm.compiler.replacements.SnippetTemplate.DEFAULT_REPLACER;
 import static org.graalvm.compiler.replacements.nodes.CStringConstant.cstring;
@@ -378,7 +379,13 @@
         if (length < 0) {
             DeoptimizeNode.deopt(DeoptimizationAction.None, DeoptimizationReason.RuntimeConstraint);
         }
-        int layoutHelper = knownElementKind != JavaKind.Illegal ? knownLayoutHelper : readLayoutHelper(nonNullKlass);
+        int layoutHelper;
+        if (knownElementKind == JavaKind.Illegal) {
+            layoutHelper = readLayoutHelper(nonNullKlass);
+        } else {
+            runtimeAssert(knownLayoutHelper == readLayoutHelper(nonNullKlass), "layout mismatch");
+            layoutHelper = knownLayoutHelper;
+        }
         //@formatter:off
         // from src/share/vm/oops/klass.hpp:
         //
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/WriteBarrierSnippets.java	Fri Feb 16 12:24:38 2018 -0800
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/WriteBarrierSnippets.java	Fri Feb 16 13:49:07 2018 -0800
@@ -24,7 +24,6 @@
 
 import static jdk.vm.ci.code.MemoryBarriers.STORE_LOAD;
 import static org.graalvm.compiler.hotspot.GraalHotSpotVMConfig.INJECTED_VMCONFIG;
-import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.arrayBaseOffset;
 import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.arrayIndexScale;
 import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.cardTableShift;
 import static org.graalvm.compiler.hotspot.replacements.HotSpotReplacementsUtil.dirtyCardValue;
@@ -59,7 +58,6 @@
 import org.graalvm.compiler.hotspot.nodes.G1PostWriteBarrier;
 import org.graalvm.compiler.hotspot.nodes.G1PreWriteBarrier;
 import org.graalvm.compiler.hotspot.nodes.G1ReferentFieldReadBarrier;
-import org.graalvm.compiler.hotspot.nodes.GetObjectAddressNode;
 import org.graalvm.compiler.hotspot.nodes.GraalHotSpotVMConfigNode;
 import org.graalvm.compiler.hotspot.nodes.HotSpotCompressionNode;
 import org.graalvm.compiler.hotspot.nodes.SerialArrayRangeWriteBarrier;
@@ -152,18 +150,14 @@
     }
 
     @Snippet
-    public static void serialArrayRangeWriteBarrier(Object object, int startIndex, int length) {
+    public static void serialArrayRangeWriteBarrier(Address address, int length, @ConstantParameter int elementStride) {
         if (length == 0) {
             return;
         }
-        Object dest = FixedValueAnchorNode.getObject(object);
         int cardShift = cardTableShift(INJECTED_VMCONFIG);
         final long cardStart = GraalHotSpotVMConfigNode.cardTableAddress();
-        final int scale = arrayIndexScale(JavaKind.Object);
-        int header = arrayBaseOffset(JavaKind.Object);
-        long dstAddr = GetObjectAddressNode.get(dest);
-        long start = (dstAddr + header + (long) startIndex * scale) >>> cardShift;
-        long end = (dstAddr + header + ((long) startIndex + length - 1) * scale) >>> cardShift;
+        long start = getPointerToFirstArrayElement(address, length, elementStride) >>> cardShift;
+        long end = getPointerToLastArrayElement(address, length, elementStride) >>> cardShift;
         long count = end - start + 1;
         while (count-- > 0) {
             DirectStoreNode.storeBoolean((start + cardStart) + count, false, JavaKind.Boolean);
@@ -305,24 +299,22 @@
     }
 
     @Snippet
-    public static void g1ArrayRangePreWriteBarrier(Object object, int startIndex, int length, @ConstantParameter Register threadRegister) {
+    public static void g1ArrayRangePreWriteBarrier(Address address, int length, @ConstantParameter int elementStride, @ConstantParameter Register threadRegister) {
         Word thread = registerAsWord(threadRegister);
         byte markingValue = thread.readByte(g1SATBQueueMarkingOffset(INJECTED_VMCONFIG));
         // If the concurrent marker is not enabled or the vector length is zero, return.
         if (markingValue == (byte) 0 || length == 0) {
             return;
         }
-        Object dest = FixedValueAnchorNode.getObject(object);
         Word bufferAddress = thread.readWord(g1SATBQueueBufferOffset(INJECTED_VMCONFIG));
         Word indexAddress = thread.add(g1SATBQueueIndexOffset(INJECTED_VMCONFIG));
-        long dstAddr = GetObjectAddressNode.get(dest);
         long indexValue = indexAddress.readWord(0).rawValue();
         final int scale = arrayIndexScale(JavaKind.Object);
-        int header = arrayBaseOffset(JavaKind.Object);
+        long start = getPointerToFirstArrayElement(address, length, elementStride);
 
-        for (int i = startIndex; i < length; i++) {
-            Word address = WordFactory.pointer(dstAddr + header + (i * scale));
-            Pointer oop = Word.objectToTrackedPointer(address.readObject(0, BarrierType.NONE));
+        for (int i = 0; i < length; i++) {
+            Word arrElemPtr = WordFactory.pointer(start + i * scale);
+            Pointer oop = Word.objectToTrackedPointer(arrElemPtr.readObject(0, BarrierType.NONE));
             verifyOop(oop.toObject());
             if (oop.notEqual(0)) {
                 if (indexValue != 0) {
@@ -339,11 +331,10 @@
     }
 
     @Snippet
-    public static void g1ArrayRangePostWriteBarrier(Object object, int startIndex, int length, @ConstantParameter Register threadRegister) {
+    public static void g1ArrayRangePostWriteBarrier(Address address, int length, @ConstantParameter int elementStride, @ConstantParameter Register threadRegister) {
         if (length == 0) {
             return;
         }
-        Object dest = FixedValueAnchorNode.getObject(object);
         Word thread = registerAsWord(threadRegister);
         Word bufferAddress = thread.readWord(g1CardQueueBufferOffset(INJECTED_VMCONFIG));
         Word indexAddress = thread.add(g1CardQueueIndexOffset(INJECTED_VMCONFIG));
@@ -351,11 +342,8 @@
 
         int cardShift = cardTableShift(INJECTED_VMCONFIG);
         final long cardStart = GraalHotSpotVMConfigNode.cardTableAddress();
-        final int scale = arrayIndexScale(JavaKind.Object);
-        int header = arrayBaseOffset(JavaKind.Object);
-        long dstAddr = GetObjectAddressNode.get(dest);
-        long start = (dstAddr + header + (long) startIndex * scale) >>> cardShift;
-        long end = (dstAddr + header + ((long) startIndex + length - 1) * scale) >>> cardShift;
+        long start = getPointerToFirstArrayElement(address, length, elementStride) >>> cardShift;
+        long end = getPointerToLastArrayElement(address, length, elementStride) >>> cardShift;
         long count = end - start + 1;
 
         while (count-- > 0) {
@@ -384,6 +372,26 @@
         }
     }
 
+    private static long getPointerToFirstArrayElement(Address address, int length, int elementStride) {
+        long result = Word.fromAddress(address).rawValue();
+        if (elementStride < 0) {
+            // the address points to the place after the last array element
+            result = result + elementStride * length;
+        }
+        return result;
+    }
+
+    private static long getPointerToLastArrayElement(Address address, int length, int elementStride) {
+        long result = Word.fromAddress(address).rawValue();
+        if (elementStride < 0) {
+            // the address points to the place after the last array element
+            result = result + elementStride;
+        } else {
+            result = result + (length - 1) * elementStride;
+        }
+        return result;
+    }
+
     public static final ForeignCallDescriptor G1WBPRECALL = new ForeignCallDescriptor("write_barrier_pre", void.class, Object.class);
 
     @NodeIntrinsic(ForeignCallNode.class)
@@ -431,9 +439,9 @@
 
         public void lower(SerialArrayRangeWriteBarrier arrayRangeWriteBarrier, LoweringTool tool) {
             Arguments args = new Arguments(serialArrayRangeWriteBarrier, arrayRangeWriteBarrier.graph().getGuardsStage(), tool.getLoweringStage());
-            args.add("object", arrayRangeWriteBarrier.getObject());
-            args.add("startIndex", arrayRangeWriteBarrier.getStartIndex());
+            args.add("address", arrayRangeWriteBarrier.getAddress());
             args.add("length", arrayRangeWriteBarrier.getLength());
+            args.addConst("elementStride", arrayRangeWriteBarrier.getElementStride());
             template(arrayRangeWriteBarrier.getDebug(), args).instantiate(providers.getMetaAccess(), arrayRangeWriteBarrier, DEFAULT_REPLACER, args);
         }
 
@@ -519,18 +527,18 @@
 
         public void lower(G1ArrayRangePreWriteBarrier arrayRangeWriteBarrier, HotSpotRegistersProvider registers, LoweringTool tool) {
             Arguments args = new Arguments(g1ArrayRangePreWriteBarrier, arrayRangeWriteBarrier.graph().getGuardsStage(), tool.getLoweringStage());
-            args.add("object", arrayRangeWriteBarrier.getObject());
-            args.add("startIndex", arrayRangeWriteBarrier.getStartIndex());
+            args.add("address", arrayRangeWriteBarrier.getAddress());
             args.add("length", arrayRangeWriteBarrier.getLength());
+            args.addConst("elementStride", arrayRangeWriteBarrier.getElementStride());
             args.addConst("threadRegister", registers.getThreadRegister());
             template(arrayRangeWriteBarrier.getDebug(), args).instantiate(providers.getMetaAccess(), arrayRangeWriteBarrier, DEFAULT_REPLACER, args);
         }
 
         public void lower(G1ArrayRangePostWriteBarrier arrayRangeWriteBarrier, HotSpotRegistersProvider registers, LoweringTool tool) {
             Arguments args = new Arguments(g1ArrayRangePostWriteBarrier, arrayRangeWriteBarrier.graph().getGuardsStage(), tool.getLoweringStage());
-            args.add("object", arrayRangeWriteBarrier.getObject());
-            args.add("startIndex", arrayRangeWriteBarrier.getStartIndex());
+            args.add("address", arrayRangeWriteBarrier.getAddress());
             args.add("length", arrayRangeWriteBarrier.getLength());
+            args.addConst("elementStride", arrayRangeWriteBarrier.getElementStride());
             args.addConst("threadRegister", registers.getThreadRegister());
             template(arrayRangeWriteBarrier.getDebug(), args).instantiate(providers.getMetaAccess(), arrayRangeWriteBarrier, DEFAULT_REPLACER, args);
         }
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/arraycopy/ArrayCopySnippets.java	Fri Feb 16 12:24:38 2018 -0800
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/replacements/arraycopy/ArrayCopySnippets.java	Fri Feb 16 13:49:07 2018 -0800
@@ -40,6 +40,7 @@
 import java.lang.reflect.Method;
 import java.util.EnumMap;
 
+import org.graalvm.collections.UnmodifiableEconomicMap;
 import org.graalvm.compiler.api.directives.GraalDirectives;
 import org.graalvm.compiler.api.replacements.Fold;
 import org.graalvm.compiler.api.replacements.Snippet;
@@ -76,7 +77,6 @@
 import org.graalvm.compiler.replacements.nodes.BasicArrayCopyNode;
 import org.graalvm.compiler.replacements.nodes.ExplodeLoopNode;
 import org.graalvm.compiler.word.Word;
-import org.graalvm.util.UnmodifiableEconomicMap;
 import org.graalvm.word.LocationIdentity;
 import org.graalvm.word.WordFactory;
 
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/stubs/Stub.java	Fri Feb 16 12:24:38 2018 -0800
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/stubs/Stub.java	Fri Feb 16 13:49:07 2018 -0800
@@ -34,6 +34,21 @@
 import java.util.ListIterator;
 import java.util.concurrent.atomic.AtomicInteger;
 
+import jdk.vm.ci.code.CodeCacheProvider;
+import jdk.vm.ci.code.InstalledCode;
+import jdk.vm.ci.code.Register;
+import jdk.vm.ci.code.RegisterConfig;
+import jdk.vm.ci.code.site.Call;
+import jdk.vm.ci.code.site.ConstantReference;
+import jdk.vm.ci.code.site.DataPatch;
+import jdk.vm.ci.code.site.Infopoint;
+import jdk.vm.ci.hotspot.HotSpotCompiledCode;
+import jdk.vm.ci.hotspot.HotSpotMetaspaceConstant;
+import jdk.vm.ci.meta.DefaultProfilingInfo;
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+import jdk.vm.ci.meta.TriState;
+
+import org.graalvm.collections.EconomicSet;
 import org.graalvm.compiler.code.CompilationResult;
 import org.graalvm.compiler.core.common.CompilationIdentifier;
 import org.graalvm.compiler.core.target.Backend;
@@ -54,21 +69,6 @@
 import org.graalvm.compiler.phases.PhaseSuite;
 import org.graalvm.compiler.phases.tiers.Suites;
 import org.graalvm.compiler.printer.GraalDebugHandlersFactory;
-import org.graalvm.util.EconomicSet;
-
-import jdk.vm.ci.code.CodeCacheProvider;
-import jdk.vm.ci.code.InstalledCode;
-import jdk.vm.ci.code.Register;
-import jdk.vm.ci.code.RegisterConfig;
-import jdk.vm.ci.code.site.Call;
-import jdk.vm.ci.code.site.ConstantReference;
-import jdk.vm.ci.code.site.DataPatch;
-import jdk.vm.ci.code.site.Infopoint;
-import jdk.vm.ci.hotspot.HotSpotCompiledCode;
-import jdk.vm.ci.hotspot.HotSpotMetaspaceConstant;
-import jdk.vm.ci.meta.DefaultProfilingInfo;
-import jdk.vm.ci.meta.ResolvedJavaMethod;
-import jdk.vm.ci.meta.TriState;
 
 //JaCoCo Exclude
 
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.java/src/org/graalvm/compiler/java/BciBlockMapping.java	Fri Feb 16 12:24:38 2018 -0800
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.java/src/org/graalvm/compiler/java/BciBlockMapping.java	Fri Feb 16 13:49:07 2018 -0800
@@ -86,6 +86,8 @@
 import java.util.List;
 import java.util.TreeSet;
 
+import org.graalvm.collections.EconomicMap;
+import org.graalvm.collections.Equivalence;
 import org.graalvm.compiler.bytecode.Bytecode;
 import org.graalvm.compiler.bytecode.BytecodeLookupSwitch;
 import org.graalvm.compiler.bytecode.BytecodeStream;
@@ -95,8 +97,6 @@
 import org.graalvm.compiler.core.common.PermanentBailoutException;
 import org.graalvm.compiler.debug.DebugContext;
 import org.graalvm.compiler.options.OptionValues;
-import org.graalvm.util.EconomicMap;
-import org.graalvm.util.Equivalence;
 
 import jdk.vm.ci.code.BytecodeFrame;
 import jdk.vm.ci.meta.ExceptionHandler;
@@ -415,9 +415,6 @@
     }
 
     public static class ExceptionDispatchBlock extends BciBlock {
-
-        private EconomicMap<ExceptionHandler, ExceptionDispatchBlock> exceptionDispatch = EconomicMap.create(Equivalence.DEFAULT);
-
         public ExceptionHandler handler;
         public int deoptBci;
     }
@@ -748,15 +745,6 @@
         }
     }
 
-    private EconomicMap<ExceptionHandler, ExceptionDispatchBlock> initialExceptionDispatch;
-
-    private EconomicMap<ExceptionHandler, ExceptionDispatchBlock> getInitialExceptionDispatch() {
-        if (initialExceptionDispatch == null) {
-            initialExceptionDispatch = EconomicMap.create(Equivalence.DEFAULT);
-        }
-        return initialExceptionDispatch;
-    }
-
     private ExceptionDispatchBlock handleExceptions(BciBlock[] blockMap, int bci) {
         ExceptionDispatchBlock lastHandler = null;
 
@@ -769,20 +757,17 @@
                     lastHandler = null;
                 }
 
-                EconomicMap<ExceptionHandler, ExceptionDispatchBlock> exceptionDispatch = lastHandler != null ? lastHandler.exceptionDispatch : getInitialExceptionDispatch();
-                ExceptionDispatchBlock curHandler = exceptionDispatch.get(h);
-                if (curHandler == null) {
-                    curHandler = new ExceptionDispatchBlock();
-                    blocksNotYetAssignedId++;
-                    curHandler.startBci = -1;
-                    curHandler.endBci = -1;
-                    curHandler.deoptBci = bci;
-                    curHandler.handler = h;
-                    curHandler.addSuccessor(blockMap[h.getHandlerBCI()]);
-                    if (lastHandler != null) {
-                        curHandler.addSuccessor(lastHandler);
-                    }
-                    exceptionDispatch.put(h, curHandler);
+                // We do not reuse exception dispatch blocks, because nested exception handlers
+                // might have problems reasoning about the correct frame state.
+                ExceptionDispatchBlock curHandler = new ExceptionDispatchBlock();
+                blocksNotYetAssignedId++;
+                curHandler.startBci = -1;
+                curHandler.endBci = -1;
+                curHandler.deoptBci = bci;
+                curHandler.handler = h;
+                curHandler.addSuccessor(blockMap[h.getHandlerBCI()]);
+                if (lastHandler != null) {
+                    curHandler.addSuccessor(lastHandler);
                 }
                 lastHandler = curHandler;
             }
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.java/src/org/graalvm/compiler/java/BytecodeParser.java	Fri Feb 16 12:24:38 2018 -0800
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.java/src/org/graalvm/compiler/java/BytecodeParser.java	Fri Feb 16 13:49:07 2018 -0800
@@ -265,6 +265,8 @@
 import java.util.Formatter;
 import java.util.List;
 
+import org.graalvm.collections.EconomicMap;
+import org.graalvm.collections.Equivalence;
 import org.graalvm.compiler.api.replacements.Snippet;
 import org.graalvm.compiler.bytecode.Bytecode;
 import org.graalvm.compiler.bytecode.BytecodeDisassembler;
@@ -278,9 +280,12 @@
 import org.graalvm.compiler.bytecode.ResolvedJavaMethodBytecode;
 import org.graalvm.compiler.bytecode.ResolvedJavaMethodBytecodeProvider;
 import org.graalvm.compiler.core.common.PermanentBailoutException;
+import org.graalvm.compiler.core.common.calc.CanonicalCondition;
 import org.graalvm.compiler.core.common.calc.Condition;
+import org.graalvm.compiler.core.common.calc.Condition.CanonicalizedCondition;
 import org.graalvm.compiler.core.common.calc.FloatConvert;
 import org.graalvm.compiler.core.common.spi.ConstantFieldProvider;
+import org.graalvm.compiler.core.common.type.IntegerStamp;
 import org.graalvm.compiler.core.common.type.ObjectStamp;
 import org.graalvm.compiler.core.common.type.Stamp;
 import org.graalvm.compiler.core.common.type.StampFactory;
@@ -343,8 +348,8 @@
 import org.graalvm.compiler.nodes.calc.AndNode;
 import org.graalvm.compiler.nodes.calc.CompareNode;
 import org.graalvm.compiler.nodes.calc.ConditionalNode;
+import org.graalvm.compiler.nodes.calc.FloatConvertNode;
 import org.graalvm.compiler.nodes.calc.FloatDivNode;
-import org.graalvm.compiler.nodes.calc.FloatConvertNode;
 import org.graalvm.compiler.nodes.calc.IntegerBelowNode;
 import org.graalvm.compiler.nodes.calc.IntegerEqualsNode;
 import org.graalvm.compiler.nodes.calc.IntegerLessThanNode;
@@ -408,8 +413,6 @@
 import org.graalvm.compiler.options.OptionValues;
 import org.graalvm.compiler.phases.OptimisticOptimizations;
 import org.graalvm.compiler.phases.util.ValueMergeUtil;
-import org.graalvm.util.EconomicMap;
-import org.graalvm.util.Equivalence;
 import org.graalvm.word.LocationIdentity;
 
 import jdk.vm.ci.code.BailoutException;
@@ -436,7 +439,6 @@
 import jdk.vm.ci.meta.ResolvedJavaType;
 import jdk.vm.ci.meta.Signature;
 import jdk.vm.ci.meta.TriState;
-import org.graalvm.compiler.core.common.type.IntegerStamp;
 
 /**
  * The {@code GraphBuilder} class parses the bytecode of a method and builds the IR graph.
@@ -577,10 +579,11 @@
                             // value on the stack on entry to an exception handler,
                             // namely the exception object.
                             assert frameState.rethrowException();
-                            ExceptionObjectNode exceptionObject = (ExceptionObjectNode) frameState.stackAt(0);
+                            ValueNode exceptionValue = frameState.stackAt(0);
+                            ExceptionObjectNode exceptionObject = (ExceptionObjectNode) GraphUtil.unproxify(exceptionValue);
                             FrameStateBuilder dispatchState = parser.frameState.copy();
                             dispatchState.clearStack();
-                            dispatchState.push(JavaKind.Object, exceptionObject);
+                            dispatchState.push(JavaKind.Object, exceptionValue);
                             dispatchState.setRethrowException(true);
                             FrameState newFrameState = dispatchState.create(parser.bci(), exceptionObject);
                             frameState.replaceAndDelete(newFrameState);
@@ -700,6 +703,12 @@
 
         assert code.getCode() != null : "method must contain bytecodes: " + method;
 
+        if (TraceBytecodeParserLevel.getValue(options) != 0) {
+            if (!Assertions.assertionsEnabled()) {
+                throw new IllegalArgumentException("A non-zero " + TraceBytecodeParserLevel.getName() + " value requires assertions to be enabled");
+            }
+        }
+
         if (graphBuilderConfig.insertFullInfopoints() && !parsingIntrinsic()) {
             lnt = code.getLineNumberTable();
             previousLineNumber = -1;
@@ -1893,7 +1902,7 @@
             LoadHubNode hub = graph.unique(new LoadHubNode(stampProvider, nonNullReceiver));
             LoadMethodNode actual = append(new LoadMethodNode(methodStamp, targetMethod, receiverType, method.getDeclaringClass(), hub));
             ConstantNode expected = graph.unique(ConstantNode.forConstant(methodStamp, targetMethod.getEncoding(), getMetaAccess()));
-            LogicNode compare = graph.addOrUniqueWithInputs(CompareNode.createCompareNode(constantReflection, metaAccess, options, null, Condition.EQ, actual, expected, NodeView.DEFAULT));
+            LogicNode compare = graph.addOrUniqueWithInputs(CompareNode.createCompareNode(constantReflection, metaAccess, options, null, CanonicalCondition.EQ, actual, expected, NodeView.DEFAULT));
 
             JavaTypeProfile profile = null;
             if (profilingInfo != null && this.optimisticOpts.useTypeCheckHints(getOptions())) {
@@ -2267,8 +2276,10 @@
     }
 
     protected void parseAndInlineCallee(ResolvedJavaMethod targetMethod, ValueNode[] args, IntrinsicContext calleeIntrinsicContext) {
+        FixedWithNextNode calleeBeforeUnwindNode = null;
+        ValueNode calleeUnwindValue = null;
+
         try (IntrinsicScope s = calleeIntrinsicContext != null && !parsingIntrinsic() ? new IntrinsicScope(this, targetMethod.getSignature().toParameterKinds(!targetMethod.isStatic()), args) : null) {
-
             BytecodeParser parser = graphBuilderInstance.createBytecodeParser(graph, this, targetMethod, INVOCATION_ENTRY_BCI, calleeIntrinsicContext);
             FrameStateBuilder startFrameState = new FrameStateBuilder(parser, parser.code, graph);
             if (!targetMethod.isStatic()) {
@@ -2315,13 +2326,25 @@
                 }
             }
 
-            FixedWithNextNode calleeBeforeUnwindNode = parser.getBeforeUnwindNode();
+            calleeBeforeUnwindNode = parser.getBeforeUnwindNode();
             if (calleeBeforeUnwindNode != null) {
-                ValueNode calleeUnwindValue = parser.getUnwindValue();
+                calleeUnwindValue = parser.getUnwindValue();
                 assert calleeUnwindValue != null;
-                calleeBeforeUnwindNode.setNext(handleException(calleeUnwindValue, bci(), false));
             }
         }
+
+        /*
+         * Method handleException will call createTarget, which wires this exception edge to the
+         * corresponding exception dispatch block in the caller. In the case where it wires to the
+         * caller's unwind block, any FrameState created meanwhile, e.g., FrameState for
+         * LoopExitNode, would be instantiated with AFTER_EXCEPTION_BCI. Such frame states should
+         * not be fixed by IntrinsicScope.close, as they denote the states of the caller. Thus, the
+         * following code should be placed outside the IntrinsicScope, so that correctly created
+         * FrameStates are not replaced.
+         */
+        if (calleeBeforeUnwindNode != null) {
+            calleeBeforeUnwindNode.setNext(handleException(calleeUnwindValue, bci(), false));
+        }
     }
 
     public MethodCallTargetNode createMethodCallTarget(InvokeKind invokeKind, ResolvedJavaMethod targetMethod, ValueNode[] args, StampPair returnStamp, JavaTypeProfile profile) {
@@ -2773,6 +2796,10 @@
             setCurrentFrameState(frameState);
             currentBlock = block;
 
+            if (block != blockMap.getUnwindBlock() && !(block instanceof ExceptionDispatchBlock)) {
+                frameState.setRethrowException(false);
+            }
+
             if (firstInstruction instanceof AbstractMergeNode) {
                 setMergeStateAfter(block, firstInstruction);
             }
@@ -2782,7 +2809,6 @@
             } else if (block instanceof ExceptionDispatchBlock) {
                 createExceptionDispatch((ExceptionDispatchBlock) block);
             } else {
-                frameState.setRethrowException(false);
                 iterateBytecodesForBlock(block);
             }
         }
@@ -3055,7 +3081,7 @@
     }
 
     private boolean traceState() {
-        if (debug.isLogEnabled() && TraceBytecodeParserLevel.getValue(options) >= TRACELEVEL_STATE) {
+        if (TraceBytecodeParserLevel.getValue(options) >= TRACELEVEL_STATE) {
             frameState.traceState();
         }
         return true;
@@ -3075,56 +3101,107 @@
 
         ValueNode a = x;
         ValueNode b = y;
+        BciBlock trueSuccessor = trueBlock;
+        BciBlock falseSuccessor = falseBlock;
+
+        CanonicalizedCondition canonicalizedCondition = cond.canonicalize();
 
         // Check whether the condition needs to mirror the operands.
-        if (cond.canonicalMirror()) {
+        if (canonicalizedCondition.mustMirror()) {
             a = y;
             b = x;
         }
+        if (canonicalizedCondition.mustNegate()) {
+            trueSuccessor = falseBlock;
+            falseSuccessor = trueBlock;
+        }
 
         // Create the logic node for the condition.
-        LogicNode condition = createLogicNode(cond, a, b);
-
-        // Check whether the condition needs to negate the result.
-        boolean negate = cond.canonicalNegate();
-        genIf(condition, negate, trueBlock, falseBlock);
-    }
-
-    protected void genIf(LogicNode conditionInput, boolean negateCondition, BciBlock trueBlockInput, BciBlock falseBlockInput) {
+        LogicNode condition = createLogicNode(canonicalizedCondition.getCanonicalCondition(), a, b);
+
+        double probability = -1;
+        if (condition instanceof IntegerEqualsNode) {
+            probability = extractInjectedProbability((IntegerEqualsNode) condition);
+            // the probability coming from here is about the actual condition
+        }
+
+        if (probability == -1) {
+            probability = getProfileProbability(canonicalizedCondition.mustNegate());
+        }
+
+        probability = clampProbability(probability);
+        genIf(condition, trueSuccessor, falseSuccessor, probability);
+    }
+
+    private double getProfileProbability(boolean negate) {
+        double probability;
+        if (profilingInfo == null) {
+            probability = 0.5;
+        } else {
+            assert assertAtIfBytecode();
+            probability = profilingInfo.getBranchTakenProbability(bci());
+            if (probability < 0) {
+                assert probability == -1 : "invalid probability";
+                debug.log("missing probability in %s at bci %d", code, bci());
+                probability = 0.5;
+            } else {
+                if (negate) {
+                    // the probability coming from profile is about the original condition
+                    probability = 1 - probability;
+                }
+            }
+        }
+        return probability;
+    }
+
+    private static double extractInjectedProbability(IntegerEqualsNode condition) {
+        // Propagate injected branch probability if any.
+        IntegerEqualsNode equalsNode = condition;
+        BranchProbabilityNode probabilityNode = null;
+        ValueNode other = null;
+        if (equalsNode.getX() instanceof BranchProbabilityNode) {
+            probabilityNode = (BranchProbabilityNode) equalsNode.getX();
+            other = equalsNode.getY();
+        } else if (equalsNode.getY() instanceof BranchProbabilityNode) {
+            probabilityNode = (BranchProbabilityNode) equalsNode.getY();
+            other = equalsNode.getX();
+        }
+
+        if (probabilityNode != null && probabilityNode.getProbability().isConstant() && other != null && other.isConstant()) {
+            double probabilityValue = probabilityNode.getProbability().asJavaConstant().asDouble();
+            return other.asJavaConstant().asInt() == 0 ? 1.0 - probabilityValue : probabilityValue;
+        }
+        return -1;
+    }
+
+    protected void genIf(LogicNode conditionInput, BciBlock trueBlockInput, BciBlock falseBlockInput, double probabilityInput) {
         BciBlock trueBlock = trueBlockInput;
         BciBlock falseBlock = falseBlockInput;
         LogicNode condition = conditionInput;
+        double probability = probabilityInput;
         FrameState stateBefore = null;
         ProfilingPlugin profilingPlugin = this.graphBuilderConfig.getPlugins().getProfilingPlugin();
         if (profilingPlugin != null && profilingPlugin.shouldProfile(this, method)) {
             stateBefore = frameState.create(bci(), getNonIntrinsicAncestor(), false, null, null);
         }
 
-        // Remove a logic negation node and fold it into the negate boolean.
-        boolean negate = negateCondition;
+        // Remove a logic negation node.
         if (condition instanceof LogicNegationNode) {
             LogicNegationNode logicNegationNode = (LogicNegationNode) condition;
-            negate = !negate;
+            BciBlock tmpBlock = trueBlock;
+            trueBlock = falseBlock;
+            falseBlock = tmpBlock;
+            probability = 1 - probability;
             condition = logicNegationNode.getValue();
         }
 
         if (condition instanceof LogicConstantNode) {
-            genConstantTargetIf(trueBlock, falseBlock, negate, condition);
+            genConstantTargetIf(trueBlock, falseBlock, condition);
         } else {
             if (condition.graph() == null) {
                 condition = genUnique(condition);
             }
 
-            // Need to get probability based on current bci.
-            double probability = branchProbability(condition);
-
-            if (negate) {
-                BciBlock tmpBlock = trueBlock;
-                trueBlock = falseBlock;
-                falseBlock = tmpBlock;
-                probability = 1 - probability;
-            }
-
             if (isNeverExecutedCode(probability)) {
                 append(new FixedGuardNode(condition, UnreachedCode, InvalidateReprofile, true));
                 if (profilingPlugin != null && profilingPlugin.shouldProfile(this, method)) {
@@ -3200,28 +3277,26 @@
         }
     }
 
-    private LogicNode createLogicNode(Condition cond, ValueNode a, ValueNode b) {
-        LogicNode condition;
+    private LogicNode createLogicNode(CanonicalCondition cond, ValueNode a, ValueNode b) {
         assert !a.getStackKind().isNumericFloat();
-        if (cond == Condition.EQ || cond == Condition.NE) {
-            if (a.getStackKind() == JavaKind.Object) {
-                condition = genObjectEquals(a, b);
-            } else {
-                condition = genIntegerEquals(a, b);
-            }
-        } else {
-            assert a.getStackKind() != JavaKind.Object && !cond.isUnsigned();
-            condition = genIntegerLessThan(a, b);
+        switch (cond) {
+            case EQ:
+                if (a.getStackKind() == JavaKind.Object) {
+                    return genObjectEquals(a, b);
+                } else {
+                    return genIntegerEquals(a, b);
+                }
+            case LT:
+                assert a.getStackKind() != JavaKind.Object;
+                return genIntegerLessThan(a, b);
+            default:
+                throw GraalError.shouldNotReachHere("Unexpected condition: " + cond);
         }
-        return condition;
-    }
-
-    private void genConstantTargetIf(BciBlock trueBlock, BciBlock falseBlock, boolean negate, LogicNode condition) {
+    }
+
+    private void genConstantTargetIf(BciBlock trueBlock, BciBlock falseBlock, LogicNode condition) {
         LogicConstantNode constantLogicNode = (LogicConstantNode) condition;
         boolean value = constantLogicNode.getValue();
-        if (negate) {
-            value = !value;
-        }
         BciBlock nextBlock = falseBlock;
         if (value) {
             nextBlock = trueBlock;
@@ -3775,7 +3850,13 @@
             BciBlock firstSucc = currentBlock.getSuccessor(0);
             BciBlock secondSucc = currentBlock.getSuccessor(1);
             if (firstSucc != secondSucc) {
-                genIf(instanceOfNode, value != Bytecodes.IFNE, firstSucc, secondSucc);
+                boolean negate = value != Bytecodes.IFNE;
+                if (negate) {
+                    BciBlock tmp = firstSucc;
+                    firstSucc = secondSucc;
+                    secondSucc = tmp;
+                }
+                genIf(instanceOfNode, firstSucc, secondSucc, getProfileProbability(negate));
             } else {
                 appendGoto(firstSucc);
             }
@@ -4263,47 +4344,12 @@
         return probability == 0 && optimisticOpts.removeNeverExecutedCode(getOptions());
     }
 
-    private double rawBranchProbability(LogicNode conditionInput) {
-        if (conditionInput instanceof IntegerEqualsNode) {
-            // Propagate injected branch probability if any.
-            IntegerEqualsNode condition = (IntegerEqualsNode) conditionInput;
-            BranchProbabilityNode injectedProbability = null;
-            ValueNode other = null;
-            if (condition.getX() instanceof BranchProbabilityNode) {
-                injectedProbability = (BranchProbabilityNode) condition.getX();
-                other = condition.getY();
-            } else if (condition.getY() instanceof BranchProbabilityNode) {
-                injectedProbability = (BranchProbabilityNode) condition.getY();
-                other = condition.getX();
-            }
-
-            if (injectedProbability != null && injectedProbability.getProbability().isConstant() && other != null && other.isConstant()) {
-                double probabilityValue = injectedProbability.getProbability().asJavaConstant().asDouble();
-                return other.asJavaConstant().asInt() == 0 ? 1.0 - probabilityValue : probabilityValue;
-            }
-        }
-
-        if (profilingInfo == null) {
-            return 0.5;
-        }
-        assert assertAtIfBytecode();
-
-        return profilingInfo.getBranchTakenProbability(bci());
-    }
-
-    protected double branchProbability(LogicNode conditionInput) {
-        double probability = rawBranchProbability(conditionInput);
-        if (probability < 0) {
-            assert probability == -1 : "invalid probability";
-            debug.log("missing probability in %s at bci %d", code, bci());
-            probability = 0.5;
-        }
-
+    private double clampProbability(double probability) {
         if (!optimisticOpts.removeNeverExecutedCode(getOptions())) {
             if (probability == 0) {
-                probability = 0.0000001;
+                return 0.0000001;
             } else if (probability == 1) {
-                probability = 0.999999;
+                return 0.999999;
             }
         }
         return probability;
@@ -4568,7 +4614,7 @@
     }
 
     protected boolean traceInstruction(int bci, int opcode, boolean blockStart) {
-        if (debug.isLogEnabled() && TraceBytecodeParserLevel.getValue(options) >= TRACELEVEL_INSTRUCTIONS) {
+        if (TraceBytecodeParserLevel.getValue(options) >= TRACELEVEL_INSTRUCTIONS) {
             traceInstructionHelper(bci, opcode, blockStart);
         }
         return true;
@@ -4589,7 +4635,7 @@
         if (!currentBlock.getJsrScope().isEmpty()) {
             sb.append(' ').append(currentBlock.getJsrScope());
         }
-        debug.log("%s", sb);
+        TTY.println("%s", sb);
     }
 
     @Override
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.java/src/org/graalvm/compiler/java/BytecodeParserOptions.java	Fri Feb 16 12:24:38 2018 -0800
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.java/src/org/graalvm/compiler/java/BytecodeParserOptions.java	Fri Feb 16 13:49:07 2018 -0800
@@ -34,7 +34,9 @@
  */
 public class BytecodeParserOptions {
     // @formatter:off
-    @Option(help = "The trace level for the bytecode parser used when building a graph from bytecode", type = OptionType.Debug)
+    @Option(help = "The trace level for the bytecode parser. A value of 1 enables instruction tracing " +
+                   "and any greater value emits a frame state trace just prior to an instruction trace. " +
+                   "This option requires assertions to be enabled.", type = OptionType.Debug)
     public static final OptionKey<Integer> TraceBytecodeParserLevel = new OptionKey<>(0);
 
     @Option(help = "Inlines trivial methods during bytecode parsing.", type = OptionType.Expert)
@@ -56,7 +58,7 @@
     public static final OptionKey<Boolean> TraceParserPlugins = new OptionKey<>(false);
 
     @Option(help = "Maximum depth when inlining during bytecode parsing.", type = OptionType.Debug)
-    public static final OptionKey<Integer> InlineDuringParsingMaxDepth = new OptionKey<>(10);
+    public static final OptionKey<Integer> InlineDuringParsingMaxDepth = new OptionKey<>(3);
 
     @Option(help = "When creating info points hide the methods of the substitutions.", type = OptionType.Debug)
     public static final OptionKey<Boolean> HideSubstitutionStates = new OptionKey<>(false);
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.java/src/org/graalvm/compiler/java/ComputeLoopFrequenciesClosure.java	Fri Feb 16 12:24:38 2018 -0800
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.java/src/org/graalvm/compiler/java/ComputeLoopFrequenciesClosure.java	Fri Feb 16 13:49:07 2018 -0800
@@ -22,8 +22,11 @@
  */
 package org.graalvm.compiler.java;
 
+import static org.graalvm.compiler.nodes.cfg.ControlFlowGraph.multiplyProbabilities;
+
 import java.util.List;
 
+import org.graalvm.collections.EconomicMap;
 import org.graalvm.compiler.nodes.AbstractBeginNode;
 import org.graalvm.compiler.nodes.AbstractMergeNode;
 import org.graalvm.compiler.nodes.ControlSplitNode;
@@ -34,9 +37,6 @@
 import org.graalvm.compiler.nodes.cfg.ControlFlowGraph;
 import org.graalvm.compiler.phases.Phase;
 import org.graalvm.compiler.phases.graph.ReentrantNodeIterator;
-import org.graalvm.util.EconomicMap;
-
-import static org.graalvm.compiler.nodes.cfg.ControlFlowGraph.multiplyProbabilities;
 
 public final class ComputeLoopFrequenciesClosure extends ReentrantNodeIterator.NodeIteratorClosure<Double> {
 
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.java/src/org/graalvm/compiler/java/FrameStateBuilder.java	Fri Feb 16 12:24:38 2018 -0800
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.java/src/org/graalvm/compiler/java/FrameStateBuilder.java	Fri Feb 16 13:49:07 2018 -0800
@@ -47,6 +47,7 @@
 import org.graalvm.compiler.core.common.type.StampFactory;
 import org.graalvm.compiler.core.common.type.StampPair;
 import org.graalvm.compiler.debug.DebugContext;
+import org.graalvm.compiler.debug.TTY;
 import org.graalvm.compiler.graph.NodeSourcePosition;
 import org.graalvm.compiler.java.BciBlockMapping.BciBlock;
 import org.graalvm.compiler.nodeinfo.Verbosity;
@@ -999,15 +1000,14 @@
     }
 
     public void traceState() {
-        DebugContext debug = graph.getDebug();
-        debug.log("|   state [nr locals = %d, stack depth = %d, method = %s]", localsSize(), stackSize(), getMethod());
+        TTY.println("|   state [nr locals = %d, stack depth = %d, method = %s]", localsSize(), stackSize(), getMethod());
         for (int i = 0; i < localsSize(); ++i) {
             ValueNode value = locals[i];
-            debug.log("|   local[%d] = %-8s : %s", i, value == null ? "bogus" : value == TWO_SLOT_MARKER ? "second" : value.getStackKind().getJavaName(), value);
+            TTY.println("|   local[%d] = %-8s : %s", i, value == null ? "bogus" : value == TWO_SLOT_MARKER ? "second" : value.getStackKind().getJavaName(), value);
         }
         for (int i = 0; i < stackSize(); ++i) {
             ValueNode value = stack[i];
-            debug.log("|   stack[%d] = %-8s : %s", i, value == null ? "bogus" : value == TWO_SLOT_MARKER ? "second" : value.getStackKind().getJavaName(), value);
+            TTY.println("|   stack[%d] = %-8s : %s", i, value == null ? "bogus" : value == TWO_SLOT_MARKER ? "second" : value.getStackKind().getJavaName(), value);
         }
     }
 }
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.aarch64/src/org/graalvm/compiler/lir/aarch64/AArch64ArrayEqualsOp.java	Fri Feb 16 12:24:38 2018 -0800
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.aarch64/src/org/graalvm/compiler/lir/aarch64/AArch64ArrayEqualsOp.java	Fri Feb 16 13:49:07 2018 -0800
@@ -26,9 +26,6 @@
 import static jdk.vm.ci.code.ValueUtil.asRegister;
 import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.REG;
 
-import java.lang.reflect.Array;
-import java.lang.reflect.Field;
-
 import org.graalvm.compiler.asm.Label;
 import org.graalvm.compiler.asm.aarch64.AArch64Address;
 import org.graalvm.compiler.asm.aarch64.AArch64Assembler.ConditionFlag;
@@ -43,7 +40,6 @@
 import jdk.vm.ci.code.Register;
 import jdk.vm.ci.meta.JavaKind;
 import jdk.vm.ci.meta.Value;
-import sun.misc.Unsafe;
 
 /**
  * Emits code which compares two arrays of the same length. If the CPU supports any vector
@@ -72,9 +68,8 @@
         assert !kind.isNumericFloat() : "Float arrays comparison (bitwise_equal || both_NaN) isn't supported";
         this.kind = kind;
 
-        Class<?> arrayClass = Array.newInstance(kind.toJavaClass(), 0).getClass();
-        this.arrayBaseOffset = UNSAFE.arrayBaseOffset(arrayClass);
-        this.arrayIndexScale = UNSAFE.arrayIndexScale(arrayClass);
+        this.arrayBaseOffset = tool.getProviders().getArrayOffsetProvider().arrayBaseOffset(kind);
+        this.arrayIndexScale = tool.getProviders().getArrayOffsetProvider().arrayScalingFactor(kind);
 
         this.resultValue = result;
         this.array1Value = array1;
@@ -218,20 +213,4 @@
         masm.bind(end);
         masm.mov(64, rscratch1, zr);
     }
-
-    private static final Unsafe UNSAFE = initUnsafe();
-
-    private static Unsafe initUnsafe() {
-        try {
-            return Unsafe.getUnsafe();
-        } catch (SecurityException se) {
-            try {
-                Field theUnsafe = Unsafe.class.getDeclaredField("theUnsafe");
-                theUnsafe.setAccessible(true);
-                return (Unsafe) theUnsafe.get(Unsafe.class);
-            } catch (Exception e) {
-                throw new RuntimeException("exception while trying to get Unsafe", e);
-            }
-        }
-    }
 }
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.amd64/src/org/graalvm/compiler/lir/amd64/AMD64ArrayEqualsOp.java	Fri Feb 16 12:24:38 2018 -0800
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.amd64/src/org/graalvm/compiler/lir/amd64/AMD64ArrayEqualsOp.java	Fri Feb 16 13:49:07 2018 -0800
@@ -22,12 +22,9 @@
  */
 package org.graalvm.compiler.lir.amd64;
 
+import static jdk.vm.ci.code.ValueUtil.asRegister;
 import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.ILLEGAL;
 import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.REG;
-import static jdk.vm.ci.code.ValueUtil.asRegister;
-
-import java.lang.reflect.Array;
-import java.lang.reflect.Field;
 
 import org.graalvm.compiler.asm.Label;
 import org.graalvm.compiler.asm.amd64.AMD64Address;
@@ -50,7 +47,6 @@
 import jdk.vm.ci.code.TargetDescription;
 import jdk.vm.ci.meta.JavaKind;
 import jdk.vm.ci.meta.Value;
-import sun.misc.Unsafe;
 
 /**
  * Emits code which compares two arrays of the same length. If the CPU supports any vector
@@ -83,9 +79,8 @@
         super(TYPE);
         this.kind = kind;
 
-        Class<?> arrayClass = Array.newInstance(kind.toJavaClass(), 0).getClass();
-        this.arrayBaseOffset = UNSAFE.arrayBaseOffset(arrayClass);
-        this.arrayIndexScale = UNSAFE.arrayIndexScale(arrayClass);
+        this.arrayBaseOffset = tool.getProviders().getArrayOffsetProvider().arrayBaseOffset(kind);
+        this.arrayIndexScale = tool.getProviders().getArrayOffsetProvider().arrayScalingFactor(kind);
 
         this.resultValue = result;
         this.array1Value = array1;
@@ -531,20 +526,4 @@
         // Floats within the range are equal, revert change to the register index
         masm.subq(index, range);
     }
-
-    private static final Unsafe UNSAFE = initUnsafe();
-
-    private static Unsafe initUnsafe() {
-        try {
-            return Unsafe.getUnsafe();
-        } catch (SecurityException se) {
-            try {
-                Field theUnsafe = Unsafe.class.getDeclaredField("theUnsafe");
-                theUnsafe.setAccessible(true);
-                return (Unsafe) theUnsafe.get(Unsafe.class);
-            } catch (Exception e) {
-                throw new RuntimeException("exception while trying to get Unsafe", e);
-            }
-        }
-    }
 }
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.amd64/src/org/graalvm/compiler/lir/amd64/AMD64Call.java	Fri Feb 16 12:24:38 2018 -0800
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.amd64/src/org/graalvm/compiler/lir/amd64/AMD64Call.java	Fri Feb 16 13:49:07 2018 -0800
@@ -101,6 +101,10 @@
         public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) {
             directCall(crb, masm, callTarget, null, true, state);
         }
+
+        public int emitCall(CompilationResultBuilder crb, AMD64MacroAssembler masm) {
+            return directCall(crb, masm, callTarget, null, true, state);
+        }
     }
 
     @Opcode("CALL_INDIRECT")
@@ -183,23 +187,27 @@
         }
     }
 
-    public static void directCall(CompilationResultBuilder crb, AMD64MacroAssembler masm, InvokeTarget callTarget, Register scratch, boolean align, LIRFrameState info) {
+    public static int directCall(CompilationResultBuilder crb, AMD64MacroAssembler masm, InvokeTarget callTarget, Register scratch, boolean align, LIRFrameState info) {
         if (align) {
             emitAlignmentForDirectCall(crb, masm);
         }
         int before = masm.position();
+        int callPCOffset;
         if (scratch != null) {
             // offset might not fit a 32-bit immediate, generate an
             // indirect call with a 64-bit immediate
             masm.movq(scratch, 0L);
+            callPCOffset = masm.position();
             masm.call(scratch);
         } else {
+            callPCOffset = masm.position();
             masm.call();
         }
         int after = masm.position();
         crb.recordDirectCall(before, after, callTarget, info);
         crb.recordExceptionHandlers(after, info);
         masm.ensureUniquePC();
+        return callPCOffset;
     }
 
     protected static void emitAlignmentForDirectCall(CompilationResultBuilder crb, AMD64MacroAssembler masm) {
@@ -228,12 +236,13 @@
         masm.ensureUniquePC();
     }
 
-    public static void indirectCall(CompilationResultBuilder crb, AMD64MacroAssembler masm, Register dst, InvokeTarget callTarget, LIRFrameState info) {
+    public static int indirectCall(CompilationResultBuilder crb, AMD64MacroAssembler masm, Register dst, InvokeTarget callTarget, LIRFrameState info) {
         int before = masm.position();
         masm.call(dst);
         int after = masm.position();
         crb.recordIndirectCall(before, after, callTarget, info);
         crb.recordExceptionHandlers(after, info);
         masm.ensureUniquePC();
+        return before;
     }
 }
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.amd64/src/org/graalvm/compiler/lir/amd64/AMD64Move.java	Fri Feb 16 12:24:38 2018 -0800
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.amd64/src/org/graalvm/compiler/lir/amd64/AMD64Move.java	Fri Feb 16 13:49:07 2018 -0800
@@ -25,6 +25,7 @@
 import static org.graalvm.compiler.asm.amd64.AMD64Assembler.ConditionFlag.Equal;
 import static org.graalvm.compiler.core.common.GraalOptions.GeneratePIC;
 import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.COMPOSITE;
+import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.CONST;
 import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.HINT;
 import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.ILLEGAL;
 import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.REG;
@@ -755,17 +756,18 @@
         }
     }
 
-    public abstract static class Pointer extends AMD64LIRInstruction {
+    public abstract static class PointerCompressionOp extends AMD64LIRInstruction {
         protected final LIRKindTool lirKindTool;
         protected final CompressEncoding encoding;
         protected final boolean nonNull;
 
         @Def({REG, HINT}) private AllocatableValue result;
-        @Use({REG}) private AllocatableValue input;
+        @Use({REG, CONST}) private Value input;
         @Alive({REG, ILLEGAL}) private AllocatableValue baseRegister;
 
-        protected Pointer(LIRInstructionClass<? extends Pointer> type, AllocatableValue result, AllocatableValue input, AllocatableValue baseRegister, CompressEncoding encoding, boolean nonNull,
-                        LIRKindTool lirKindTool) {
+        protected PointerCompressionOp(LIRInstructionClass<? extends PointerCompressionOp> type, AllocatableValue result, Value input,
+                        AllocatableValue baseRegister, CompressEncoding encoding, boolean nonNull, LIRKindTool lirKindTool) {
+
             super(type);
             this.result = result;
             this.input = input;
@@ -779,8 +781,12 @@
             return GeneratePIC.getValue(crb.getOptions()) || encoding.hasBase();
         }
 
-        protected final Register getResultRegister() {
-            return asRegister(result);
+        public final Value getInput() {
+            return input;
+        }
+
+        public final AllocatableValue getResult() {
+            return result;
         }
 
         protected final Register getBaseRegister() {
@@ -796,18 +802,24 @@
         }
     }
 
-    public static final class CompressPointer extends Pointer {
-        public static final LIRInstructionClass<CompressPointer> TYPE = LIRInstructionClass.create(CompressPointer.class);
+    public static class CompressPointerOp extends PointerCompressionOp {
+        public static final LIRInstructionClass<CompressPointerOp> TYPE = LIRInstructionClass.create(CompressPointerOp.class);
 
-        public CompressPointer(AllocatableValue result, AllocatableValue input, AllocatableValue baseRegister, CompressEncoding encoding, boolean nonNull, LIRKindTool lirKindTool) {
-            super(TYPE, result, input, baseRegister, encoding, nonNull, lirKindTool);
+        public CompressPointerOp(AllocatableValue result, Value input, AllocatableValue baseRegister, CompressEncoding encoding, boolean nonNull, LIRKindTool lirKindTool) {
+            this(TYPE, result, input, baseRegister, encoding, nonNull, lirKindTool);
+        }
+
+        protected CompressPointerOp(LIRInstructionClass<? extends PointerCompressionOp> type, AllocatableValue result, Value input,
+                        AllocatableValue baseRegister, CompressEncoding encoding, boolean nonNull, LIRKindTool lirKindTool) {
+
+            super(type, result, input, baseRegister, encoding, nonNull, lirKindTool);
         }
 
         @Override
         public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) {
             move(lirKindTool.getObjectKind(), crb, masm);
 
-            Register resReg = getResultRegister();
+            Register resReg = asRegister(getResult());
             if (hasBase(crb)) {
                 Register baseReg = getBaseRegister();
                 if (!nonNull) {
@@ -824,18 +836,24 @@
         }
     }
 
-    public static final class UncompressPointer extends Pointer {
-        public static final LIRInstructionClass<UncompressPointer> TYPE = LIRInstructionClass.create(UncompressPointer.class);
+    public static class UncompressPointerOp extends PointerCompressionOp {
+        public static final LIRInstructionClass<UncompressPointerOp> TYPE = LIRInstructionClass.create(UncompressPointerOp.class);
 
-        public UncompressPointer(AllocatableValue result, AllocatableValue input, AllocatableValue baseRegister, CompressEncoding encoding, boolean nonNull, LIRKindTool lirKindTool) {
-            super(TYPE, result, input, baseRegister, encoding, nonNull, lirKindTool);
+        public UncompressPointerOp(AllocatableValue result, Value input, AllocatableValue baseRegister, CompressEncoding encoding, boolean nonNull, LIRKindTool lirKindTool) {
+            this(TYPE, result, input, baseRegister, encoding, nonNull, lirKindTool);
+        }
+
+        protected UncompressPointerOp(LIRInstructionClass<? extends PointerCompressionOp> type, AllocatableValue result, Value input,
+                        AllocatableValue baseRegister, CompressEncoding encoding, boolean nonNull, LIRKindTool lirKindTool) {
+
+            super(type, result, input, baseRegister, encoding, nonNull, lirKindTool);
         }
 
         @Override
         public void emitCode(CompilationResultBuilder crb, AMD64MacroAssembler masm) {
             move(lirKindTool.getNarrowOopKind(), crb, masm);
 
-            Register resReg = getResultRegister();
+            Register resReg = asRegister(getResult());
             int shift = getShift();
             if (shift != 0) {
                 masm.shlq(resReg, shift);
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.amd64/src/org/graalvm/compiler/lir/amd64/AMD64SaveRegistersOp.java	Fri Feb 16 12:24:38 2018 -0800
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.amd64/src/org/graalvm/compiler/lir/amd64/AMD64SaveRegistersOp.java	Fri Feb 16 13:49:07 2018 -0800
@@ -22,11 +22,13 @@
  */
 package org.graalvm.compiler.lir.amd64;
 
-import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.STACK;
 import static jdk.vm.ci.code.ValueUtil.asStackSlot;
 import static jdk.vm.ci.code.ValueUtil.isStackSlot;
+import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.STACK;
 
 import java.util.Arrays;
+
+import org.graalvm.collections.EconomicSet;
 import org.graalvm.compiler.asm.amd64.AMD64MacroAssembler;
 import org.graalvm.compiler.lir.LIRInstructionClass;
 import org.graalvm.compiler.lir.LIRValueUtil;
@@ -34,7 +36,6 @@
 import org.graalvm.compiler.lir.StandardOp.SaveRegistersOp;
 import org.graalvm.compiler.lir.asm.CompilationResultBuilder;
 import org.graalvm.compiler.lir.framemap.FrameMap;
-import org.graalvm.util.EconomicSet;
 
 import jdk.vm.ci.amd64.AMD64Kind;
 import jdk.vm.ci.code.Register;
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.amd64/src/org/graalvm/compiler/lir/amd64/AMD64ZapRegistersOp.java	Fri Feb 16 12:24:38 2018 -0800
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.amd64/src/org/graalvm/compiler/lir/amd64/AMD64ZapRegistersOp.java	Fri Feb 16 13:49:07 2018 -0800
@@ -24,13 +24,13 @@
 
 import static org.graalvm.compiler.lir.amd64.AMD64SaveRegistersOp.prune;
 
+import org.graalvm.collections.EconomicSet;
 import org.graalvm.compiler.asm.amd64.AMD64MacroAssembler;
 import org.graalvm.compiler.lir.LIRInstructionClass;
 import org.graalvm.compiler.lir.Opcode;
 import org.graalvm.compiler.lir.StandardOp.SaveRegistersOp;
 import org.graalvm.compiler.lir.asm.CompilationResultBuilder;
 import org.graalvm.compiler.lir.framemap.FrameMap;
-import org.graalvm.util.EconomicSet;
 
 import jdk.vm.ci.code.Register;
 import jdk.vm.ci.code.RegisterSaveLayout;
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.sparc/src/org/graalvm/compiler/lir/sparc/SPARCArrayEqualsOp.java	Fri Feb 16 12:24:38 2018 -0800
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.sparc/src/org/graalvm/compiler/lir/sparc/SPARCArrayEqualsOp.java	Fri Feb 16 13:49:07 2018 -0800
@@ -36,9 +36,6 @@
 import static org.graalvm.compiler.asm.sparc.SPARCAssembler.ConditionFlag.NotEqual;
 import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.REG;
 
-import java.lang.reflect.Array;
-import java.lang.reflect.Field;
-
 import org.graalvm.compiler.asm.Label;
 import org.graalvm.compiler.asm.sparc.SPARCAddress;
 import org.graalvm.compiler.asm.sparc.SPARCMacroAssembler;
@@ -52,7 +49,6 @@
 import jdk.vm.ci.meta.AllocatableValue;
 import jdk.vm.ci.meta.JavaKind;
 import jdk.vm.ci.sparc.SPARCKind;
-import sun.misc.Unsafe;
 
 /**
  * Emits code which compares two arrays of the same length.
@@ -82,9 +78,8 @@
         assert !kind.isNumericFloat() : "Float arrays comparison (bitwise_equal || both_NaN) isn't supported";
         this.kind = kind;
 
-        Class<?> arrayClass = Array.newInstance(kind.toJavaClass(), 0).getClass();
-        this.arrayBaseOffset = UNSAFE.arrayBaseOffset(arrayClass);
-        this.arrayIndexScale = UNSAFE.arrayIndexScale(arrayClass);
+        this.arrayBaseOffset = tool.getProviders().getArrayOffsetProvider().arrayBaseOffset(kind);
+        this.arrayIndexScale = tool.getProviders().getArrayOffsetProvider().arrayScalingFactor(kind);
 
         this.resultValue = result;
         this.array1Value = array1;
@@ -247,20 +242,4 @@
             }
         }
     }
-
-    private static final Unsafe UNSAFE = initUnsafe();
-
-    private static Unsafe initUnsafe() {
-        try {
-            return Unsafe.getUnsafe();
-        } catch (SecurityException se) {
-            try {
-                Field theUnsafe = Unsafe.class.getDeclaredField("theUnsafe");
-                theUnsafe.setAccessible(true);
-                return (Unsafe) theUnsafe.get(Unsafe.class);
-            } catch (Exception e) {
-                throw new RuntimeException("exception while trying to get Unsafe", e);
-            }
-        }
-    }
 }
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.sparc/src/org/graalvm/compiler/lir/sparc/SPARCControlFlow.java	Fri Feb 16 12:24:38 2018 -0800
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.sparc/src/org/graalvm/compiler/lir/sparc/SPARCControlFlow.java	Fri Feb 16 13:49:07 2018 -0800
@@ -78,6 +78,8 @@
 import java.util.EnumSet;
 import java.util.List;
 
+import org.graalvm.collections.EconomicMap;
+import org.graalvm.collections.Equivalence;
 import org.graalvm.compiler.asm.Assembler;
 import org.graalvm.compiler.asm.Assembler.LabelHint;
 import org.graalvm.compiler.asm.Label;
@@ -98,8 +100,6 @@
 import org.graalvm.compiler.lir.SwitchStrategy.BaseSwitchClosure;
 import org.graalvm.compiler.lir.Variable;
 import org.graalvm.compiler.lir.asm.CompilationResultBuilder;
-import org.graalvm.util.EconomicMap;
-import org.graalvm.util.Equivalence;
 
 import jdk.vm.ci.code.Register;
 import jdk.vm.ci.meta.AllocatableValue;
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.sparc/src/org/graalvm/compiler/lir/sparc/SPARCSaveRegistersOp.java	Fri Feb 16 12:24:38 2018 -0800
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.sparc/src/org/graalvm/compiler/lir/sparc/SPARCSaveRegistersOp.java	Fri Feb 16 13:49:07 2018 -0800
@@ -22,12 +22,14 @@
  */
 package org.graalvm.compiler.lir.sparc;
 
+import static jdk.vm.ci.code.ValueUtil.asStackSlot;
+import static jdk.vm.ci.code.ValueUtil.isStackSlot;
 import static org.graalvm.compiler.lir.LIRInstruction.OperandFlag.STACK;
 import static org.graalvm.compiler.lir.sparc.SPARCDelayedControlTransfer.DUMMY;
-import static jdk.vm.ci.code.ValueUtil.asStackSlot;
-import static jdk.vm.ci.code.ValueUtil.isStackSlot;
 
 import java.util.Arrays;
+
+import org.graalvm.collections.EconomicSet;
 import org.graalvm.compiler.asm.sparc.SPARCAddress;
 import org.graalvm.compiler.asm.sparc.SPARCMacroAssembler;
 import org.graalvm.compiler.lir.LIRInstructionClass;
@@ -36,7 +38,6 @@
 import org.graalvm.compiler.lir.StandardOp.SaveRegistersOp;
 import org.graalvm.compiler.lir.asm.CompilationResultBuilder;
 import org.graalvm.compiler.lir.framemap.FrameMap;
-import org.graalvm.util.EconomicSet;
 
 import jdk.vm.ci.code.Register;
 import jdk.vm.ci.code.RegisterSaveLayout;
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.test/src/org/graalvm/compiler/lir/test/alloc/trace/TraceGlobalMoveResolutionMappingTest.java	Fri Feb 16 12:24:38 2018 -0800
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir.test/src/org/graalvm/compiler/lir/test/alloc/trace/TraceGlobalMoveResolutionMappingTest.java	Fri Feb 16 13:49:07 2018 -0800
@@ -27,15 +27,14 @@
 
 import java.util.HashSet;
 
+import org.graalvm.collections.Pair;
+import org.graalvm.compiler.core.common.LIRKind;
+import org.graalvm.compiler.lir.alloc.trace.ShadowedRegisterValue;
+import org.graalvm.compiler.lir.alloc.trace.TraceGlobalMoveResolutionPhase;
 import org.junit.Before;
 import org.junit.Ignore;
 import org.junit.Test;
 
-import org.graalvm.compiler.core.common.LIRKind;
-import org.graalvm.compiler.lir.alloc.trace.ShadowedRegisterValue;
-import org.graalvm.compiler.lir.alloc.trace.TraceGlobalMoveResolutionPhase;
-import org.graalvm.util.Pair;
-
 import jdk.vm.ci.code.Register;
 import jdk.vm.ci.code.Register.RegisterCategory;
 import jdk.vm.ci.code.RegisterValue;
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/LIRIntrospection.java	Fri Feb 16 12:24:38 2018 -0800
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/LIRIntrospection.java	Fri Feb 16 13:49:07 2018 -0800
@@ -33,14 +33,14 @@
 import java.util.Arrays;
 import java.util.EnumSet;
 
+import org.graalvm.collections.EconomicMap;
+import org.graalvm.collections.Equivalence;
+import org.graalvm.collections.MapCursor;
 import org.graalvm.compiler.core.common.FieldIntrospection;
 import org.graalvm.compiler.core.common.Fields;
 import org.graalvm.compiler.core.common.FieldsScanner;
 import org.graalvm.compiler.lir.LIRInstruction.OperandFlag;
 import org.graalvm.compiler.lir.LIRInstruction.OperandMode;
-import org.graalvm.util.Equivalence;
-import org.graalvm.util.EconomicMap;
-import org.graalvm.util.MapCursor;
 
 import jdk.vm.ci.code.RegisterValue;
 import jdk.vm.ci.code.StackSlot;
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/RedundantMoveElimination.java	Fri Feb 16 12:24:38 2018 -0800
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/RedundantMoveElimination.java	Fri Feb 16 13:49:07 2018 -0800
@@ -30,7 +30,8 @@
 import java.util.Collections;
 import java.util.EnumSet;
 
-import jdk.vm.ci.code.RegisterConfig;
+import org.graalvm.collections.EconomicMap;
+import org.graalvm.collections.Equivalence;
 import org.graalvm.compiler.core.common.LIRKind;
 import org.graalvm.compiler.core.common.cfg.AbstractBlockBase;
 import org.graalvm.compiler.debug.CounterKey;
@@ -43,11 +44,10 @@
 import org.graalvm.compiler.lir.framemap.FrameMap;
 import org.graalvm.compiler.lir.gen.LIRGenerationResult;
 import org.graalvm.compiler.lir.phases.PostAllocationOptimizationPhase;
-import org.graalvm.util.EconomicMap;
-import org.graalvm.util.Equivalence;
 
 import jdk.vm.ci.code.Register;
 import jdk.vm.ci.code.RegisterArray;
+import jdk.vm.ci.code.RegisterConfig;
 import jdk.vm.ci.code.RegisterValue;
 import jdk.vm.ci.code.StackSlot;
 import jdk.vm.ci.code.TargetDescription;
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/StandardOp.java	Fri Feb 16 12:24:38 2018 -0800
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/StandardOp.java	Fri Feb 16 13:49:07 2018 -0800
@@ -31,12 +31,12 @@
 import java.util.ArrayList;
 import java.util.EnumSet;
 
+import org.graalvm.collections.EconomicSet;
 import org.graalvm.compiler.asm.Label;
 import org.graalvm.compiler.core.common.cfg.AbstractBlockBase;
 import org.graalvm.compiler.debug.GraalError;
 import org.graalvm.compiler.lir.asm.CompilationResultBuilder;
 import org.graalvm.compiler.lir.framemap.FrameMap;
-import org.graalvm.util.EconomicSet;
 
 import jdk.vm.ci.code.Register;
 import jdk.vm.ci.code.RegisterSaveLayout;
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/lsra/LinearScan.java	Fri Feb 16 12:24:38 2018 -0800
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/lsra/LinearScan.java	Fri Feb 16 13:49:07 2018 -0800
@@ -35,6 +35,7 @@
 import java.util.BitSet;
 import java.util.EnumSet;
 
+import org.graalvm.collections.Pair;
 import org.graalvm.compiler.core.common.LIRKind;
 import org.graalvm.compiler.core.common.alloc.RegisterAllocationConfig;
 import org.graalvm.compiler.core.common.cfg.AbstractBlockBase;
@@ -60,7 +61,6 @@
 import org.graalvm.compiler.options.OptionKey;
 import org.graalvm.compiler.options.OptionType;
 import org.graalvm.compiler.options.OptionValues;
-import org.graalvm.util.Pair;
 
 import jdk.vm.ci.code.Register;
 import jdk.vm.ci.code.RegisterArray;
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/lsra/LinearScanLifetimeAnalysisPhase.java	Fri Feb 16 12:24:38 2018 -0800
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/lsra/LinearScanLifetimeAnalysisPhase.java	Fri Feb 16 13:49:07 2018 -0800
@@ -35,6 +35,8 @@
 import java.util.BitSet;
 import java.util.EnumSet;
 
+import org.graalvm.collections.EconomicSet;
+import org.graalvm.collections.Equivalence;
 import org.graalvm.compiler.core.common.LIRKind;
 import org.graalvm.compiler.core.common.PermanentBailoutException;
 import org.graalvm.compiler.core.common.alloc.ComputeBlockOrder;
@@ -56,8 +58,6 @@
 import org.graalvm.compiler.lir.alloc.lsra.LinearScan.BlockData;
 import org.graalvm.compiler.lir.gen.LIRGenerationResult;
 import org.graalvm.compiler.lir.phases.AllocationPhase.AllocationContext;
-import org.graalvm.util.EconomicSet;
-import org.graalvm.util.Equivalence;
 
 import jdk.vm.ci.code.Register;
 import jdk.vm.ci.code.RegisterArray;
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/lsra/LinearScanRegisterAllocationPhase.java	Fri Feb 16 12:24:38 2018 -0800
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/lsra/LinearScanRegisterAllocationPhase.java	Fri Feb 16 13:49:07 2018 -0800
@@ -22,10 +22,10 @@
  */
 package org.graalvm.compiler.lir.alloc.lsra;
 
+import org.graalvm.collections.Pair;
 import org.graalvm.compiler.debug.Indent;
 import org.graalvm.compiler.lir.gen.LIRGenerationResult;
 import org.graalvm.compiler.lir.phases.AllocationPhase.AllocationContext;
-import org.graalvm.util.Pair;
 
 import jdk.vm.ci.code.TargetDescription;
 
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/lsra/MoveResolver.java	Fri Feb 16 12:24:38 2018 -0800
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/alloc/lsra/MoveResolver.java	Fri Feb 16 13:49:07 2018 -0800
@@ -28,6 +28,8 @@
 
 import java.util.ArrayList;
 
+import org.graalvm.collections.EconomicSet;
+import org.graalvm.collections.Equivalence;
 import org.graalvm.compiler.core.common.LIRKind;
 import org.graalvm.compiler.debug.CounterKey;
 import org.graalvm.compiler.debug.DebugContext;
@@ -37,8 +39,6 @@
 import org.graalvm.compiler.lir.LIRInstruction;
 import org.graalvm.compiler.lir.LIRValueUtil;
 import org.graalvm.compiler.lir.gen.LIRGenerationResult;
-import org.graalvm.util.EconomicSet;
-import org.graalvm.util.Equivalence;
 
 import jdk.vm.ci.meta.AllocatableValue;
 import jdk.vm.ci.meta.Constant;
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/asm/CompilationResultBuilder.java	Fri Feb 16 12:24:38 2018 -0800
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/asm/CompilationResultBuilder.java	Fri Feb 16 13:49:07 2018 -0800
@@ -32,13 +32,15 @@
 import java.util.List;
 import java.util.function.Consumer;
 
+import org.graalvm.collections.EconomicMap;
+import org.graalvm.collections.Equivalence;
 import org.graalvm.compiler.asm.AbstractAddress;
 import org.graalvm.compiler.asm.Assembler;
-import org.graalvm.compiler.core.common.NumUtil;
 import org.graalvm.compiler.code.CompilationResult;
 import org.graalvm.compiler.code.CompilationResult.CodeAnnotation;
 import org.graalvm.compiler.code.DataSection.Data;
 import org.graalvm.compiler.code.DataSection.RawData;
+import org.graalvm.compiler.core.common.NumUtil;
 import org.graalvm.compiler.core.common.cfg.AbstractBlockBase;
 import org.graalvm.compiler.core.common.spi.ForeignCallsProvider;
 import org.graalvm.compiler.core.common.type.DataPointerConstant;
@@ -55,8 +57,6 @@
 import org.graalvm.compiler.options.OptionKey;
 import org.graalvm.compiler.options.OptionType;
 import org.graalvm.compiler.options.OptionValues;
-import org.graalvm.util.EconomicMap;
-import org.graalvm.util.Equivalence;
 
 import jdk.vm.ci.code.CodeCacheProvider;
 import jdk.vm.ci.code.DebugInfo;
@@ -324,12 +324,32 @@
     }
 
     /**
-     * Notifies this object of a branch instruction at offset {@code pos} in the code.
+     * Notifies this object of a branch instruction at offset {@code pcOffset} in the code.
      *
      * @param isNegated negation status of the branch's condition.
      */
     @SuppressWarnings("unused")
-    public void recordBranch(int pos, boolean isNegated) {
+    public void recordBranch(int pcOffset, boolean isNegated) {
+    }
+
+    /**
+     * Notifies this object of a call instruction belonging to an INVOKEVIRTUAL or INVOKEINTERFACE
+     * at offset {@code pcOffset} in the code.
+     *
+     * @param nodeSourcePosition source position of the corresponding invoke.
+     */
+    @SuppressWarnings("unused")
+    public void recordInvokeVirtualOrInterfaceCallOp(int pcOffset, NodeSourcePosition nodeSourcePosition) {
+    }
+
+    /**
+     * Notifies this object of a call instruction belonging to an INLINE_INVOKE at offset
+     * {@code pcOffset} in the code.
+     *
+     * @param nodeSourcePosition source position of the corresponding invoke.
+     */
+    @SuppressWarnings("unused")
+    public void recordInlineInvokeCallOp(int pcOffset, NodeSourcePosition nodeSourcePosition) {
     }
 
     /**
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/gen/LIRGenerationResult.java	Fri Feb 16 12:24:38 2018 -0800
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/gen/LIRGenerationResult.java	Fri Feb 16 13:49:07 2018 -0800
@@ -22,7 +22,8 @@
  */
 package org.graalvm.compiler.lir.gen;
 
-import jdk.vm.ci.code.RegisterConfig;
+import org.graalvm.collections.EconomicMap;
+import org.graalvm.collections.Equivalence;
 import org.graalvm.compiler.core.common.CompilationIdentifier;
 import org.graalvm.compiler.core.common.CompilationIdentifier.Verbosity;
 import org.graalvm.compiler.debug.DebugContext;
@@ -30,10 +31,9 @@
 import org.graalvm.compiler.lir.LIRInstruction;
 import org.graalvm.compiler.lir.framemap.FrameMap;
 import org.graalvm.compiler.lir.framemap.FrameMapBuilder;
-import org.graalvm.util.EconomicMap;
-import org.graalvm.util.Equivalence;
 
 import jdk.vm.ci.code.CallingConvention;
+import jdk.vm.ci.code.RegisterConfig;
 
 public class LIRGenerationResult {
 
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/gen/PhiResolver.java	Fri Feb 16 12:24:38 2018 -0800
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/gen/PhiResolver.java	Fri Feb 16 13:49:07 2018 -0800
@@ -22,20 +22,20 @@
  */
 package org.graalvm.compiler.lir.gen;
 
-import static org.graalvm.compiler.lir.LIRValueUtil.isVariable;
 import static jdk.vm.ci.code.ValueUtil.isIllegal;
 import static jdk.vm.ci.code.ValueUtil.isLegal;
 import static jdk.vm.ci.meta.Value.ILLEGAL;
+import static org.graalvm.compiler.lir.LIRValueUtil.isVariable;
 
 import java.util.ArrayList;
 import java.util.List;
 
+import org.graalvm.collections.EconomicMap;
+import org.graalvm.collections.Equivalence;
 import org.graalvm.compiler.core.common.cfg.AbstractBlockBase;
 import org.graalvm.compiler.lir.LIRInsertionBuffer;
 import org.graalvm.compiler.lir.LIRInstruction;
 import org.graalvm.compiler.lir.gen.LIRGeneratorTool.MoveFactory;
-import org.graalvm.util.Equivalence;
-import org.graalvm.util.EconomicMap;
 
 import jdk.vm.ci.meta.AllocatableValue;
 import jdk.vm.ci.meta.Value;
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/phases/PreAllocationOptimizationStage.java	Fri Feb 16 12:24:38 2018 -0800
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/phases/PreAllocationOptimizationStage.java	Fri Feb 16 13:49:07 2018 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -31,7 +31,7 @@
     public PreAllocationOptimizationStage(OptionValues options) {
         if (ConstantLoadOptimization.Options.LIROptConstantLoadOptimization.getValue(options)) {
             appendPhase(new ConstantLoadOptimization());
-            appendPhase(new SaveCalleeSaveRegisters());
         }
+        appendPhase(new SaveCalleeSaveRegisters());
     }
 }
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/stackslotalloc/FixPointIntervalBuilder.java	Fri Feb 16 12:24:38 2018 -0800
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/stackslotalloc/FixPointIntervalBuilder.java	Fri Feb 16 13:49:07 2018 -0800
@@ -31,6 +31,8 @@
 import java.util.Deque;
 import java.util.EnumSet;
 
+import org.graalvm.collections.EconomicSet;
+import org.graalvm.collections.Equivalence;
 import org.graalvm.compiler.core.common.cfg.AbstractBlockBase;
 import org.graalvm.compiler.core.common.cfg.BlockMap;
 import org.graalvm.compiler.debug.CounterKey;
@@ -43,8 +45,6 @@
 import org.graalvm.compiler.lir.LIRInstruction.OperandFlag;
 import org.graalvm.compiler.lir.LIRInstruction.OperandMode;
 import org.graalvm.compiler.lir.VirtualStackSlot;
-import org.graalvm.util.EconomicSet;
-import org.graalvm.util.Equivalence;
 
 import jdk.vm.ci.meta.Value;
 
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/stackslotalloc/LSStackSlotAllocator.java	Fri Feb 16 12:24:38 2018 -0800
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/stackslotalloc/LSStackSlotAllocator.java	Fri Feb 16 13:49:07 2018 -0800
@@ -35,6 +35,7 @@
 import java.util.EnumSet;
 import java.util.PriorityQueue;
 
+import org.graalvm.collections.EconomicSet;
 import org.graalvm.compiler.core.common.cfg.AbstractBlockBase;
 import org.graalvm.compiler.debug.DebugCloseable;
 import org.graalvm.compiler.debug.DebugContext;
@@ -54,7 +55,6 @@
 import org.graalvm.compiler.options.NestedBooleanOptionKey;
 import org.graalvm.compiler.options.Option;
 import org.graalvm.compiler.options.OptionType;
-import org.graalvm.util.EconomicSet;
 
 import jdk.vm.ci.code.StackSlot;
 import jdk.vm.ci.code.TargetDescription;
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/util/GenericValueMap.java	Fri Feb 16 12:24:38 2018 -0800
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.lir/src/org/graalvm/compiler/lir/util/GenericValueMap.java	Fri Feb 16 13:49:07 2018 -0800
@@ -22,8 +22,8 @@
  */
 package org.graalvm.compiler.lir.util;
 
-import org.graalvm.util.Equivalence;
-import org.graalvm.util.EconomicMap;
+import org.graalvm.collections.EconomicMap;
+import org.graalvm.collections.Equivalence;
 
 import jdk.vm.ci.meta.Value;
 
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.loop.phases/src/org/graalvm/compiler/loop/phases/LoopTransformations.java	Fri Feb 16 12:24:38 2018 -0800
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.loop.phases/src/org/graalvm/compiler/loop/phases/LoopTransformations.java	Fri Feb 16 13:49:07 2018 -0800
@@ -31,7 +31,7 @@
 import java.util.List;
 
 import org.graalvm.compiler.core.common.RetryableBailoutException;
-import org.graalvm.compiler.core.common.calc.Condition;
+import org.graalvm.compiler.core.common.calc.CanonicalCondition;
 import org.graalvm.compiler.debug.DebugContext;
 import org.graalvm.compiler.debug.GraalError;
 import org.graalvm.compiler.graph.Graph.Mark;
@@ -451,7 +451,7 @@
         if (!(condition instanceof CompareNode)) {
             return false;
         }
-        if (((CompareNode) condition).condition() == Condition.EQ || ((CompareNode) condition).condition() == Condition.NE) {
+        if (((CompareNode) condition).condition() == CanonicalCondition.EQ) {
             condition.getDebug().log(DebugContext.VERBOSE_LEVEL, "isUnrollableLoop %s condition unsupported %s ", loopBegin, ((CompareNode) condition).condition());
             return false;
         }
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.loop/src/org/graalvm/compiler/loop/CountedLoopInfo.java	Fri Feb 16 12:24:38 2018 -0800
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.loop/src/org/graalvm/compiler/loop/CountedLoopInfo.java	Fri Feb 16 13:49:07 2018 -0800
@@ -73,12 +73,18 @@
         Stamp stamp = iv.valueNode().stamp(NodeView.DEFAULT);
         ValueNode range = sub(graph, end, iv.initNode());
 
+        ValueNode max;
+        ValueNode min;
         ValueNode oneDirection;
         if (iv.direction() == Direction.Up) {
             oneDirection = ConstantNode.forIntegerStamp(stamp, 1, graph);
+            max = end;
+            min = iv.initNode();
         } else {
             assert iv.direction() == Direction.Down;
             oneDirection = ConstantNode.forIntegerStamp(stamp, -1, graph);
+            max = iv.initNode();
+            min = end;
         }
         if (oneOff) {
             range = add(graph, range, oneDirection);
@@ -95,7 +101,7 @@
             return div;
         }
         ConstantNode zero = ConstantNode.forIntegerStamp(stamp, 0, graph);
-        return graph.unique(new ConditionalNode(graph.unique(new IntegerLessThanNode(zero, div)), div, zero));
+        return graph.unique(new ConditionalNode(graph.unique(new IntegerLessThanNode(max, min)), zero, div));
     }
 
     /**
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.loop/src/org/graalvm/compiler/loop/LoopEx.java	Fri Feb 16 12:24:38 2018 -0800
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.loop/src/org/graalvm/compiler/loop/LoopEx.java	Fri Feb 16 13:49:07 2018 -0800
@@ -22,7 +22,13 @@
  */
 package org.graalvm.compiler.loop;
 
-import jdk.vm.ci.code.BytecodeFrame;
+import java.util.Collection;
+import java.util.LinkedList;
+import java.util.Queue;
+
+import org.graalvm.collections.EconomicMap;
+import org.graalvm.collections.EconomicSet;
+import org.graalvm.collections.Equivalence;
 import org.graalvm.compiler.core.common.calc.Condition;
 import org.graalvm.compiler.core.common.cfg.Loop;
 import org.graalvm.compiler.core.common.type.IntegerStamp;
@@ -67,13 +73,8 @@
 import org.graalvm.compiler.nodes.debug.ControlFlowAnchored;
 import org.graalvm.compiler.nodes.extended.ValueAnchorNode;
 import org.graalvm.compiler.nodes.util.GraphUtil;
-import org.graalvm.util.EconomicMap;
-import org.graalvm.util.EconomicSet;
-import org.graalvm.util.Equivalence;
 
-import java.util.Collection;
-import java.util.LinkedList;
-import java.util.Queue;
+import jdk.vm.ci.code.BytecodeFrame;
 
 public class LoopEx {
     private final Loop<Block> loop;
@@ -236,13 +237,13 @@
             if (isOutsideLoop(lessThan.getX())) {
                 iv = getInductionVariables().get(lessThan.getY());
                 if (iv != null) {
-                    condition = lessThan.condition().mirror();
+                    condition = lessThan.condition().asCondition().mirror();
                     limit = lessThan.getX();
                 }
             } else if (isOutsideLoop(lessThan.getY())) {
                 iv = getInductionVariables().get(lessThan.getX());
                 if (iv != null) {
-                    condition = lessThan.condition();
+                    condition = lessThan.condition().asCondition();
                     limit = lessThan.getY();
                 }
             }
@@ -393,8 +394,8 @@
                 } else {
                     boolean isValidConvert = op instanceof PiNode || op instanceof SignExtendNode;
                     if (!isValidConvert && op instanceof ZeroExtendNode) {
-                        IntegerStamp inputStamp = (IntegerStamp) ((ZeroExtendNode) op).getValue().stamp(NodeView.DEFAULT);
-                        isValidConvert = inputStamp.isPositive();
+                        ZeroExtendNode zeroExtendNode = (ZeroExtendNode) op;
+                        isValidConvert = zeroExtendNode.isInputAlwaysPositive() || ((IntegerStamp) zeroExtendNode.stamp(NodeView.DEFAULT)).isPositive();
                     }
 
                     if (isValidConvert) {
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.loop/src/org/graalvm/compiler/loop/LoopFragment.java	Fri Feb 16 12:24:38 2018 -0800
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.loop/src/org/graalvm/compiler/loop/LoopFragment.java	Fri Feb 16 13:49:07 2018 -0800
@@ -22,7 +22,12 @@
  */
 package org.graalvm.compiler.loop;
 
-import jdk.vm.ci.meta.TriState;
+import java.util.ArrayDeque;
+import java.util.Collections;
+import java.util.Deque;
+import java.util.Iterator;
+
+import org.graalvm.collections.EconomicMap;
 import org.graalvm.compiler.debug.GraalError;
 import org.graalvm.compiler.graph.Graph;
 import org.graalvm.compiler.graph.Graph.DuplicationReplacement;
@@ -52,12 +57,8 @@
 import org.graalvm.compiler.nodes.spi.NodeWithState;
 import org.graalvm.compiler.nodes.virtual.CommitAllocationNode;
 import org.graalvm.compiler.nodes.virtual.VirtualObjectNode;
-import org.graalvm.util.EconomicMap;
 
-import java.util.ArrayDeque;
-import java.util.Collections;
-import java.util.Deque;
-import java.util.Iterator;
+import jdk.vm.ci.meta.TriState;
 
 public abstract class LoopFragment {
 
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.loop/src/org/graalvm/compiler/loop/LoopFragmentInside.java	Fri Feb 16 12:24:38 2018 -0800
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.loop/src/org/graalvm/compiler/loop/LoopFragmentInside.java	Fri Feb 16 13:49:07 2018 -0800
@@ -26,6 +26,8 @@
 import java.util.LinkedList;
 import java.util.List;
 
+import org.graalvm.collections.EconomicMap;
+import org.graalvm.collections.Equivalence;
 import org.graalvm.compiler.debug.DebugContext;
 import org.graalvm.compiler.debug.GraalError;
 import org.graalvm.compiler.graph.Graph.DuplicationReplacement;
@@ -62,8 +64,6 @@
 import org.graalvm.compiler.nodes.calc.SubNode;
 import org.graalvm.compiler.nodes.memory.MemoryPhiNode;
 import org.graalvm.compiler.nodes.util.GraphUtil;
-import org.graalvm.util.EconomicMap;
-import org.graalvm.util.Equivalence;
 
 public class LoopFragmentInside extends LoopFragment {
 
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.loop/src/org/graalvm/compiler/loop/LoopFragmentWhole.java	Fri Feb 16 12:24:38 2018 -0800
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.loop/src/org/graalvm/compiler/loop/LoopFragmentWhole.java	Fri Feb 16 13:49:07 2018 -0800
@@ -22,6 +22,7 @@
  */
 package org.graalvm.compiler.loop;
 
+import org.graalvm.collections.EconomicSet;
 import org.graalvm.compiler.core.common.cfg.Loop;
 import org.graalvm.compiler.debug.DebugContext;
 import org.graalvm.compiler.graph.Graph;
@@ -35,7 +36,6 @@
 import org.graalvm.compiler.nodes.StructuredGraph;
 import org.graalvm.compiler.nodes.ValueNode;
 import org.graalvm.compiler.nodes.cfg.Block;
-import org.graalvm.util.EconomicSet;
 
 public class LoopFragmentWhole extends LoopFragment {
 
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.loop/src/org/graalvm/compiler/loop/LoopsData.java	Fri Feb 16 12:24:38 2018 -0800
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.loop/src/org/graalvm/compiler/loop/LoopsData.java	Fri Feb 16 13:49:07 2018 -0800
@@ -27,6 +27,9 @@
 import java.util.LinkedList;
 import java.util.List;
 
+import org.graalvm.collections.EconomicMap;
+import org.graalvm.collections.EconomicSet;
+import org.graalvm.collections.Equivalence;
 import org.graalvm.compiler.core.common.cfg.Loop;
 import org.graalvm.compiler.debug.DebugContext;
 import org.graalvm.compiler.nodes.LoopBeginNode;
@@ -34,9 +37,6 @@
 import org.graalvm.compiler.nodes.ValueNode;
 import org.graalvm.compiler.nodes.cfg.Block;
 import org.graalvm.compiler.nodes.cfg.ControlFlowGraph;
-import org.graalvm.util.EconomicMap;
-import org.graalvm.util.EconomicSet;
-import org.graalvm.util.Equivalence;
 
 public class LoopsData {
     private final EconomicMap<LoopBeginNode, LoopEx> loopBeginToEx = EconomicMap.create(Equivalence.IDENTITY);
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.microbenchmarks/src/org/graalvm/compiler/microbenchmarks/graal/SchedulePhaseBenchmark.java	Fri Feb 16 12:24:38 2018 -0800
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.microbenchmarks/src/org/graalvm/compiler/microbenchmarks/graal/SchedulePhaseBenchmark.java	Fri Feb 16 13:49:07 2018 -0800
@@ -24,7 +24,9 @@
 
 import java.util.Arrays;
 
+import org.graalvm.compiler.phases.schedule.SchedulePhase;
 import org.openjdk.jmh.annotations.Benchmark;
+import org.openjdk.jmh.annotations.Measurement;
 import org.openjdk.jmh.annotations.Warmup;
 
 import org.graalvm.compiler.microbenchmarks.graal.util.MethodSpec;
@@ -32,7 +34,8 @@
 import org.graalvm.compiler.nodes.cfg.ControlFlowGraph;
 import org.graalvm.compiler.phases.schedule.SchedulePhase.SchedulingStrategy;
 
-@Warmup(iterations = 15)
+@Warmup(iterations = 20)
+@Measurement(iterations = 10)
 public class SchedulePhaseBenchmark extends GraalBenchmark {
 
     @MethodSpec(declaringClass = String.class, name = "equals")
@@ -117,5 +120,67 @@
     public void intersection_EARLIEST_OPTIMAL(IntersectionState_EARLIEST_OPTIMAL s) {
         s.schedule.apply(s.graph);
     }
+
+    @MethodSpec(declaringClass = SchedulePhaseBenchmark.class, name = "intersectionSnippet")
+    public static class IntersectionState_EARLIEST_WITH_GUARD_ORDER_OPTIMAL extends ScheduleState {
+        public IntersectionState_EARLIEST_WITH_GUARD_ORDER_OPTIMAL() {
+            super(SchedulingStrategy.EARLIEST_WITH_GUARD_ORDER);
+        }
+    }
+
+    @Benchmark
+    public void intersection_EARLIEST_WITH_GUARD_ORDER_OPTIMAL(IntersectionState_EARLIEST_WITH_GUARD_ORDER_OPTIMAL s) {
+        s.schedule.apply(s.graph);
+    }
+    // Checkstyle: resume method name check
+
+    // Checkstyle: stop method name check
+    @MethodSpec(declaringClass = SchedulePhase.Instance.class, name = "scheduleEarliestIterative")
+    public static class ScheduleEarliestIterative_LATEST_OPTIMAL extends ScheduleState {
+        public ScheduleEarliestIterative_LATEST_OPTIMAL() {
+            super(SchedulingStrategy.LATEST);
+        }
+    }
+
+    @Benchmark
+    public void scheduleEarliestIterative_LATEST_OPTIMAL(ScheduleEarliestIterative_LATEST_OPTIMAL s) {
+        s.schedule.apply(s.graph);
+    }
+
+    @MethodSpec(declaringClass = SchedulePhase.Instance.class, name = "scheduleEarliestIterative")
+    public static class ScheduleEarliestIterative_LATEST_OUT_OF_LOOPS_OPTIMAL extends ScheduleState {
+        public ScheduleEarliestIterative_LATEST_OUT_OF_LOOPS_OPTIMAL() {
+            super(SchedulingStrategy.LATEST_OUT_OF_LOOPS);
+        }
+    }
+
+    @Benchmark
+    public void scheduleEarliestIterative_LATEST_OUT_OF_LOOPS_OPTIMAL(ScheduleEarliestIterative_LATEST_OUT_OF_LOOPS_OPTIMAL s) {
+        s.schedule.apply(s.graph);
+    }
+
+    @MethodSpec(declaringClass = SchedulePhase.Instance.class, name = "scheduleEarliestIterative")
+    public static class ScheduleEarliestIterative_EARLIEST_OPTIMAL extends ScheduleState {
+        public ScheduleEarliestIterative_EARLIEST_OPTIMAL() {
+            super(SchedulingStrategy.EARLIEST);
+        }
+    }
+
+    @Benchmark
+    public void scheduleEarliestIterative_EARLIEST_OPTIMAL(ScheduleEarliestIterative_EARLIEST_OPTIMAL s) {
+        s.schedule.apply(s.graph);
+    }
+
+    @MethodSpec(declaringClass = SchedulePhase.Instance.class, name = "scheduleEarliestIterative")
+    public static class ScheduleEarliestIterative_EARLIEST_WITH_GUARD_ORDER_OPTIMAL extends ScheduleState {
+        public ScheduleEarliestIterative_EARLIEST_WITH_GUARD_ORDER_OPTIMAL() {
+            super(SchedulingStrategy.EARLIEST_WITH_GUARD_ORDER);
+        }
+    }
+
+    @Benchmark
+    public void scheduleEarliestIterative_EARLIEST_WITH_GUARD_ORDER_OPTIMAL(ScheduleEarliestIterative_EARLIEST_WITH_GUARD_ORDER_OPTIMAL s) {
+        s.schedule.apply(s.graph);
+    }
     // Checkstyle: resume method name check
 }
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.microbenchmarks/src/org/graalvm/compiler/microbenchmarks/graal/util/ScheduleState.java	Fri Feb 16 12:24:38 2018 -0800
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.microbenchmarks/src/org/graalvm/compiler/microbenchmarks/graal/util/ScheduleState.java	Fri Feb 16 13:49:07 2018 -0800
@@ -22,8 +22,12 @@
  */
 package org.graalvm.compiler.microbenchmarks.graal.util;
 
+import org.graalvm.compiler.nodes.StructuredGraph;
+import org.graalvm.compiler.phases.OptimisticOptimizations;
+import org.graalvm.compiler.phases.PhaseSuite;
 import org.graalvm.compiler.phases.schedule.SchedulePhase;
 import org.graalvm.compiler.phases.schedule.SchedulePhase.SchedulingStrategy;
+import org.graalvm.compiler.phases.tiers.HighTierContext;
 
 public class ScheduleState extends GraphState {
 
@@ -36,7 +40,7 @@
     }
 
     public ScheduleState() {
-        this(SchedulingStrategy.EARLIEST);
+        this(SchedulingStrategy.EARLIEST_WITH_GUARD_ORDER);
     }
 
     @Override
@@ -44,4 +48,13 @@
         schedule = new SchedulePhase(selectedStrategy);
         super.beforeInvocation();
     }
+
+    @Override
+    protected StructuredGraph preprocessOriginal(StructuredGraph structuredGraph) {
+        StructuredGraph g = super.preprocessOriginal(structuredGraph);
+        GraalState graal = new GraalState();
+        PhaseSuite<HighTierContext> highTier = graal.backend.getSuites().getDefaultSuites(graal.options).getHighTier();
+        highTier.apply(g, new HighTierContext(graal.providers, graal.backend.getSuites().getDefaultGraphBuilderSuite(), OptimisticOptimizations.ALL));
+        return g;
+    }
 }
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes.test/src/org/graalvm/compiler/nodes/test/IfNodeCanonicalizationTest.java	Fri Feb 16 12:24:38 2018 -0800
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes.test/src/org/graalvm/compiler/nodes/test/IfNodeCanonicalizationTest.java	Fri Feb 16 13:49:07 2018 -0800
@@ -156,11 +156,11 @@
 
         PhaseContext context = new PhaseContext(getProviders());
         CanonicalizerPhase canonicalizer = new CanonicalizerPhase();
+        new ConvertDeoptimizeToGuardPhase().apply(graph, context);
         graph.clearAllStateAfter();
         graph.setGuardsStage(StructuredGraph.GuardsStage.AFTER_FSA);
         canonicalizer.apply(graph, context);
 
-        new ConvertDeoptimizeToGuardPhase().apply(graph, context);
         // new DominatorConditionalEliminationPhase(true).apply(graph, context);
         new IterativeConditionalEliminationPhase(canonicalizer, true).apply(graph, context);
         canonicalizer.apply(graph, context);
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/AbstractBeginNode.java	Fri Feb 16 12:24:38 2018 -0800
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/AbstractBeginNode.java	Fri Feb 16 13:49:07 2018 -0800
@@ -129,10 +129,13 @@
             if (ret == null) {
                 throw new NoSuchElementException();
             }
-            if (!(current instanceof FixedWithNextNode) || (current instanceof AbstractBeginNode && current != AbstractBeginNode.this)) {
+            if (current instanceof FixedWithNextNode) {
+                current = ((FixedWithNextNode) current).next();
+                if (current instanceof AbstractBeginNode) {
+                    current = null;
+                }
+            } else {
                 current = null;
-            } else {
-                current = ((FixedWithNextNode) current).next();
             }
             return ret;
         }
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/ControlSplitNode.java	Fri Feb 16 12:24:38 2018 -0800
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/ControlSplitNode.java	Fri Feb 16 13:49:07 2018 -0800
@@ -49,7 +49,7 @@
 
     /**
      * Primary successor of the control split. Data dependencies on the node have to be scheduled in
-     * the primary successor.
+     * the primary successor. Returns null if data dependencies are not expected.
      *
      * @return the primary successor
      */
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/DeoptimizeNode.java	Fri Feb 16 12:24:38 2018 -0800
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/DeoptimizeNode.java	Fri Feb 16 13:49:07 2018 -0800
@@ -39,7 +39,7 @@
 import jdk.vm.ci.meta.Value;
 
 @NodeInfo(shortName = "Deopt", nameTemplate = "Deopt {p#reason/s}")
-public final class DeoptimizeNode extends AbstractDeoptimizeNode implements Lowerable, LIRLowerable {
+public final class DeoptimizeNode extends AbstractDeoptimizeNode implements Lowerable, LIRLowerable, StaticDeoptimizingNode {
     public static final int DEFAULT_DEBUG_ID = 0;
 
     public static final NodeClass<DeoptimizeNode> TYPE = NodeClass.create(DeoptimizeNode.class);
@@ -67,11 +67,13 @@
         this.speculation = speculation;
     }
 
-    public DeoptimizationAction action() {
+    @Override
+    public DeoptimizationAction getAction() {
         return action;
     }
 
-    public DeoptimizationReason reason() {
+    @Override
+    public DeoptimizationReason getReason() {
         return reason;
     }
 
@@ -115,6 +117,7 @@
         return ConstantNode.forConstant(speculation, metaAccess, graph());
     }
 
+    @Override
     public JavaConstant getSpeculation() {
         return speculation;
     }
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/DeoptimizingGuard.java	Fri Feb 16 12:24:38 2018 -0800
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/DeoptimizingGuard.java	Fri Feb 16 13:49:07 2018 -0800
@@ -24,25 +24,15 @@
 
 import org.graalvm.compiler.nodes.extended.GuardingNode;
 
-import jdk.vm.ci.meta.DeoptimizationAction;
-import jdk.vm.ci.meta.DeoptimizationReason;
-import jdk.vm.ci.meta.JavaConstant;
-
 /**
  * Shared interface to capture core methods of {@link AbstractFixedGuardNode} and {@link GuardNode}.
  *
  */
-public interface DeoptimizingGuard extends ValueNodeInterface, GuardingNode {
+public interface DeoptimizingGuard extends GuardingNode, StaticDeoptimizingNode {
 
     LogicNode getCondition();
 
     void setCondition(LogicNode x, boolean negated);
 
-    DeoptimizationReason getReason();
-
-    DeoptimizationAction getAction();
-
-    JavaConstant getSpeculation();
-
     boolean isNegated();
 }
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/FixedGuardNode.java	Fri Feb 16 12:24:38 2018 -0800
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/FixedGuardNode.java	Fri Feb 16 13:49:07 2018 -0800
@@ -83,15 +83,7 @@
     @Override
     public void lower(LoweringTool tool) {
         if (graph().getGuardsStage().allowsFloatingGuards()) {
-            /*
-             * Don't allow guards with action None and reason RuntimeConstraint to float. In cases
-             * where 2 guards are testing equivalent conditions they might be lowered at the same
-             * location. If the guard with the None action is lowered before the other guard then
-             * the code will be stuck repeatedly deoptimizing without invalidating the code.
-             * Conditional elimination will eliminate the guard if it's truly redundant in this
-             * case.
-             */
-            if (getAction() != DeoptimizationAction.None || getReason() != DeoptimizationReason.RuntimeConstraint) {
+            if (getAction() != DeoptimizationAction.None) {
                 ValueNode guard = tool.createGuard(this, getCondition(), getReason(), getAction(), getSpeculation(), isNegated()).asNode();
                 this.replaceAtUsages(guard);
                 graph().removeFixed(this);
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/GraphDecoder.java	Fri Feb 16 12:24:38 2018 -0800
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/GraphDecoder.java	Fri Feb 16 13:49:07 2018 -0800
@@ -37,6 +37,9 @@
 import java.util.SortedMap;
 import java.util.TreeMap;
 
+import org.graalvm.collections.EconomicMap;
+import org.graalvm.collections.EconomicSet;
+import org.graalvm.collections.Equivalence;
 import org.graalvm.compiler.core.common.Fields;
 import org.graalvm.compiler.core.common.PermanentBailoutException;
 import org.graalvm.compiler.core.common.util.TypeReader;
@@ -62,9 +65,6 @@
 import org.graalvm.compiler.nodes.extended.IntegerSwitchNode;
 import org.graalvm.compiler.nodes.graphbuilderconf.LoopExplosionPlugin.LoopExplosionKind;
 import org.graalvm.compiler.options.OptionValues;
-import org.graalvm.util.EconomicMap;
-import org.graalvm.util.EconomicSet;
-import org.graalvm.util.Equivalence;
 
 import jdk.vm.ci.code.Architecture;
 import jdk.vm.ci.meta.DeoptimizationAction;
@@ -489,7 +489,8 @@
                  */
                 LoopScope outerScope = loopScope.outer;
                 int nextIterationNumber = outerScope.nextIterations.isEmpty() ? outerScope.loopIteration + 1 : outerScope.nextIterations.getLast().loopIteration + 1;
-                successorAddScope = new LoopScope(methodScope, outerScope.outer, outerScope.loopDepth, nextIterationNumber, outerScope.loopBeginOrderId, outerScope.initialCreatedNodes,
+                successorAddScope = new LoopScope(methodScope, outerScope.outer, outerScope.loopDepth, nextIterationNumber, outerScope.loopBeginOrderId,
+                                outerScope.initialCreatedNodes == null ? null : Arrays.copyOf(outerScope.initialCreatedNodes, outerScope.initialCreatedNodes.length),
                                 Arrays.copyOf(loopScope.initialCreatedNodes, loopScope.initialCreatedNodes.length), outerScope.nextIterations, outerScope.iterationStates);
                 checkLoopExplosionIteration(methodScope, successorAddScope);
 
@@ -736,7 +737,8 @@
         assert methodScope.loopExplosion != LoopExplosionKind.NONE;
         if (methodScope.loopExplosion != LoopExplosionKind.FULL_UNROLL || loopScope.nextIterations.isEmpty()) {
             int nextIterationNumber = loopScope.nextIterations.isEmpty() ? loopScope.loopIteration + 1 : loopScope.nextIterations.getLast().loopIteration + 1;
-            LoopScope nextIterationScope = new LoopScope(methodScope, loopScope.outer, loopScope.loopDepth, nextIterationNumber, loopScope.loopBeginOrderId, loopScope.initialCreatedNodes,
+            LoopScope nextIterationScope = new LoopScope(methodScope, loopScope.outer, loopScope.loopDepth, nextIterationNumber, loopScope.loopBeginOrderId,
+                            Arrays.copyOf(loopScope.initialCreatedNodes, loopScope.initialCreatedNodes.length),
                             Arrays.copyOf(loopScope.initialCreatedNodes, loopScope.initialCreatedNodes.length), loopScope.nextIterations, loopScope.iterationStates);
             checkLoopExplosionIteration(methodScope, nextIterationScope);
             loopScope.nextIterations.addLast(nextIterationScope);
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/GraphEncoder.java	Fri Feb 16 12:24:38 2018 -0800
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/GraphEncoder.java	Fri Feb 16 13:49:07 2018 -0800
@@ -27,6 +27,8 @@
 import java.util.Iterator;
 import java.util.Objects;
 
+import org.graalvm.collections.Pair;
+import org.graalvm.collections.UnmodifiableMapCursor;
 import org.graalvm.compiler.core.common.Fields;
 import org.graalvm.compiler.core.common.util.FrequencyEncoder;
 import org.graalvm.compiler.core.common.util.TypeConversion;
@@ -42,8 +44,6 @@
 import org.graalvm.compiler.graph.iterators.NodeIterable;
 import org.graalvm.compiler.nodes.StructuredGraph.AllowAssumptions;
 import org.graalvm.compiler.nodes.java.ExceptionObjectNode;
-import org.graalvm.util.Pair;
-import org.graalvm.util.UnmodifiableMapCursor;
 
 import jdk.vm.ci.code.Architecture;
 
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/IfNode.java	Fri Feb 16 12:24:38 2018 -0800
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/IfNode.java	Fri Feb 16 13:49:07 2018 -0800
@@ -30,6 +30,8 @@
 import java.util.Iterator;
 import java.util.List;
 
+import org.graalvm.collections.EconomicMap;
+import org.graalvm.collections.Equivalence;
 import org.graalvm.compiler.core.common.calc.Condition;
 import org.graalvm.compiler.core.common.type.IntegerStamp;
 import org.graalvm.compiler.core.common.type.Stamp;
@@ -59,8 +61,6 @@
 import org.graalvm.compiler.nodes.spi.LIRLowerable;
 import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool;
 import org.graalvm.compiler.nodes.util.GraphUtil;
-import org.graalvm.util.EconomicMap;
-import org.graalvm.util.Equivalence;
 
 import jdk.vm.ci.meta.Constant;
 import jdk.vm.ci.meta.JavaConstant;
@@ -557,7 +557,7 @@
         } else if (next1 instanceof DeoptimizeNode && next2 instanceof DeoptimizeNode) {
             DeoptimizeNode deopt1 = (DeoptimizeNode) next1;
             DeoptimizeNode deopt2 = (DeoptimizeNode) next2;
-            if (deopt1.reason() == deopt2.reason() && deopt1.action() == deopt2.action()) {
+            if (deopt1.getReason() == deopt2.getReason() && deopt1.getAction() == deopt2.getAction()) {
                 // Same deoptimization reason and action.
                 return true;
             }
@@ -600,7 +600,7 @@
             }
         } else if (a instanceof CompareNode) {
             CompareNode compareA = (CompareNode) a;
-            Condition conditionA = compareA.condition();
+            Condition conditionA = compareA.condition().asCondition();
             if (compareA.unorderedIsTrue()) {
                 return false;
             }
@@ -614,7 +614,7 @@
                     return false;
                 }
                 Condition comparableCondition = null;
-                Condition conditionB = compareB.condition();
+                Condition conditionB = compareB.condition().asCondition();
                 if (compareB.getX() == compareA.getX() && compareB.getY() == compareA.getY()) {
                     comparableCondition = conditionB;
                 } else if (compareB.getX() == compareA.getY() && compareB.getY() == compareA.getX()) {
@@ -1384,7 +1384,7 @@
 
     @Override
     public AbstractBeginNode getPrimarySuccessor() {
-        return this.trueSuccessor();
+        return null;
     }
 
     public AbstractBeginNode getSuccessor(boolean result) {
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/InliningLog.java	Fri Feb 16 13:49:07 2018 -0800
@@ -0,0 +1,278 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.nodes;
+
+import jdk.vm.ci.code.BytecodePosition;
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * This class contains all inlining decisions performed on a graph during the compilation.
+ *
+ * Each inlining decision consists of:
+ *
+ * <ul>
+ * <li>a value indicating whether the decision was positive or negative</li>
+ * <li>the call target method</li>
+ * <li>the reason for the inlining decision</li>
+ * <li>the name of the phase in which the inlining decision took place</li>
+ * <li>the special {@link BytecodePositionWithId} value that describes the position in the bytecode
+ * together with the callsite-specific unique identifier</li>
+ * <li>the inlining log of the inlined graph, or {@code null} if the decision was negative</li>
+ * </ul>
+ *
+ * A phase that does inlining should use the instance of this class contained in the
+ * {@link StructuredGraph} by calling {@link #addDecision} whenever it decides to inline a method.
+ * If there are invokes in the graph at the end of the respective phase, then that phase must call
+ * {@link #addDecision} to log negative decisions.
+ *
+ * At the end of the compilation, the contents of the inlining log can be converted into a list of
+ * decisions by calling {@link #formatAsList} or into an inlining tree, by calling
+ * {@link #formatAsTree}.
+ */
+public class InliningLog {
+    /**
+     * A bytecode position with a unique identifier attached.
+     *
+     * The purpose of this class is to disambiguate callsites that are duplicated by a
+     * transformation (such as loop peeling or path duplication).
+     */
+    public static final class BytecodePositionWithId extends BytecodePosition implements Comparable<BytecodePositionWithId> {
+        private final int id;
+
+        public BytecodePositionWithId(BytecodePositionWithId caller, ResolvedJavaMethod method, int bci, int id) {
+            super(caller, method, bci);
+            this.id = id;
+        }
+
+        public BytecodePositionWithId addCallerWithId(BytecodePositionWithId caller) {
+            if (getCaller() == null) {
+                return new BytecodePositionWithId(caller, getMethod(), getBCI(), id);
+            } else {
+                return new BytecodePositionWithId(getCaller().addCallerWithId(caller), getMethod(), getBCI(), id);
+            }
+        }
+
+        public static BytecodePositionWithId create(FrameState state) {
+            return create(state, true);
+        }
+
+        @SuppressWarnings("deprecation")
+        private static BytecodePositionWithId create(FrameState state, boolean topLevel) {
+            if (state == null) {
+                return null;
+            }
+            ResolvedJavaMethod method = state.getMethod();
+            int bci = topLevel ? state.bci - 3 : state.bci;
+            int id = state.getId();
+            return new BytecodePositionWithId(create(state.outerFrameState(), false), method, bci, id);
+        }
+
+        @Override
+        public BytecodePositionWithId getCaller() {
+            return (BytecodePositionWithId) super.getCaller();
+        }
+
+        public BytecodePositionWithId withoutCaller() {
+            return new BytecodePositionWithId(null, getMethod(), getBCI(), id);
+        }
+
+        public long getId() {
+            return id;
+        }
+
+        @Override
+        public boolean equals(Object that) {
+            return super.equals(that) && this.id == ((BytecodePositionWithId) that).id;
+        }
+
+        @Override
+        public int hashCode() {
+            return super.hashCode() ^ (id << 16);
+        }
+
+        @Override
+        public int compareTo(BytecodePositionWithId that) {
+            int diff = this.getBCI() - that.getBCI();
+            if (diff != 0) {
+                return diff;
+            }
+            diff = (int) (this.getId() - that.getId());
+            return diff;
+        }
+    }
+
+    public static final class Decision {
+        private final boolean positive;
+        private final String reason;
+        private final String phase;
+        private final ResolvedJavaMethod target;
+        private final BytecodePositionWithId position;
+        private final InliningLog childLog;
+
+        private Decision(boolean positive, String reason, String phase, ResolvedJavaMethod target, BytecodePositionWithId position, InliningLog childLog) {
+            assert position != null;
+            this.positive = positive;
+            this.reason = reason;
+            this.phase = phase;
+            this.target = target;
+            this.position = position;
+            this.childLog = childLog;
+        }
+
+        public boolean isPositive() {
+            return positive;
+        }
+
+        public String getReason() {
+            return reason;
+        }
+
+        public String getPhase() {
+            return phase;
+        }
+
+        public BytecodePositionWithId getPosition() {
+            return position;
+        }
+
+        public InliningLog getChildLog() {
+            return childLog;
+        }
+
+        public ResolvedJavaMethod getTarget() {
+            return target;
+        }
+    }
+
+    private static class Callsite {
+        public final List<String> decisions;
+        public final Map<BytecodePositionWithId, Callsite> children;
+        public final BytecodePositionWithId position;
+
+        Callsite(BytecodePositionWithId position) {
+            this.children = new HashMap<>();
+            this.position = position;
+            this.decisions = new ArrayList<>();
+        }
+
+        public Callsite getOrCreateChild(BytecodePositionWithId fromRootPosition) {
+            Callsite child = children.get(fromRootPosition.withoutCaller());
+            if (child == null) {
+                child = new Callsite(fromRootPosition);
+                children.put(fromRootPosition.withoutCaller(), child);
+            }
+            return child;
+        }
+
+        public Callsite createCallsite(BytecodePositionWithId fromRootPosition, String decision) {
+            Callsite parent = getOrCreateCallsite(fromRootPosition.getCaller());
+            Callsite callsite = parent.getOrCreateChild(fromRootPosition);
+            callsite.decisions.add(decision);
+            return null;
+        }
+
+        private Callsite getOrCreateCallsite(BytecodePositionWithId fromRootPosition) {
+            if (fromRootPosition == null) {
+                return this;
+            } else {
+                Callsite parent = getOrCreateCallsite(fromRootPosition.getCaller());
+                Callsite callsite = parent.getOrCreateChild(fromRootPosition);
+                return callsite;
+            }
+        }
+    }
+
+    private final List<Decision> decisions;
+
+    public InliningLog() {
+        this.decisions = new ArrayList<>();
+    }
+
+    public List<Decision> getDecisions() {
+        return decisions;
+    }
+
+    public void addDecision(boolean positive, String reason, String phase, ResolvedJavaMethod target, BytecodePositionWithId position,
+                    InliningLog calleeLog) {
+        Decision decision = new Decision(positive, reason, phase, target, position, calleeLog);
+        decisions.add(decision);
+    }
+
+    public String formatAsList() {
+        StringBuilder builder = new StringBuilder();
+        formatAsList("", null, decisions, builder);
+        return builder.toString();
+    }
+
+    private void formatAsList(String phasePrefix, BytecodePositionWithId caller, List<Decision> subDecisions, StringBuilder builder) {
+        for (Decision decision : subDecisions) {
+            String phaseStack = phasePrefix.equals("") ? decision.getPhase() : phasePrefix + "-" + decision.getPhase();
+            String target = decision.getTarget().format("%H.%n(%p)");
+            String positive = decision.isPositive() ? "inline" : "do not inline";
+            BytecodePositionWithId absolutePosition = decision.getPosition().addCallerWithId(caller);
+            String position = "  " + decision.getPosition().toString().replaceAll("\n", "\n  ");
+            String line = String.format("<%s> %s %s: %s\n%s", phaseStack, positive, target, decision.getReason(), position);
+            builder.append(line).append(System.lineSeparator());
+            if (decision.getChildLog() != null) {
+                formatAsList(phaseStack, absolutePosition, decision.getChildLog().getDecisions(), builder);
+            }
+        }
+    }
+
+    public String formatAsTree() {
+        Callsite root = new Callsite(null);
+        createTree("", null, root, decisions);
+        StringBuilder builder = new StringBuilder();
+        formatAsTree(root, "", builder);
+        return builder.toString();
+    }
+
+    private void createTree(String phasePrefix, BytecodePositionWithId caller, Callsite root, List<Decision> subDecisions) {
+        for (Decision decision : subDecisions) {
+            String phaseStack = phasePrefix.equals("") ? decision.getPhase() : phasePrefix + "-" + decision.getPhase();
+            String target = decision.getTarget().format("%H.%n(%p)");
+            BytecodePositionWithId absolutePosition = decision.getPosition().addCallerWithId(caller);
+            String line = String.format("<%s> %s: %s", phaseStack, target, decision.getReason());
+            root.createCallsite(absolutePosition, line);
+            if (decision.getChildLog() != null) {
+                createTree(phaseStack, absolutePosition, root, decision.getChildLog().getDecisions());
+            }
+        }
+    }
+
+    private void formatAsTree(Callsite site, String indent, StringBuilder builder) {
+        String position = site.position != null ? site.position.withoutCaller().toString() : "<root>";
+        String decision = String.join("; ", site.decisions);
+        String line = String.format("%s%s; %s", indent, position, decision);
+        builder.append(line).append(System.lineSeparator());
+        String childIndent = indent + "  ";
+        site.children.entrySet().stream().sorted((x, y) -> x.getKey().compareTo(y.getKey())).forEach(e -> {
+            formatAsTree(e.getValue(), childIndent, builder);
+        });
+    }
+}
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/NamedLocationIdentity.java	Fri Feb 16 12:24:38 2018 -0800
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/NamedLocationIdentity.java	Fri Feb 16 13:49:07 2018 -0800
@@ -24,9 +24,9 @@
 
 import java.util.EnumMap;
 
-import org.graalvm.util.Equivalence;
+import org.graalvm.collections.EconomicSet;
+import org.graalvm.collections.Equivalence;
 import org.graalvm.word.LocationIdentity;
-import org.graalvm.util.EconomicSet;
 
 import jdk.vm.ci.meta.JavaKind;
 import jdk.vm.ci.meta.JavaKind.FormatWithToString;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/StaticDeoptimizingNode.java	Fri Feb 16 13:49:07 2018 -0800
@@ -0,0 +1,78 @@
+/*
+ * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.nodes;
+
+import org.graalvm.compiler.debug.GraalError;
+
+import jdk.vm.ci.meta.DeoptimizationAction;
+import jdk.vm.ci.meta.DeoptimizationReason;
+import jdk.vm.ci.meta.JavaConstant;
+
+public interface StaticDeoptimizingNode extends ValueNodeInterface {
+
+    DeoptimizationReason getReason();
+
+    DeoptimizationAction getAction();
+
+    JavaConstant getSpeculation();
+
+    /**
+     * Describes how much information is gathered when deoptimization triggers.
+     *
+     * This enum is {@link Comparable} and orders its element from highest priority to lowest
+     * priority.
+     */
+    enum GuardPriority {
+        Speculation,
+        Profile,
+        None;
+
+        public boolean isHigherPriorityThan(GuardPriority other) {
+            return this.compareTo(other) < 0;
+        }
+
+        public boolean isLowerPriorityThan(GuardPriority other) {
+            return this.compareTo(other) > 0;
+        }
+
+        public static GuardPriority highest() {
+            return Speculation;
+        }
+    }
+
+    default GuardPriority computePriority() {
+        if (getSpeculation() != null && getSpeculation().isNonNull()) {
+            return GuardNode.GuardPriority.Speculation;
+        }
+        switch (getAction()) {
+            case InvalidateReprofile:
+            case InvalidateRecompile:
+                return GuardNode.GuardPriority.Profile;
+            case RecompileIfTooManyDeopts:
+            case InvalidateStopCompiling:
+            case None:
+                return GuardNode.GuardPriority.None;
+        }
+        throw GraalError.shouldNotReachHere();
+    }
+}
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/StructuredGraph.java	Fri Feb 16 12:24:38 2018 -0800
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/StructuredGraph.java	Fri Feb 16 13:49:07 2018 -0800
@@ -28,6 +28,10 @@
 import java.util.concurrent.atomic.AtomicLong;
 import java.util.function.Consumer;
 
+import org.graalvm.collections.EconomicMap;
+import org.graalvm.collections.EconomicSet;
+import org.graalvm.collections.Equivalence;
+import org.graalvm.collections.UnmodifiableEconomicMap;
 import org.graalvm.compiler.core.common.CancellationBailoutException;
 import org.graalvm.compiler.core.common.CompilationIdentifier;
 import org.graalvm.compiler.core.common.GraalOptions;
@@ -38,6 +42,7 @@
 import org.graalvm.compiler.graph.Graph;
 import org.graalvm.compiler.graph.Node;
 import org.graalvm.compiler.graph.NodeMap;
+import org.graalvm.compiler.graph.NodeSourcePosition;
 import org.graalvm.compiler.nodes.calc.FloatingNode;
 import org.graalvm.compiler.nodes.cfg.Block;
 import org.graalvm.compiler.nodes.cfg.ControlFlowGraph;
@@ -45,10 +50,6 @@
 import org.graalvm.compiler.nodes.spi.VirtualizableAllocation;
 import org.graalvm.compiler.nodes.util.GraphUtil;
 import org.graalvm.compiler.options.OptionValues;
-import org.graalvm.util.EconomicMap;
-import org.graalvm.util.EconomicSet;
-import org.graalvm.util.Equivalence;
-import org.graalvm.util.UnmodifiableEconomicMap;
 
 import jdk.vm.ci.meta.Assumptions;
 import jdk.vm.ci.meta.Assumptions.Assumption;
@@ -169,6 +170,7 @@
         private final OptionValues options;
         private Cancellable cancellable = null;
         private final DebugContext debug;
+        private NodeSourcePosition callerContext;
 
         /**
          * Creates a builder for a graph.
@@ -255,8 +257,13 @@
             return this;
         }
 
+        public Builder callerContext(NodeSourcePosition context) {
+            this.callerContext = context;
+            return this;
+        }
+
         public StructuredGraph build() {
-            return new StructuredGraph(name, rootMethod, entryBCI, assumptions, speculationLog, useProfilingInfo, compilationId, options, debug, cancellable);
+            return new StructuredGraph(name, rootMethod, entryBCI, assumptions, speculationLog, useProfilingInfo, compilationId, options, debug, cancellable, callerContext);
         }
     }
 
@@ -284,6 +291,13 @@
 
     private ScheduleResult lastSchedule;
 
+    private final InliningLog inliningLog;
+
+    /**
+     * Call stack (context) leading to construction of this graph.
+     */
+    private final NodeSourcePosition callerContext;
+
     /**
      * Records the methods that were used while constructing this graph, one entry for each time a
      * specific method is used.
@@ -317,7 +331,8 @@
                     CompilationIdentifier compilationId,
                     OptionValues options,
                     DebugContext debug,
-                    Cancellable cancellable) {
+                    Cancellable cancellable,
+                    NodeSourcePosition context) {
         super(name, options, debug);
         this.setStart(add(new StartNode()));
         this.rootMethod = method;
@@ -328,6 +343,8 @@
         this.speculationLog = speculationLog;
         this.useProfilingInfo = useProfilingInfo;
         this.cancellable = cancellable;
+        this.inliningLog = new InliningLog();
+        this.callerContext = context;
     }
 
     public void setLastSchedule(ScheduleResult result) {
@@ -436,6 +453,10 @@
         this.start = start;
     }
 
+    public InliningLog getInliningLog() {
+        return inliningLog;
+    }
+
     /**
      * Creates a copy of this graph.
      *
@@ -459,7 +480,7 @@
                         speculationLog,
                         useProfilingInfo,
                         newCompilationId,
-                        getOptions(), debugForCopy, null);
+                        getOptions(), debugForCopy, null, callerContext);
         if (allowAssumptions == AllowAssumptions.YES && assumptions != null) {
             copy.assumptions.record(assumptions);
         }
@@ -931,4 +952,8 @@
     protected void afterRegister(Node node) {
         assert hasValueProxies() || !(node instanceof ValueProxyNode);
     }
+
+    public NodeSourcePosition getCallerContext() {
+        return callerContext;
+    }
 }
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/CompareNode.java	Fri Feb 16 12:24:38 2018 -0800
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/CompareNode.java	Fri Feb 16 13:49:07 2018 -0800
@@ -25,7 +25,7 @@
 import static org.graalvm.compiler.core.common.GraalOptions.GeneratePIC;
 import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_1;
 
-import jdk.vm.ci.meta.MetaAccessProvider;
+import org.graalvm.compiler.core.common.calc.CanonicalCondition;
 import org.graalvm.compiler.core.common.calc.Condition;
 import org.graalvm.compiler.core.common.type.AbstractObjectStamp;
 import org.graalvm.compiler.core.common.type.AbstractPointerStamp;
@@ -42,17 +42,18 @@
 import org.graalvm.compiler.nodes.NodeView;
 import org.graalvm.compiler.nodes.StructuredGraph;
 import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.options.OptionValues;
 
 import jdk.vm.ci.meta.Constant;
 import jdk.vm.ci.meta.ConstantReflectionProvider;
+import jdk.vm.ci.meta.MetaAccessProvider;
 import jdk.vm.ci.meta.PrimitiveConstant;
-import org.graalvm.compiler.options.OptionValues;
 
 @NodeInfo(cycles = CYCLES_1)
 public abstract class CompareNode extends BinaryOpLogicNode implements Canonicalizable.Binary<ValueNode> {
 
     public static final NodeClass<CompareNode> TYPE = NodeClass.create(CompareNode.class);
-    protected final Condition condition;
+    protected final CanonicalCondition condition;
     protected final boolean unorderedIsTrue;
 
     /**
@@ -61,7 +62,7 @@
      * @param x the instruction producing the first input to the instruction
      * @param y the instruction that produces the second input to this instruction
      */
-    protected CompareNode(NodeClass<? extends CompareNode> c, Condition condition, boolean unorderedIsTrue, ValueNode x, ValueNode y) {
+    protected CompareNode(NodeClass<? extends CompareNode> c, CanonicalCondition condition, boolean unorderedIsTrue, ValueNode x, ValueNode y) {
         super(c, x, y);
         this.condition = condition;
         this.unorderedIsTrue = unorderedIsTrue;
@@ -72,7 +73,7 @@
      *
      * @return the condition
      */
-    public final Condition condition() {
+    public final CanonicalCondition condition() {
         return condition;
     }
 
@@ -85,7 +86,7 @@
         return this.unorderedIsTrue;
     }
 
-    public static LogicNode tryConstantFold(Condition condition, ValueNode forX, ValueNode forY, ConstantReflectionProvider constantReflection, boolean unorderedIsTrue) {
+    public static LogicNode tryConstantFold(CanonicalCondition condition, ValueNode forX, ValueNode forY, ConstantReflectionProvider constantReflection, boolean unorderedIsTrue) {
         if (forX.isConstant() && forY.isConstant() && (constantReflection != null || forX.asConstant() instanceof PrimitiveConstant)) {
             return LogicConstantNode.forBoolean(condition.foldCondition(forX.asConstant(), forY.asConstant(), constantReflection, unorderedIsTrue));
         }
@@ -93,7 +94,7 @@
     }
 
     @SuppressWarnings("unused")
-    public static LogicNode tryConstantFoldPrimitive(Condition condition, ValueNode forX, ValueNode forY, boolean unorderedIsTrue, NodeView view) {
+    public static LogicNode tryConstantFoldPrimitive(CanonicalCondition condition, ValueNode forX, ValueNode forY, boolean unorderedIsTrue, NodeView view) {
         if (forX.asConstant() instanceof PrimitiveConstant && forY.asConstant() instanceof PrimitiveConstant) {
             return LogicConstantNode.forBoolean(condition.foldCondition((PrimitiveConstant) forX.asConstant(), (PrimitiveConstant) forY.asConstant(), unorderedIsTrue));
         }
@@ -107,11 +108,11 @@
      * @return true for identity comparisons
      */
     public boolean isIdentityComparison() {
-        return condition == Condition.EQ;
+        return condition == CanonicalCondition.EQ;
     }
 
     public abstract static class CompareOp {
-        public LogicNode canonical(ConstantReflectionProvider constantReflection, MetaAccessProvider metaAccess, OptionValues options, Integer smallestCompareWidth, Condition condition,
+        public LogicNode canonical(ConstantReflectionProvider constantReflection, MetaAccessProvider metaAccess, OptionValues options, Integer smallestCompareWidth, CanonicalCondition condition,
                         boolean unorderedIsTrue, ValueNode forX, ValueNode forY, NodeView view) {
             LogicNode constantCondition = tryConstantFold(condition, forX, forY, constantReflection, unorderedIsTrue);
             if (constantCondition != null) {
@@ -151,9 +152,13 @@
         }
 
         protected LogicNode canonicalizeSymmetricConstant(ConstantReflectionProvider constantReflection, MetaAccessProvider metaAccess, OptionValues options, Integer smallestCompareWidth,
-                        Condition condition, Constant constant, ValueNode nonConstant, boolean mirrored, boolean unorderedIsTrue, NodeView view) {
+                        CanonicalCondition condition, Constant constant, ValueNode nonConstant, boolean mirrored, boolean unorderedIsTrue, NodeView view) {
             if (nonConstant instanceof ConditionalNode) {
-                return optimizeConditional(constant, (ConditionalNode) nonConstant, constantReflection, mirrored ? condition.mirror() : condition, unorderedIsTrue);
+                Condition realCondition = condition.asCondition();
+                if (mirrored) {
+                    realCondition = realCondition.mirror();
+                }
+                return optimizeConditional(constant, (ConditionalNode) nonConstant, constantReflection, realCondition, unorderedIsTrue);
             } else if (nonConstant instanceof NormalizeCompareNode) {
                 return optimizeNormalizeCompare(constantReflection, metaAccess, options, smallestCompareWidth, constant, (NormalizeCompareNode) nonConstant, mirrored, view);
             } else if (nonConstant instanceof ConvertNode) {
@@ -186,7 +191,7 @@
             return null;
         }
 
-        private static ConstantNode canonicalConvertConstant(ConstantReflectionProvider constantReflection, MetaAccessProvider metaAccess, OptionValues options, Condition condition,
+        private static ConstantNode canonicalConvertConstant(ConstantReflectionProvider constantReflection, MetaAccessProvider metaAccess, OptionValues options, CanonicalCondition condition,
                         ConvertNode convert, Constant constant, NodeView view) {
             if (convert.preservesOrder(condition, constant, constantReflection)) {
                 Constant reverseConverted = convert.reverse(constant, constantReflection);
@@ -235,18 +240,17 @@
         protected abstract LogicNode duplicateModified(ValueNode newW, ValueNode newY, boolean unorderedIsTrue, NodeView view);
     }
 
-    public static LogicNode createCompareNode(StructuredGraph graph, Condition condition, ValueNode x, ValueNode y, ConstantReflectionProvider constantReflection, NodeView view) {
+    public static LogicNode createCompareNode(StructuredGraph graph, CanonicalCondition condition, ValueNode x, ValueNode y, ConstantReflectionProvider constantReflection, NodeView view) {
         LogicNode result = createCompareNode(condition, x, y, constantReflection, view);
         return (result.graph() == null ? graph.addOrUniqueWithInputs(result) : result);
     }
 
-    public static LogicNode createCompareNode(Condition condition, ValueNode x, ValueNode y, ConstantReflectionProvider constantReflection, NodeView view) {
+    public static LogicNode createCompareNode(CanonicalCondition condition, ValueNode x, ValueNode y, ConstantReflectionProvider constantReflection, NodeView view) {
         assert x.getStackKind() == y.getStackKind();
-        assert condition.isCanonical();
         assert !x.getStackKind().isNumericFloat();
 
         LogicNode comparison;
-        if (condition == Condition.EQ) {
+        if (condition == CanonicalCondition.EQ) {
             if (x.stamp(view) instanceof AbstractObjectStamp) {
                 comparison = ObjectEqualsNode.create(x, y, constantReflection, view);
             } else if (x.stamp(view) instanceof AbstractPointerStamp) {
@@ -255,11 +259,11 @@
                 assert x.getStackKind().isNumericInteger();
                 comparison = IntegerEqualsNode.create(x, y, view);
             }
-        } else if (condition == Condition.LT) {
+        } else if (condition == CanonicalCondition.LT) {
             assert x.getStackKind().isNumericInteger();
             comparison = IntegerLessThanNode.create(x, y, view);
         } else {
-            assert condition == Condition.BT;
+            assert condition == CanonicalCondition.BT;
             assert x.getStackKind().isNumericInteger();
             comparison = IntegerBelowNode.create(x, y, view);
         }
@@ -268,19 +272,18 @@
     }
 
     public static LogicNode createCompareNode(StructuredGraph graph, ConstantReflectionProvider constantReflection, MetaAccessProvider metaAccess, OptionValues options, Integer smallestCompareWidth,
-                    Condition condition, ValueNode x, ValueNode y, NodeView view) {
+                    CanonicalCondition condition, ValueNode x, ValueNode y, NodeView view) {
         LogicNode result = createCompareNode(constantReflection, metaAccess, options, smallestCompareWidth, condition, x, y, view);
         return (result.graph() == null ? graph.addOrUniqueWithInputs(result) : result);
     }
 
     public static LogicNode createCompareNode(ConstantReflectionProvider constantReflection, MetaAccessProvider metaAccess, OptionValues options, Integer smallestCompareWidth,
-                    Condition condition, ValueNode x, ValueNode y, NodeView view) {
+                    CanonicalCondition condition, ValueNode x, ValueNode y, NodeView view) {
         assert x.getStackKind() == y.getStackKind();
-        assert condition.isCanonical();
         assert !x.getStackKind().isNumericFloat();
 
         LogicNode comparison;
-        if (condition == Condition.EQ) {
+        if (condition == CanonicalCondition.EQ) {
             if (x.stamp(view) instanceof AbstractObjectStamp) {
                 assert smallestCompareWidth == null;
                 comparison = ObjectEqualsNode.create(constantReflection, metaAccess, options, x, y, view);
@@ -290,11 +293,11 @@
                 assert x.getStackKind().isNumericInteger();
                 comparison = IntegerEqualsNode.create(constantReflection, metaAccess, options, smallestCompareWidth, x, y, view);
             }
-        } else if (condition == Condition.LT) {
+        } else if (condition == CanonicalCondition.LT) {
             assert x.getStackKind().isNumericInteger();
             comparison = IntegerLessThanNode.create(constantReflection, metaAccess, options, smallestCompareWidth, x, y, view);
         } else {
-            assert condition == Condition.BT;
+            assert condition == CanonicalCondition.BT;
             assert x.getStackKind().isNumericInteger();
             comparison = IntegerBelowNode.create(constantReflection, metaAccess, options, smallestCompareWidth, x, y, view);
         }
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/ConditionalNode.java	Fri Feb 16 12:24:38 2018 -0800
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/ConditionalNode.java	Fri Feb 16 13:49:07 2018 -0800
@@ -26,7 +26,7 @@
 import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_2;
 import static org.graalvm.compiler.nodes.calc.CompareNode.createCompareNode;
 
-import org.graalvm.compiler.core.common.calc.Condition;
+import org.graalvm.compiler.core.common.calc.CanonicalCondition;
 import org.graalvm.compiler.core.common.type.IntegerStamp;
 import org.graalvm.compiler.core.common.type.Stamp;
 import org.graalvm.compiler.core.common.type.StampFactory;
@@ -268,7 +268,7 @@
         generator.emitConditional(this);
     }
 
-    public ConditionalNode(StructuredGraph graph, Condition condition, ValueNode x, ValueNode y) {
+    public ConditionalNode(StructuredGraph graph, CanonicalCondition condition, ValueNode x, ValueNode y) {
         this(createCompareNode(graph, condition, x, y, null, NodeView.DEFAULT));
     }
 }
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/ConvertNode.java	Fri Feb 16 12:24:38 2018 -0800
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/ConvertNode.java	Fri Feb 16 13:49:07 2018 -0800
@@ -22,7 +22,7 @@
  */
 package org.graalvm.compiler.nodes.calc;
 
-import org.graalvm.compiler.core.common.calc.Condition;
+import org.graalvm.compiler.core.common.calc.CanonicalCondition;
 import org.graalvm.compiler.nodes.ValueNode;
 import org.graalvm.compiler.nodes.ValueNodeInterface;
 
@@ -61,7 +61,7 @@
      * @param op a comparison operator
      * @return true iff (c1 op c2) == (convert(c1) op convert(c2)) for all c1, c2
      */
-    default boolean preservesOrder(Condition op) {
+    default boolean preservesOrder(CanonicalCondition op) {
         return isLossless();
     }
 
@@ -73,7 +73,7 @@
      * @param constantReflection
      * @return true iff (c1 op value) == (convert(c1) op convert(value)) for value and all c1
      */
-    default boolean preservesOrder(Condition op, Constant value, ConstantReflectionProvider constantReflection) {
+    default boolean preservesOrder(CanonicalCondition op, Constant value, ConstantReflectionProvider constantReflection) {
         return preservesOrder(op);
     }
 }
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/FloatEqualsNode.java	Fri Feb 16 12:24:38 2018 -0800
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/FloatEqualsNode.java	Fri Feb 16 13:49:07 2018 -0800
@@ -22,10 +22,9 @@
  */
 package org.graalvm.compiler.nodes.calc;
 
-import jdk.vm.ci.meta.ConstantReflectionProvider;
-import jdk.vm.ci.meta.MetaAccessProvider;
-import jdk.vm.ci.meta.TriState;
-import org.graalvm.compiler.core.common.calc.Condition;
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_2;
+
+import org.graalvm.compiler.core.common.calc.CanonicalCondition;
 import org.graalvm.compiler.core.common.type.FloatStamp;
 import org.graalvm.compiler.core.common.type.IntegerStamp;
 import org.graalvm.compiler.core.common.type.Stamp;
@@ -42,7 +41,9 @@
 import org.graalvm.compiler.nodes.util.GraphUtil;
 import org.graalvm.compiler.options.OptionValues;
 
-import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_2;
+import jdk.vm.ci.meta.ConstantReflectionProvider;
+import jdk.vm.ci.meta.MetaAccessProvider;
+import jdk.vm.ci.meta.TriState;
 
 @NodeInfo(shortName = "==", cycles = CYCLES_2)
 public final class FloatEqualsNode extends CompareNode implements BinaryCommutative<ValueNode> {
@@ -50,13 +51,13 @@
     private static final FloatEqualsOp OP = new FloatEqualsOp();
 
     public FloatEqualsNode(ValueNode x, ValueNode y) {
-        super(TYPE, Condition.EQ, false, x, y);
+        super(TYPE, CanonicalCondition.EQ, false, x, y);
         assert x.stamp(NodeView.DEFAULT) instanceof FloatStamp && y.stamp(NodeView.DEFAULT) instanceof FloatStamp : x.stamp(NodeView.DEFAULT) + " " + y.stamp(NodeView.DEFAULT);
         assert x.stamp(NodeView.DEFAULT).isCompatible(y.stamp(NodeView.DEFAULT));
     }
 
     public static LogicNode create(ValueNode x, ValueNode y, NodeView view) {
-        LogicNode result = CompareNode.tryConstantFoldPrimitive(Condition.EQ, x, y, false, view);
+        LogicNode result = CompareNode.tryConstantFoldPrimitive(CanonicalCondition.EQ, x, y, false, view);
         if (result != null) {
             return result;
         } else {
@@ -66,7 +67,7 @@
 
     public static LogicNode create(ConstantReflectionProvider constantReflection, MetaAccessProvider metaAccess, OptionValues options, Integer smallestCompareWidth,
                     ValueNode x, ValueNode y, NodeView view) {
-        LogicNode value = OP.canonical(constantReflection, metaAccess, options, smallestCompareWidth, Condition.EQ, false, x, y, view);
+        LogicNode value = OP.canonical(constantReflection, metaAccess, options, smallestCompareWidth, CanonicalCondition.EQ, false, x, y, view);
         if (value != null) {
             return value;
         }
@@ -89,7 +90,7 @@
     @Override
     public Node canonical(CanonicalizerTool tool, ValueNode forX, ValueNode forY) {
         NodeView view = NodeView.from(tool);
-        ValueNode value = OP.canonical(tool.getConstantReflection(), tool.getMetaAccess(), tool.getOptions(), tool.smallestCompareWidth(), Condition.EQ, unorderedIsTrue, forX, forY, view);
+        ValueNode value = OP.canonical(tool.getConstantReflection(), tool.getMetaAccess(), tool.getOptions(), tool.smallestCompareWidth(), CanonicalCondition.EQ, unorderedIsTrue, forX, forY, view);
         if (value != null) {
             return value;
         }
@@ -99,7 +100,7 @@
     public static class FloatEqualsOp extends CompareOp {
 
         @Override
-        public LogicNode canonical(ConstantReflectionProvider constantReflection, MetaAccessProvider metaAccess, OptionValues options, Integer smallestCompareWidth, Condition condition,
+        public LogicNode canonical(ConstantReflectionProvider constantReflection, MetaAccessProvider metaAccess, OptionValues options, Integer smallestCompareWidth, CanonicalCondition condition,
                         boolean unorderedIsTrue, ValueNode forX, ValueNode forY, NodeView view) {
             LogicNode result = super.canonical(constantReflection, metaAccess, options, smallestCompareWidth, condition, unorderedIsTrue, forX, forY, view);
             if (result != null) {
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/FloatLessThanNode.java	Fri Feb 16 12:24:38 2018 -0800
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/FloatLessThanNode.java	Fri Feb 16 13:49:07 2018 -0800
@@ -22,10 +22,9 @@
  */
 package org.graalvm.compiler.nodes.calc;
 
-import jdk.vm.ci.meta.ConstantReflectionProvider;
-import jdk.vm.ci.meta.MetaAccessProvider;
-import jdk.vm.ci.meta.TriState;
-import org.graalvm.compiler.core.common.calc.Condition;
+import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_2;
+
+import org.graalvm.compiler.core.common.calc.CanonicalCondition;
 import org.graalvm.compiler.core.common.type.FloatStamp;
 import org.graalvm.compiler.core.common.type.IntegerStamp;
 import org.graalvm.compiler.core.common.type.Stamp;
@@ -41,7 +40,9 @@
 import org.graalvm.compiler.nodes.util.GraphUtil;
 import org.graalvm.compiler.options.OptionValues;
 
-import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_2;
+import jdk.vm.ci.meta.ConstantReflectionProvider;
+import jdk.vm.ci.meta.MetaAccessProvider;
+import jdk.vm.ci.meta.TriState;
 
 @NodeInfo(shortName = "<", cycles = CYCLES_2)
 public final class FloatLessThanNode extends CompareNode {
@@ -49,13 +50,13 @@
     private static final FloatLessThanOp OP = new FloatLessThanOp();
 
     public FloatLessThanNode(ValueNode x, ValueNode y, boolean unorderedIsTrue) {
-        super(TYPE, Condition.LT, unorderedIsTrue, x, y);
+        super(TYPE, CanonicalCondition.LT, unorderedIsTrue, x, y);
         assert x.stamp(NodeView.DEFAULT) instanceof FloatStamp && y.stamp(NodeView.DEFAULT) instanceof FloatStamp;
         assert x.stamp(NodeView.DEFAULT).isCompatible(y.stamp(NodeView.DEFAULT));
     }
 
     public static LogicNode create(ValueNode x, ValueNode y, boolean unorderedIsTrue, NodeView view) {
-        LogicNode result = CompareNode.tryConstantFoldPrimitive(Condition.LT, x, y, unorderedIsTrue, view);
+        LogicNode result = CompareNode.tryConstantFoldPrimitive(CanonicalCondition.LT, x, y, unorderedIsTrue, view);
         if (result != null) {
             return result;
         }
@@ -64,7 +65,7 @@
 
     public static LogicNode create(ConstantReflectionProvider constantReflection, MetaAccessProvider metaAccess, OptionValues options, Integer smallestCompareWidth,
                     ValueNode x, ValueNode y, boolean unorderedIsTrue, NodeView view) {
-        LogicNode result = OP.canonical(constantReflection, metaAccess, options, smallestCompareWidth, Condition.LT, unorderedIsTrue, x, y, view);
+        LogicNode result = OP.canonical(constantReflection, metaAccess, options, smallestCompareWidth, CanonicalCondition.LT, unorderedIsTrue, x, y, view);
         if (result != null) {
             return result;
         }
@@ -74,7 +75,7 @@
     @Override
     public Node canonical(CanonicalizerTool tool, ValueNode forX, ValueNode forY) {
         NodeView view = NodeView.from(tool);
-        ValueNode value = OP.canonical(tool.getConstantReflection(), tool.getMetaAccess(), tool.getOptions(), tool.smallestCompareWidth(), Condition.LT, unorderedIsTrue, forX, forY, view);
+        ValueNode value = OP.canonical(tool.getConstantReflection(), tool.getMetaAccess(), tool.getOptions(), tool.smallestCompareWidth(), CanonicalCondition.LT, unorderedIsTrue, forX, forY, view);
         if (value != null) {
             return value;
         }
@@ -84,7 +85,7 @@
     public static class FloatLessThanOp extends CompareOp {
 
         @Override
-        public LogicNode canonical(ConstantReflectionProvider constantReflection, MetaAccessProvider metaAccess, OptionValues options, Integer smallestCompareWidth, Condition condition,
+        public LogicNode canonical(ConstantReflectionProvider constantReflection, MetaAccessProvider metaAccess, OptionValues options, Integer smallestCompareWidth, CanonicalCondition condition,
                         boolean unorderedIsTrue, ValueNode forX, ValueNode forY, NodeView view) {
             LogicNode result = super.canonical(constantReflection, metaAccess, options, smallestCompareWidth, condition, unorderedIsTrue, forX, forY, view);
             if (result != null) {
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/IntegerBelowNode.java	Fri Feb 16 12:24:38 2018 -0800
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/IntegerBelowNode.java	Fri Feb 16 13:49:07 2018 -0800
@@ -22,10 +22,8 @@
  */
 package org.graalvm.compiler.nodes.calc;
 
-import jdk.vm.ci.meta.ConstantReflectionProvider;
-import jdk.vm.ci.meta.MetaAccessProvider;
 import org.graalvm.compiler.core.common.NumUtil;
-import org.graalvm.compiler.core.common.calc.Condition;
+import org.graalvm.compiler.core.common.calc.CanonicalCondition;
 import org.graalvm.compiler.core.common.type.IntegerStamp;
 import org.graalvm.compiler.core.common.type.StampFactory;
 import org.graalvm.compiler.graph.Node;
@@ -35,9 +33,11 @@
 import org.graalvm.compiler.nodes.LogicNode;
 import org.graalvm.compiler.nodes.NodeView;
 import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.options.OptionValues;
 
 import jdk.vm.ci.code.CodeUtil;
-import org.graalvm.compiler.options.OptionValues;
+import jdk.vm.ci.meta.ConstantReflectionProvider;
+import jdk.vm.ci.meta.MetaAccessProvider;
 
 @NodeInfo(shortName = "|<|")
 public final class IntegerBelowNode extends IntegerLowerThanNode {
@@ -126,8 +126,8 @@
         }
 
         @Override
-        protected Condition getCondition() {
-            return Condition.BT;
+        protected CanonicalCondition getCondition() {
+            return CanonicalCondition.BT;
         }
 
         @Override
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/IntegerEqualsNode.java	Fri Feb 16 12:24:38 2018 -0800
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/IntegerEqualsNode.java	Fri Feb 16 13:49:07 2018 -0800
@@ -22,9 +22,7 @@
  */
 package org.graalvm.compiler.nodes.calc;
 
-import jdk.vm.ci.meta.ConstantReflectionProvider;
-import jdk.vm.ci.meta.MetaAccessProvider;
-import org.graalvm.compiler.core.common.calc.Condition;
+import org.graalvm.compiler.core.common.calc.CanonicalCondition;
 import org.graalvm.compiler.core.common.type.AbstractPointerStamp;
 import org.graalvm.compiler.core.common.type.FloatStamp;
 import org.graalvm.compiler.core.common.type.IntegerStamp;
@@ -42,12 +40,14 @@
 import org.graalvm.compiler.nodes.NodeView;
 import org.graalvm.compiler.nodes.ValueNode;
 import org.graalvm.compiler.nodes.util.GraphUtil;
+import org.graalvm.compiler.options.OptionValues;
 
 import jdk.vm.ci.meta.Constant;
+import jdk.vm.ci.meta.ConstantReflectionProvider;
 import jdk.vm.ci.meta.JavaKind;
+import jdk.vm.ci.meta.MetaAccessProvider;
 import jdk.vm.ci.meta.PrimitiveConstant;
 import jdk.vm.ci.meta.TriState;
-import org.graalvm.compiler.options.OptionValues;
 
 @NodeInfo(shortName = "==")
 public final class IntegerEqualsNode extends CompareNode implements BinaryCommutative<ValueNode> {
@@ -55,13 +55,13 @@
     private static final IntegerEqualsOp OP = new IntegerEqualsOp();
 
     public IntegerEqualsNode(ValueNode x, ValueNode y) {
-        super(TYPE, Condition.EQ, false, x, y);
+        super(TYPE, CanonicalCondition.EQ, false, x, y);
         assert !x.getStackKind().isNumericFloat() && x.getStackKind() != JavaKind.Object;
         assert !y.getStackKind().isNumericFloat() && y.getStackKind() != JavaKind.Object;
     }
 
     public static LogicNode create(ValueNode x, ValueNode y, NodeView view) {
-        LogicNode result = CompareNode.tryConstantFoldPrimitive(Condition.EQ, x, y, false, view);
+        LogicNode result = CompareNode.tryConstantFoldPrimitive(CanonicalCondition.EQ, x, y, false, view);
         if (result != null) {
             return result;
         }
@@ -87,7 +87,7 @@
 
     public static LogicNode create(ConstantReflectionProvider constantReflection, MetaAccessProvider metaAccess, OptionValues options, Integer smallestCompareWidth, ValueNode x, ValueNode y,
                     NodeView view) {
-        LogicNode value = OP.canonical(constantReflection, metaAccess, options, smallestCompareWidth, Condition.EQ, false, x, y, view);
+        LogicNode value = OP.canonical(constantReflection, metaAccess, options, smallestCompareWidth, CanonicalCondition.EQ, false, x, y, view);
         if (value != null) {
             return value;
         }
@@ -97,7 +97,7 @@
     @Override
     public Node canonical(CanonicalizerTool tool, ValueNode forX, ValueNode forY) {
         NodeView view = NodeView.from(tool);
-        ValueNode value = OP.canonical(tool.getConstantReflection(), tool.getMetaAccess(), tool.getOptions(), tool.smallestCompareWidth(), Condition.EQ, false, forX, forY, view);
+        ValueNode value = OP.canonical(tool.getConstantReflection(), tool.getMetaAccess(), tool.getOptions(), tool.smallestCompareWidth(), CanonicalCondition.EQ, false, forX, forY, view);
         if (value != null) {
             return value;
         }
@@ -149,7 +149,7 @@
         }
 
         @Override
-        public LogicNode canonical(ConstantReflectionProvider constantReflection, MetaAccessProvider metaAccess, OptionValues options, Integer smallestCompareWidth, Condition condition,
+        public LogicNode canonical(ConstantReflectionProvider constantReflection, MetaAccessProvider metaAccess, OptionValues options, Integer smallestCompareWidth, CanonicalCondition condition,
                         boolean unorderedIsTrue, ValueNode forX, ValueNode forY, NodeView view) {
             if (GraphUtil.unproxify(forX) == GraphUtil.unproxify(forY)) {
                 return LogicConstantNode.tautology();
@@ -186,7 +186,7 @@
 
         @Override
         protected LogicNode canonicalizeSymmetricConstant(ConstantReflectionProvider constantReflection, MetaAccessProvider metaAccess, OptionValues options, Integer smallestCompareWidth,
-                        Condition condition, Constant constant, ValueNode nonConstant, boolean mirrored, boolean unorderedIsTrue, NodeView view) {
+                        CanonicalCondition condition, Constant constant, ValueNode nonConstant, boolean mirrored, boolean unorderedIsTrue, NodeView view) {
             if (constant instanceof PrimitiveConstant) {
                 PrimitiveConstant primitiveConstant = (PrimitiveConstant) constant;
                 IntegerStamp nonConstantStamp = ((IntegerStamp) nonConstant.stamp(view));
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/IntegerLessThanNode.java	Fri Feb 16 12:24:38 2018 -0800
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/IntegerLessThanNode.java	Fri Feb 16 13:49:07 2018 -0800
@@ -22,12 +22,10 @@
  */
 package org.graalvm.compiler.nodes.calc;
 
-import static org.graalvm.compiler.core.common.calc.Condition.LT;
+import static org.graalvm.compiler.core.common.calc.CanonicalCondition.LT;
 
-import jdk.vm.ci.meta.ConstantReflectionProvider;
-import jdk.vm.ci.meta.MetaAccessProvider;
 import org.graalvm.compiler.core.common.NumUtil;
-import org.graalvm.compiler.core.common.calc.Condition;
+import org.graalvm.compiler.core.common.calc.CanonicalCondition;
 import org.graalvm.compiler.core.common.type.FloatStamp;
 import org.graalvm.compiler.core.common.type.IntegerStamp;
 import org.graalvm.compiler.core.common.type.StampFactory;
@@ -42,13 +40,15 @@
 import org.graalvm.compiler.nodes.LogicNode;
 import org.graalvm.compiler.nodes.NodeView;
 import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.options.OptionValues;
 
 import jdk.vm.ci.code.CodeUtil;
 import jdk.vm.ci.meta.Constant;
+import jdk.vm.ci.meta.ConstantReflectionProvider;
 import jdk.vm.ci.meta.JavaConstant;
 import jdk.vm.ci.meta.JavaKind;
+import jdk.vm.ci.meta.MetaAccessProvider;
 import jdk.vm.ci.meta.PrimitiveConstant;
-import org.graalvm.compiler.options.OptionValues;
 
 @NodeInfo(shortName = "<")
 public final class IntegerLessThanNode extends IntegerLowerThanNode {
@@ -258,7 +258,7 @@
         }
 
         @Override
-        protected Condition getCondition() {
+        protected CanonicalCondition getCondition() {
             return LT;
         }
 
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/IntegerLowerThanNode.java	Fri Feb 16 12:24:38 2018 -0800
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/IntegerLowerThanNode.java	Fri Feb 16 13:49:07 2018 -0800
@@ -22,9 +22,7 @@
  */
 package org.graalvm.compiler.nodes.calc;
 
-import jdk.vm.ci.meta.ConstantReflectionProvider;
-import jdk.vm.ci.meta.MetaAccessProvider;
-import org.graalvm.compiler.core.common.calc.Condition;
+import org.graalvm.compiler.core.common.calc.CanonicalCondition;
 import org.graalvm.compiler.core.common.type.IntegerStamp;
 import org.graalvm.compiler.core.common.type.Stamp;
 import org.graalvm.compiler.graph.NodeClass;
@@ -36,9 +34,11 @@
 import org.graalvm.compiler.nodes.NodeView;
 import org.graalvm.compiler.nodes.ValueNode;
 import org.graalvm.compiler.nodes.util.GraphUtil;
+import org.graalvm.compiler.options.OptionValues;
 
+import jdk.vm.ci.meta.ConstantReflectionProvider;
+import jdk.vm.ci.meta.MetaAccessProvider;
 import jdk.vm.ci.meta.TriState;
-import org.graalvm.compiler.options.OptionValues;
 
 /**
  * Common super-class for "a < b" comparisons both {@linkplain IntegerLowerThanNode signed} and
@@ -117,7 +117,7 @@
 
     public abstract static class LowerOp extends CompareOp {
         @Override
-        public LogicNode canonical(ConstantReflectionProvider constantReflection, MetaAccessProvider metaAccess, OptionValues options, Integer smallestCompareWidth, Condition condition,
+        public LogicNode canonical(ConstantReflectionProvider constantReflection, MetaAccessProvider metaAccess, OptionValues options, Integer smallestCompareWidth, CanonicalCondition condition,
                         boolean unorderedIsTrue, ValueNode forX, ValueNode forY, NodeView view) {
             LogicNode result = super.canonical(constantReflection, metaAccess, options, smallestCompareWidth, condition, unorderedIsTrue, forX, forY, view);
             if (result != null) {
@@ -156,7 +156,7 @@
 
         protected abstract IntegerStamp forInteger(int bits, long min, long max);
 
-        protected abstract Condition getCondition();
+        protected abstract CanonicalCondition getCondition();
 
         protected abstract IntegerLowerThanNode createNode(ValueNode x, ValueNode y);
 
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/NarrowNode.java	Fri Feb 16 12:24:38 2018 -0800
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/NarrowNode.java	Fri Feb 16 13:49:07 2018 -0800
@@ -112,9 +112,9 @@
                     // ==> sxxx -(sign-extend)-> sssssxxx
                     return SignExtendNode.create(other.getValue(), other.getInputBits(), getResultBits(), view);
                 } else if (other instanceof ZeroExtendNode) {
-                    // xxxx -(zero-extend)-> 00000000 00000xxx -(narrow)-> 0000xxxx
+                    // xxxx -(zero-extend)-> 00000000 0000xxxx -(narrow)-> 0000xxxx
                     // ==> xxxx -(zero-extend)-> 0000xxxx
-                    return new ZeroExtendNode(other.getValue(), other.getInputBits(), getResultBits());
+                    return new ZeroExtendNode(other.getValue(), other.getInputBits(), getResultBits(), ((ZeroExtendNode) other).isInputAlwaysPositive());
                 }
             }
         } else if (forValue instanceof AndNode) {
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/NormalizeCompareNode.java	Fri Feb 16 12:24:38 2018 -0800
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/NormalizeCompareNode.java	Fri Feb 16 13:49:07 2018 -0800
@@ -24,7 +24,7 @@
 
 import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_2;
 
-import org.graalvm.compiler.core.common.calc.Condition;
+import org.graalvm.compiler.core.common.calc.CanonicalCondition;
 import org.graalvm.compiler.core.common.type.Stamp;
 import org.graalvm.compiler.core.common.type.StampFactory;
 import org.graalvm.compiler.graph.IterableNodeType;
@@ -67,10 +67,10 @@
     }
 
     protected static ValueNode tryConstantFold(ValueNode x, ValueNode y, boolean isUnorderedLess, JavaKind kind, ConstantReflectionProvider constantReflection) {
-        LogicNode result = CompareNode.tryConstantFold(Condition.EQ, x, y, null, false);
+        LogicNode result = CompareNode.tryConstantFold(CanonicalCondition.EQ, x, y, null, false);
         if (result instanceof LogicConstantNode) {
             LogicConstantNode logicConstantNode = (LogicConstantNode) result;
-            LogicNode resultLT = CompareNode.tryConstantFold(Condition.LT, x, y, constantReflection, isUnorderedLess);
+            LogicNode resultLT = CompareNode.tryConstantFold(CanonicalCondition.LT, x, y, constantReflection, isUnorderedLess);
             if (resultLT instanceof LogicConstantNode) {
                 LogicConstantNode logicConstantNodeLT = (LogicConstantNode) resultLT;
                 if (logicConstantNodeLT.getValue()) {
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/ObjectEqualsNode.java	Fri Feb 16 12:24:38 2018 -0800
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/ObjectEqualsNode.java	Fri Feb 16 13:49:07 2018 -0800
@@ -22,7 +22,7 @@
  */
 package org.graalvm.compiler.nodes.calc;
 
-import org.graalvm.compiler.core.common.calc.Condition;
+import org.graalvm.compiler.core.common.calc.CanonicalCondition;
 import org.graalvm.compiler.core.common.type.AbstractObjectStamp;
 import org.graalvm.compiler.core.common.type.AbstractPointerStamp;
 import org.graalvm.compiler.core.common.type.ObjectStamp;
@@ -42,6 +42,7 @@
 import org.graalvm.compiler.nodes.spi.VirtualizerTool;
 import org.graalvm.compiler.nodes.virtual.VirtualBoxingNode;
 import org.graalvm.compiler.nodes.virtual.VirtualObjectNode;
+import org.graalvm.compiler.options.OptionValues;
 
 import jdk.vm.ci.meta.Constant;
 import jdk.vm.ci.meta.ConstantReflectionProvider;
@@ -49,7 +50,6 @@
 import jdk.vm.ci.meta.JavaKind;
 import jdk.vm.ci.meta.MetaAccessProvider;
 import jdk.vm.ci.meta.ResolvedJavaType;
-import org.graalvm.compiler.options.OptionValues;
 
 @NodeInfo(shortName = "==")
 public final class ObjectEqualsNode extends PointerEqualsNode implements Virtualizable {
@@ -64,7 +64,7 @@
     }
 
     public static LogicNode create(ValueNode x, ValueNode y, ConstantReflectionProvider constantReflection, NodeView view) {
-        LogicNode result = CompareNode.tryConstantFold(Condition.EQ, x, y, constantReflection, false);
+        LogicNode result = CompareNode.tryConstantFold(CanonicalCondition.EQ, x, y, constantReflection, false);
         if (result != null) {
             return result;
         } else {
@@ -77,7 +77,7 @@
     }
 
     public static LogicNode create(ConstantReflectionProvider constantReflection, MetaAccessProvider metaAccess, OptionValues options, ValueNode x, ValueNode y, NodeView view) {
-        LogicNode result = OP.canonical(constantReflection, metaAccess, options, null, Condition.EQ, false, x, y, view);
+        LogicNode result = OP.canonical(constantReflection, metaAccess, options, null, CanonicalCondition.EQ, false, x, y, view);
         if (result != null) {
             return result;
         }
@@ -87,7 +87,7 @@
     @Override
     public ValueNode canonical(CanonicalizerTool tool, ValueNode forX, ValueNode forY) {
         NodeView view = NodeView.from(tool);
-        ValueNode value = OP.canonical(tool.getConstantReflection(), tool.getMetaAccess(), tool.getOptions(), tool.smallestCompareWidth(), Condition.EQ, false, forX, forY, view);
+        ValueNode value = OP.canonical(tool.getConstantReflection(), tool.getMetaAccess(), tool.getOptions(), tool.smallestCompareWidth(), CanonicalCondition.EQ, false, forX, forY, view);
         if (value != null) {
             return value;
         }
@@ -98,7 +98,7 @@
 
         @Override
         protected LogicNode canonicalizeSymmetricConstant(ConstantReflectionProvider constantReflection, MetaAccessProvider metaAccess, OptionValues options, Integer smallestCompareWidth,
-                        Condition condition, Constant constant, ValueNode nonConstant, boolean mirrored, boolean unorderedIsTrue, NodeView view) {
+                        CanonicalCondition condition, Constant constant, ValueNode nonConstant, boolean mirrored, boolean unorderedIsTrue, NodeView view) {
             ResolvedJavaType type = constantReflection.asJavaType(constant);
             if (type != null && nonConstant instanceof GetClassNode) {
                 GetClassNode getClassNode = (GetClassNode) nonConstant;
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/PointerEqualsNode.java	Fri Feb 16 12:24:38 2018 -0800
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/PointerEqualsNode.java	Fri Feb 16 13:49:07 2018 -0800
@@ -22,9 +22,7 @@
  */
 package org.graalvm.compiler.nodes.calc;
 
-import jdk.vm.ci.meta.ConstantReflectionProvider;
-import jdk.vm.ci.meta.MetaAccessProvider;
-import org.graalvm.compiler.core.common.calc.Condition;
+import org.graalvm.compiler.core.common.calc.CanonicalCondition;
 import org.graalvm.compiler.core.common.type.AbstractPointerStamp;
 import org.graalvm.compiler.core.common.type.ObjectStamp;
 import org.graalvm.compiler.core.common.type.Stamp;
@@ -41,11 +39,13 @@
 import org.graalvm.compiler.nodes.extended.LoadMethodNode;
 import org.graalvm.compiler.nodes.type.StampTool;
 import org.graalvm.compiler.nodes.util.GraphUtil;
+import org.graalvm.compiler.options.OptionValues;
 
+import jdk.vm.ci.meta.ConstantReflectionProvider;
+import jdk.vm.ci.meta.MetaAccessProvider;
 import jdk.vm.ci.meta.ResolvedJavaMethod;
 import jdk.vm.ci.meta.ResolvedJavaType;
 import jdk.vm.ci.meta.TriState;
-import org.graalvm.compiler.options.OptionValues;
 
 @NodeInfo(shortName = "==")
 public class PointerEqualsNode extends CompareNode implements BinaryCommutative<ValueNode> {
@@ -66,7 +66,7 @@
     }
 
     protected PointerEqualsNode(NodeClass<? extends PointerEqualsNode> c, ValueNode x, ValueNode y) {
-        super(c, Condition.EQ, false, x, y);
+        super(c, CanonicalCondition.EQ, false, x, y);
         assert x.stamp(NodeView.DEFAULT) instanceof AbstractPointerStamp;
         assert y.stamp(NodeView.DEFAULT) instanceof AbstractPointerStamp;
     }
@@ -74,7 +74,7 @@
     @Override
     public Node canonical(CanonicalizerTool tool, ValueNode forX, ValueNode forY) {
         NodeView view = NodeView.from(tool);
-        ValueNode value = OP.canonical(tool.getConstantReflection(), tool.getMetaAccess(), tool.getOptions(), tool.smallestCompareWidth(), Condition.EQ, false, forX, forY, view);
+        ValueNode value = OP.canonical(tool.getConstantReflection(), tool.getMetaAccess(), tool.getOptions(), tool.smallestCompareWidth(), CanonicalCondition.EQ, false, forX, forY, view);
         if (value != null) {
             return value;
         }
@@ -88,9 +88,9 @@
          * could select a certain method and if so, returns {@code true} if the answer is guaranteed
          * to be false. Otherwise, returns {@code false}.
          */
-        private static boolean isAlwaysFailingVirtualDispatchTest(Condition condition, ValueNode forX, ValueNode forY) {
+        private static boolean isAlwaysFailingVirtualDispatchTest(CanonicalCondition condition, ValueNode forX, ValueNode forY) {
             if (forY.isConstant()) {
-                if (forX instanceof LoadMethodNode && condition == Condition.EQ) {
+                if (forX instanceof LoadMethodNode && condition == CanonicalCondition.EQ) {
                     LoadMethodNode lm = ((LoadMethodNode) forX);
                     if (lm.getMethod().getEncoding().equals(forY.asConstant())) {
                         if (lm.getHub() instanceof LoadHubNode) {
@@ -112,7 +112,7 @@
         }
 
         @Override
-        public LogicNode canonical(ConstantReflectionProvider constantReflection, MetaAccessProvider metaAccess, OptionValues options, Integer smallestCompareWidth, Condition condition,
+        public LogicNode canonical(ConstantReflectionProvider constantReflection, MetaAccessProvider metaAccess, OptionValues options, Integer smallestCompareWidth, CanonicalCondition condition,
                         boolean unorderedIsTrue, ValueNode forX, ValueNode forY, NodeView view) {
             LogicNode result = findSynonym(forX, forY, view);
             if (result != null) {
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/SignExtendNode.java	Fri Feb 16 12:24:38 2018 -0800
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/SignExtendNode.java	Fri Feb 16 13:49:07 2018 -0800
@@ -95,7 +95,7 @@
             if (other.getResultBits() > other.getInputBits()) {
                 // sxxx -(zero-extend)-> 0000 sxxx -(sign-extend)-> 00000000 0000sxxx
                 // ==> sxxx -(zero-extend)-> 00000000 0000sxxx
-                return ZeroExtendNode.create(other.getValue(), other.getInputBits(), resultBits, view);
+                return ZeroExtendNode.create(other.getValue(), other.getInputBits(), resultBits, view, other.isInputAlwaysPositive());
             }
         }
 
@@ -104,7 +104,7 @@
             if ((inputStamp.upMask() & (1L << (inputBits - 1))) == 0L) {
                 // 0xxx -(sign-extend)-> 0000 0xxx
                 // ==> 0xxx -(zero-extend)-> 0000 0xxx
-                return ZeroExtendNode.create(forValue, inputBits, resultBits, view);
+                return ZeroExtendNode.create(forValue, inputBits, resultBits, view, true);
             }
         }
 
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/ZeroExtendNode.java	Fri Feb 16 12:24:38 2018 -0800
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/calc/ZeroExtendNode.java	Fri Feb 16 13:49:07 2018 -0800
@@ -24,7 +24,7 @@
 
 import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_1;
 
-import org.graalvm.compiler.core.common.calc.Condition;
+import org.graalvm.compiler.core.common.calc.CanonicalCondition;
 import org.graalvm.compiler.core.common.type.ArithmeticOpTable;
 import org.graalvm.compiler.core.common.type.ArithmeticOpTable.IntegerConvertOp;
 import org.graalvm.compiler.core.common.type.ArithmeticOpTable.IntegerConvertOp.Narrow;
@@ -50,26 +50,33 @@
 
     public static final NodeClass<ZeroExtendNode> TYPE = NodeClass.create(ZeroExtendNode.class);
 
+    private final boolean inputAlwaysPositive;
+
     public ZeroExtendNode(ValueNode input, int resultBits) {
-        this(input, PrimitiveStamp.getBits(input.stamp(NodeView.DEFAULT)), resultBits);
+        this(input, PrimitiveStamp.getBits(input.stamp(NodeView.DEFAULT)), resultBits, false);
         assert 0 < PrimitiveStamp.getBits(input.stamp(NodeView.DEFAULT)) && PrimitiveStamp.getBits(input.stamp(NodeView.DEFAULT)) <= resultBits;
     }
 
-    public ZeroExtendNode(ValueNode input, int inputBits, int resultBits) {
+    public ZeroExtendNode(ValueNode input, int inputBits, int resultBits, boolean inputAlwaysPositive) {
         super(TYPE, ArithmeticOpTable::getZeroExtend, ArithmeticOpTable::getNarrow, inputBits, resultBits, input);
+        this.inputAlwaysPositive = inputAlwaysPositive;
     }
 
     public static ValueNode create(ValueNode input, int resultBits, NodeView view) {
-        return create(input, PrimitiveStamp.getBits(input.stamp(view)), resultBits, view);
+        return create(input, PrimitiveStamp.getBits(input.stamp(view)), resultBits, view, false);
     }
 
     public static ValueNode create(ValueNode input, int inputBits, int resultBits, NodeView view) {
+        return create(input, inputBits, resultBits, view, false);
+    }
+
+    public static ValueNode create(ValueNode input, int inputBits, int resultBits, NodeView view, boolean alwaysPositive) {
         IntegerConvertOp<ZeroExtend> signExtend = ArithmeticOpTable.forStamp(input.stamp(view)).getZeroExtend();
         ValueNode synonym = findSynonym(signExtend, input, inputBits, resultBits, signExtend.foldStamp(inputBits, resultBits, input.stamp(view)));
         if (synonym != null) {
             return synonym;
         }
-        return canonical(null, input, inputBits, resultBits, view);
+        return canonical(null, input, inputBits, resultBits, view, alwaysPositive);
     }
 
     @Override
@@ -77,12 +84,13 @@
         return true;
     }
 
+    public boolean isInputAlwaysPositive() {
+        return inputAlwaysPositive;
+    }
+
     @Override
-    public boolean preservesOrder(Condition cond) {
+    public boolean preservesOrder(CanonicalCondition cond) {
         switch (cond) {
-            case GE:
-            case GT:
-            case LE:
             case LT:
                 return false;
             default:
@@ -98,16 +106,16 @@
             return ret;
         }
 
-        return canonical(this, forValue, getInputBits(), getResultBits(), view);
+        return canonical(this, forValue, getInputBits(), getResultBits(), view, inputAlwaysPositive);
     }
 
-    private static ValueNode canonical(ZeroExtendNode zeroExtendNode, ValueNode forValue, int inputBits, int resultBits, NodeView view) {
+    private static ValueNode canonical(ZeroExtendNode zeroExtendNode, ValueNode forValue, int inputBits, int resultBits, NodeView view, boolean alwaysPositive) {
         ZeroExtendNode self = zeroExtendNode;
         if (forValue instanceof ZeroExtendNode) {
             // xxxx -(zero-extend)-> 0000 xxxx -(zero-extend)-> 00000000 0000xxxx
             // ==> xxxx -(zero-extend)-> 00000000 0000xxxx
             ZeroExtendNode other = (ZeroExtendNode) forValue;
-            return new ZeroExtendNode(other.getValue(), other.getInputBits(), resultBits);
+            return new ZeroExtendNode(other.getValue(), other.getInputBits(), resultBits, other.isInputAlwaysPositive());
         }
         if (forValue instanceof NarrowNode) {
             NarrowNode narrow = (NarrowNode) forValue;
@@ -135,7 +143,7 @@
         }
 
         if (self == null) {
-            self = new ZeroExtendNode(forValue, inputBits, resultBits);
+            self = new ZeroExtendNode(forValue, inputBits, resultBits, alwaysPositive);
         }
         return self;
     }
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/cfg/Block.java	Fri Feb 16 12:24:38 2018 -0800
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/cfg/Block.java	Fri Feb 16 13:49:07 2018 -0800
@@ -42,7 +42,6 @@
 import org.graalvm.word.LocationIdentity;
 
 public final class Block extends AbstractBlockBase<Block> {
-
     public static final Block[] EMPTY_ARRAY = new Block[0];
 
     protected final AbstractBeginNode beginNode;
@@ -53,7 +52,6 @@
     private Loop<Block> loop;
 
     protected Block postdominator;
-    protected Block distancedDominatorCache;
     private LocationSet killLocations;
     private LocationSet killLocationsBetweenThisAndDominator;
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/ArrayRangeWrite.java	Fri Feb 16 13:49:07 2018 -0800
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.nodes.extended;
+
+import org.graalvm.compiler.graph.NodeInterface;
+import org.graalvm.compiler.nodes.FixedWithNextNode;
+import org.graalvm.compiler.nodes.ValueNode;
+import org.graalvm.compiler.nodes.memory.address.AddressNode;
+
+public interface ArrayRangeWrite extends NodeInterface {
+    AddressNode getAddress();
+
+    /**
+     * The length of the modified range.
+     */
+    ValueNode getLength();
+
+    /**
+     * Return true if the written array is an object array, false if it is a primitive array.
+     */
+    boolean writesObjectArray();
+
+    /**
+     * Returns whether this write is the initialization of the written location. If it is true, the
+     * old value of the memory location is either uninitialized or zero. If it is false, the memory
+     * location is guaranteed to contain a valid value or zero.
+     */
+    boolean isInitialization();
+
+    int getElementStride();
+
+    @Override
+    FixedWithNextNode asNode();
+}
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/ArrayRangeWriteNode.java	Fri Feb 16 12:24:38 2018 -0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,72 +0,0 @@
-/*
- * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package org.graalvm.compiler.nodes.extended;
-
-import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_UNKNOWN;
-import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_UNKNOWN;
-
-import org.graalvm.compiler.core.common.type.Stamp;
-import org.graalvm.compiler.graph.NodeClass;
-import org.graalvm.compiler.nodeinfo.NodeInfo;
-import org.graalvm.compiler.nodes.ValueNode;
-import org.graalvm.compiler.nodes.memory.AbstractMemoryCheckpoint;
-
-/**
- * Base class for nodes that modify a range of an array.
- */
-@NodeInfo(cycles = CYCLES_UNKNOWN, size = SIZE_UNKNOWN)
-public abstract class ArrayRangeWriteNode extends AbstractMemoryCheckpoint {
-
-    public static final NodeClass<ArrayRangeWriteNode> TYPE = NodeClass.create(ArrayRangeWriteNode.class);
-
-    protected ArrayRangeWriteNode(NodeClass<? extends ArrayRangeWriteNode> c, Stamp stamp) {
-        super(c, stamp);
-    }
-
-    /**
-     * The array that is written to.
-     */
-    public abstract ValueNode getArray();
-
-    /**
-     * The first modified index.
-     */
-    public abstract ValueNode getIndex();
-
-    /**
-     * The length of the modified range.
-     */
-    public abstract ValueNode getLength();
-
-    /**
-     * Return true if the written array is an object array, false if it is a primitive array.
-     */
-    public abstract boolean isObjectArray();
-
-    /**
-     * Returns whether this write is the initialization of the written location. If it is true, the
-     * old value of the memory location is either uninitialized or zero. If it is false, the memory
-     * location is guaranteed to contain a valid value or zero.
-     */
-    public abstract boolean isInitialization();
-}
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/BranchProbabilityNode.java	Fri Feb 16 12:24:38 2018 -0800
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/BranchProbabilityNode.java	Fri Feb 16 13:49:07 2018 -0800
@@ -25,7 +25,7 @@
 import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_0;
 import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_0;
 
-import org.graalvm.compiler.core.common.calc.Condition;
+import org.graalvm.compiler.core.common.calc.CanonicalCondition;
 import org.graalvm.compiler.debug.GraalError;
 import org.graalvm.compiler.graph.NodeClass;
 import org.graalvm.compiler.graph.iterators.NodePredicates;
@@ -101,7 +101,7 @@
             }
             boolean usageFound = false;
             for (IntegerEqualsNode node : this.usages().filter(IntegerEqualsNode.class)) {
-                assert node.condition() == Condition.EQ;
+                assert node.condition() == CanonicalCondition.EQ;
                 ValueNode other = node.getX();
                 if (node.getX() == this) {
                     other = node.getY();
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/RawLoadNode.java	Fri Feb 16 12:24:38 2018 -0800
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/RawLoadNode.java	Fri Feb 16 13:49:07 2018 -0800
@@ -97,7 +97,7 @@
             ValueNode offsetValue = tool.getAlias(offset());
             if (offsetValue.isConstant()) {
                 long off = offsetValue.asJavaConstant().asLong();
-                int entryIndex = virtual.entryIndexForOffset(off, accessKind());
+                int entryIndex = virtual.entryIndexForOffset(tool.getArrayOffsetProvider(), off, accessKind());
 
                 if (entryIndex != -1) {
                     ValueNode entry = tool.getEntry(virtual, entryIndex);
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/RawStoreNode.java	Fri Feb 16 12:24:38 2018 -0800
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/RawStoreNode.java	Fri Feb 16 13:49:07 2018 -0800
@@ -119,7 +119,7 @@
             ValueNode indexValue = tool.getAlias(offset());
             if (indexValue.isConstant()) {
                 long off = indexValue.asJavaConstant().asLong();
-                int entryIndex = virtual.entryIndexForOffset(off, accessKind());
+                int entryIndex = virtual.entryIndexForOffset(tool.getArrayOffsetProvider(), off, accessKind());
                 if (entryIndex != -1 && tool.setVirtualEntry(virtual, entryIndex, value(), accessKind(), off)) {
                     tool.delete();
                 }
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/SwitchNode.java	Fri Feb 16 12:24:38 2018 -0800
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/extended/SwitchNode.java	Fri Feb 16 13:49:07 2018 -0800
@@ -228,7 +228,7 @@
 
     @Override
     public AbstractBeginNode getPrimarySuccessor() {
-        return this.defaultSuccessor();
+        return null;
     }
 
     /**
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/graphbuilderconf/InlineInvokePlugin.java	Fri Feb 16 12:24:38 2018 -0800
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/graphbuilderconf/InlineInvokePlugin.java	Fri Feb 16 13:49:07 2018 -0800
@@ -82,6 +82,10 @@
             return methodToInline;
         }
 
+        public boolean allowsInlining() {
+            return methodToInline != null;
+        }
+
         /**
          * Gets the provider of bytecode to be parsed for {@link #getMethodToInline()} if is is an
          * intrinsic for the original method (i.e., the {@code method} passed to
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/graphbuilderconf/InvocationPlugins.java	Fri Feb 16 12:24:38 2018 -0800
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/graphbuilderconf/InvocationPlugins.java	Fri Feb 16 13:49:07 2018 -0800
@@ -35,6 +35,12 @@
 import java.util.List;
 import java.util.Map;
 
+import org.graalvm.collections.EconomicMap;
+import org.graalvm.collections.Equivalence;
+import org.graalvm.collections.MapCursor;
+import org.graalvm.collections.Pair;
+import org.graalvm.collections.UnmodifiableEconomicMap;
+import org.graalvm.collections.UnmodifiableMapCursor;
 import org.graalvm.compiler.api.replacements.MethodSubstitution;
 import org.graalvm.compiler.api.replacements.MethodSubstitutionRegistry;
 import org.graalvm.compiler.bytecode.BytecodeProvider;
@@ -44,12 +50,6 @@
 import org.graalvm.compiler.graph.iterators.NodeIterable;
 import org.graalvm.compiler.nodes.ValueNode;
 import org.graalvm.compiler.nodes.graphbuilderconf.InvocationPlugin.Receiver;
-import org.graalvm.util.EconomicMap;
-import org.graalvm.util.Equivalence;
-import org.graalvm.util.MapCursor;
-import org.graalvm.util.Pair;
-import org.graalvm.util.UnmodifiableEconomicMap;
-import org.graalvm.util.UnmodifiableMapCursor;
 
 import jdk.vm.ci.meta.MetaUtil;
 import jdk.vm.ci.meta.ResolvedJavaMethod;
@@ -112,6 +112,26 @@
     }
 
     /**
+     * A symbol for an already resolved method.
+     */
+    public static class ResolvedJavaSymbol implements Type {
+        private final ResolvedJavaType resolved;
+
+        public ResolvedJavaSymbol(ResolvedJavaType type) {
+            this.resolved = type;
+        }
+
+        public ResolvedJavaType getResolved() {
+            return resolved;
+        }
+
+        @Override
+        public String toString() {
+            return resolved.toJavaName();
+        }
+    }
+
+    /**
      * A symbol that is lazily {@linkplain OptionalLazySymbol#resolve() resolved} to a {@link Type}.
      */
     static class OptionalLazySymbol implements Type {
@@ -696,7 +716,7 @@
      *
      * @param declaringClass the class to test
      */
-    protected boolean canBeIntrinsified(ResolvedJavaType declaringClass) {
+    public boolean canBeIntrinsified(ResolvedJavaType declaringClass) {
         return true;
     }
 
@@ -1150,6 +1170,9 @@
         }
 
         static boolean checkResolvable(boolean isOptional, Type declaringType, Binding binding) {
+            if (declaringType instanceof ResolvedJavaSymbol) {
+                return checkResolvable(isOptional, ((ResolvedJavaSymbol) declaringType).getResolved(), binding);
+            }
             Class<?> declaringClass = InvocationPlugins.resolveType(declaringType, isOptional);
             if (declaringClass == null) {
                 return true;
@@ -1165,6 +1188,13 @@
             }
             return true;
         }
+
+        private static boolean checkResolvable(boolean isOptional, ResolvedJavaType declaringType, Binding binding) {
+            if (resolveJavaMethod(declaringType, binding) == null && !isOptional) {
+                throw new AssertionError(String.format("Method not found: %s.%s%s", declaringType.toJavaName(), binding.name, binding.argumentsDescriptor));
+            }
+            return true;
+        }
     }
 
     /**
@@ -1235,7 +1265,7 @@
      * {@link NoSuchMethodError} is thrown.
      *
      * @param declaringClass the class to search for a method matching {@code binding}
-     * @return the method (if any) in {@code declaringClass} matching binding
+     * @return the method (if any) in {@code declaringClass} matching {@code binding}
      */
     public static Method resolveMethod(Class<?> declaringClass, Binding binding) {
         if (binding.name.equals("<init>")) {
@@ -1243,32 +1273,70 @@
         }
         Method[] methods = declaringClass.getDeclaredMethods();
         List<String> parameterTypeNames = parseParameters(binding.argumentsDescriptor);
+        Method match = null;
         for (int i = 0; i < methods.length; ++i) {
             Method m = methods[i];
-            if (binding.isStatic == Modifier.isStatic(m.getModifiers()) && m.getName().equals(binding.name)) {
-                if (parameterTypeNames.equals(toInternalTypeNames(m.getParameterTypes()))) {
-                    for (int j = i + 1; j < methods.length; ++j) {
-                        Method other = methods[j];
-                        if (binding.isStatic == Modifier.isStatic(other.getModifiers()) && other.getName().equals(binding.name)) {
-                            if (parameterTypeNames.equals(toInternalTypeNames(other.getParameterTypes()))) {
-                                if (m.getReturnType().isAssignableFrom(other.getReturnType())) {
-                                    // `other` has a more specific return type - choose it
-                                    // (m is most likely a bridge method)
-                                    m = other;
-                                } else {
-                                    if (!other.getReturnType().isAssignableFrom(m.getReturnType())) {
-                                        throw new NoSuchMethodError(String.format(
-                                                        "Found 2 methods with same name and parameter types but unrelated return types:%n %s%n %s", m, other));
-                                    }
-                                }
-                            }
-                        }
+            if (binding.isStatic == Modifier.isStatic(m.getModifiers()) &&
+                            m.getName().equals(binding.name) &&
+                            parameterTypeNames.equals(toInternalTypeNames(m.getParameterTypes()))) {
+                if (match == null) {
+                    match = m;
+                } else if (match.getReturnType().isAssignableFrom(m.getReturnType())) {
+                    // `m` has a more specific return type - choose it
+                    // (`match` is most likely a bridge method)
+                    match = m;
+                } else {
+                    if (!m.getReturnType().isAssignableFrom(match.getReturnType())) {
+                        throw new NoSuchMethodError(String.format(
+                                        "Found 2 methods with same name and parameter types but unrelated return types:%n %s%n %s", match, m));
                     }
+                }
+            }
+        }
+        return match;
+    }
+
+    /**
+     * Same as {@link #resolveMethod(Class, Binding)} and
+     * {@link #resolveConstructor(Class, Binding)} except in terms of {@link ResolvedJavaType} and
+     * {@link ResolvedJavaMethod}.
+     */
+    public static ResolvedJavaMethod resolveJavaMethod(ResolvedJavaType declaringClass, Binding binding) {
+        ResolvedJavaMethod[] methods = declaringClass.getDeclaredMethods();
+        if (binding.name.equals("<init>")) {
+            for (ResolvedJavaMethod m : methods) {
+                if (m.getName().equals("<init>") && m.getSignature().toMethodDescriptor().startsWith(binding.argumentsDescriptor)) {
                     return m;
                 }
             }
+            return null;
         }
-        return null;
+
+        ResolvedJavaMethod match = null;
+        for (int i = 0; i < methods.length; ++i) {
+            ResolvedJavaMethod m = methods[i];
+            if (binding.isStatic == m.isStatic() &&
+                            m.getName().equals(binding.name) &&
+                            m.getSignature().toMethodDescriptor().startsWith(binding.argumentsDescriptor)) {
+                if (match == null) {
+                    match = m;
+                } else {
+                    final ResolvedJavaType matchReturnType = (ResolvedJavaType) match.getSignature().getReturnType(declaringClass);
+                    final ResolvedJavaType mReturnType = (ResolvedJavaType) m.getSignature().getReturnType(declaringClass);
+                    if (matchReturnType.isAssignableFrom(mReturnType)) {
+                        // `m` has a more specific return type - choose it
+                        // (`match` is most likely a bridge method)
+                        match = m;
+                    } else {
+                        if (!mReturnType.isAssignableFrom(matchReturnType)) {
+                            throw new NoSuchMethodError(String.format(
+                                            "Found 2 methods with same name and parameter types but unrelated return types:%n %s%n %s", match, m));
+                        }
+                    }
+                }
+            }
+        }
+        return match;
     }
 
     /**
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/AtomicReadAndAddNode.java	Fri Feb 16 12:24:38 2018 -0800
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/AtomicReadAndAddNode.java	Fri Feb 16 13:49:07 2018 -0800
@@ -39,10 +39,10 @@
 import org.graalvm.word.LocationIdentity;
 
 import jdk.vm.ci.meta.Value;
-import sun.misc.Unsafe;
 
 /**
- * Represents an atomic read-and-add operation like {@link Unsafe#getAndAddInt(Object, long, int)}.
+ * Represents an atomic read-and-add operation like
+ * {@link sun.misc.Unsafe#getAndAddInt(Object, long, int)}.
  */
 @NodeInfo(allowedUsageTypes = Memory, cycles = CYCLES_8, size = SIZE_2)
 public final class AtomicReadAndAddNode extends AbstractMemoryCheckpoint implements LIRLowerable, MemoryCheckpoint.Single {
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/AtomicReadAndWriteNode.java	Fri Feb 16 12:24:38 2018 -0800
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/AtomicReadAndWriteNode.java	Fri Feb 16 13:49:07 2018 -0800
@@ -36,11 +36,10 @@
 import org.graalvm.word.LocationIdentity;
 
 import jdk.vm.ci.meta.JavaKind;
-import sun.misc.Unsafe;
 
 /**
- * Represents an atomic read-and-write operation like {@link Unsafe#getAndSetInt(Object, long, int)}
- * .
+ * Represents an atomic read-and-write operation like
+ * {@link sun.misc.Unsafe#getAndSetInt(Object, long, int)}.
  */
 @NodeInfo(cycles = CYCLES_8, size = SIZE_2)
 public final class AtomicReadAndWriteNode extends AbstractMemoryCheckpoint implements Lowerable, MemoryCheckpoint.Single {
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/DynamicNewArrayNode.java	Fri Feb 16 12:24:38 2018 -0800
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/DynamicNewArrayNode.java	Fri Feb 16 13:49:07 2018 -0800
@@ -125,6 +125,13 @@
     }
 
     @NodeIntrinsic
+    private static native Object newArray(Class<?> componentType, int length, @ConstantNodeParameter boolean fillContents);
+
+    public static Object newArray(Class<?> componentType, int length) {
+        return newArray(componentType, length, true);
+    }
+
+    @NodeIntrinsic
     private static native Object newArray(Class<?> componentType, int length, @ConstantNodeParameter boolean fillContents, @ConstantNodeParameter JavaKind knownElementKind);
 
     public static Object newArray(Class<?> componentType, int length, JavaKind knownElementKind) {
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/LoweredAtomicReadAndWriteNode.java	Fri Feb 16 12:24:38 2018 -0800
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/LoweredAtomicReadAndWriteNode.java	Fri Feb 16 13:49:07 2018 -0800
@@ -42,11 +42,10 @@
 import org.graalvm.word.LocationIdentity;
 
 import jdk.vm.ci.meta.Value;
-import sun.misc.Unsafe;
 
 /**
  * Represents the lowered version of an atomic read-and-write operation like
- * {@link Unsafe#getAndSetInt(Object, long, int)} .
+ * {@link sun.misc.Unsafe#getAndSetInt(Object, long, int)}.
  */
 @NodeInfo(allowedUsageTypes = {Memory}, cycles = CYCLES_8, size = SIZE_2)
 public final class LoweredAtomicReadAndWriteNode extends FixedAccessNode implements StateSplit, LIRLowerableAccess, MemoryCheckpoint.Single {
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/NewArrayNode.java	Fri Feb 16 12:24:38 2018 -0800
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/java/NewArrayNode.java	Fri Feb 16 13:49:07 2018 -0800
@@ -24,7 +24,7 @@
 
 import java.util.Collections;
 
-import org.graalvm.compiler.core.common.calc.Condition;
+import org.graalvm.compiler.core.common.calc.CanonicalCondition;
 import org.graalvm.compiler.core.common.type.IntegerStamp;
 import org.graalvm.compiler.core.common.type.Stamp;
 import org.graalvm.compiler.core.common.type.StampFactory;
@@ -132,7 +132,7 @@
             // Should be areFrameStatesAtSideEffects but currently SVM will complain about
             // RuntimeConstraint
             if (graph().getGuardsStage().allowsFloatingGuards()) {
-                LogicNode lengthNegativeCondition = CompareNode.createCompareNode(graph(), Condition.LT, length(), ConstantNode.forInt(0, graph()), tool.getConstantReflection(), view);
+                LogicNode lengthNegativeCondition = CompareNode.createCompareNode(graph(), CanonicalCondition.LT, length(), ConstantNode.forInt(0, graph()), tool.getConstantReflection(), view);
                 // we do not have a non-deopting path for that at the moment so action=None.
                 FixedGuardNode guard = graph().add(new FixedGuardNode(lengthNegativeCondition, DeoptimizationReason.RuntimeConstraint, DeoptimizationAction.None, true));
                 graph().replaceFixedWithFixed(this, guard);
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/memory/MemoryMapNode.java	Fri Feb 16 12:24:38 2018 -0800
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/memory/MemoryMapNode.java	Fri Feb 16 13:49:07 2018 -0800
@@ -32,6 +32,9 @@
 import java.util.Collection;
 import java.util.List;
 
+import org.graalvm.collections.EconomicMap;
+import org.graalvm.collections.Equivalence;
+import org.graalvm.collections.MapCursor;
 import org.graalvm.compiler.core.common.type.StampFactory;
 import org.graalvm.compiler.graph.NodeClass;
 import org.graalvm.compiler.graph.NodeInputList;
@@ -41,9 +44,6 @@
 import org.graalvm.compiler.nodes.calc.FloatingNode;
 import org.graalvm.compiler.nodes.spi.LIRLowerable;
 import org.graalvm.compiler.nodes.spi.NodeLIRBuilderTool;
-import org.graalvm.util.Equivalence;
-import org.graalvm.util.EconomicMap;
-import org.graalvm.util.MapCursor;
 import org.graalvm.word.LocationIdentity;
 
 @NodeInfo(allowedUsageTypes = {Extension, Memory}, cycles = CYCLES_0, size = SIZE_0)
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/spi/LoweringProvider.java	Fri Feb 16 12:24:38 2018 -0800
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/spi/LoweringProvider.java	Fri Feb 16 13:49:07 2018 -0800
@@ -22,6 +22,7 @@
  */
 package org.graalvm.compiler.nodes.spi;
 
+import org.graalvm.compiler.core.common.spi.ArrayOffsetProvider;
 import org.graalvm.compiler.graph.Node;
 import org.graalvm.compiler.nodes.ValueNode;
 import org.graalvm.compiler.nodes.memory.address.AddressNode;
@@ -31,7 +32,7 @@
 /**
  * Provides a capability for replacing a higher node with one or more lower level nodes.
  */
-public interface LoweringProvider {
+public interface LoweringProvider extends ArrayOffsetProvider {
 
     void lower(Node n, LoweringTool tool);
 
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/spi/VirtualizerTool.java	Fri Feb 16 12:24:38 2018 -0800
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/spi/VirtualizerTool.java	Fri Feb 16 13:49:07 2018 -0800
@@ -24,6 +24,7 @@
 
 import java.util.List;
 
+import org.graalvm.compiler.core.common.spi.ArrayOffsetProvider;
 import org.graalvm.compiler.debug.DebugContext;
 import org.graalvm.compiler.debug.GraalError;
 import org.graalvm.compiler.graph.Node;
@@ -56,6 +57,8 @@
      */
     ConstantReflectionProvider getConstantReflectionProvider();
 
+    ArrayOffsetProvider getArrayOffsetProvider();
+
     /**
      * This method should be used to query the maximum size of virtualized objects before attempting
      * virtualization.
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/util/GraphUtil.java	Fri Feb 16 12:24:38 2018 -0800
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/util/GraphUtil.java	Fri Feb 16 13:49:07 2018 -0800
@@ -30,6 +30,10 @@
 import java.util.List;
 import java.util.function.BiFunction;
 
+import org.graalvm.collections.EconomicMap;
+import org.graalvm.collections.EconomicSet;
+import org.graalvm.collections.Equivalence;
+import org.graalvm.collections.MapCursor;
 import org.graalvm.compiler.bytecode.Bytecode;
 import org.graalvm.compiler.code.SourceStackTraceBailoutException;
 import org.graalvm.compiler.core.common.spi.ConstantFieldProvider;
@@ -76,10 +80,6 @@
 import org.graalvm.compiler.options.OptionKey;
 import org.graalvm.compiler.options.OptionType;
 import org.graalvm.compiler.options.OptionValues;
-import org.graalvm.util.EconomicMap;
-import org.graalvm.util.EconomicSet;
-import org.graalvm.util.Equivalence;
-import org.graalvm.util.MapCursor;
 
 import jdk.vm.ci.code.BailoutException;
 import jdk.vm.ci.code.BytecodePosition;
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/virtual/VirtualArrayNode.java	Fri Feb 16 12:24:38 2018 -0800
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/virtual/VirtualArrayNode.java	Fri Feb 16 13:49:07 2018 -0800
@@ -24,6 +24,7 @@
 
 import java.nio.ByteOrder;
 
+import org.graalvm.compiler.core.common.spi.ArrayOffsetProvider;
 import org.graalvm.compiler.graph.NodeClass;
 import org.graalvm.compiler.nodeinfo.NodeInfo;
 import org.graalvm.compiler.nodeinfo.Verbosity;
@@ -35,7 +36,6 @@
 
 import jdk.vm.ci.meta.JavaKind;
 import jdk.vm.ci.meta.ResolvedJavaType;
-import sun.misc.Unsafe;
 
 @NodeInfo(nameTemplate = "VirtualArray({p#objectId}) {p#componentType/s}[{p#length}]")
 public class VirtualArrayNode extends VirtualObjectNode implements ArrayLengthProvider {
@@ -88,53 +88,14 @@
     }
 
     @Override
-    public int entryIndexForOffset(long constantOffset, JavaKind expectedEntryKind) {
-        return entryIndexForOffset(constantOffset, expectedEntryKind, componentType, length);
+    public int entryIndexForOffset(ArrayOffsetProvider arrayOffsetProvider, long constantOffset, JavaKind expectedEntryKind) {
+        return entryIndexForOffset(arrayOffsetProvider, constantOffset, expectedEntryKind, componentType, length);
     }
 
-    public static int entryIndexForOffset(long constantOffset, JavaKind expectedEntryKind, ResolvedJavaType componentType, int length) {
-        int baseOffset;
-        int indexScale;
-        switch (componentType.getJavaKind()) {
-            case Boolean:
-                baseOffset = Unsafe.ARRAY_BOOLEAN_BASE_OFFSET;
-                indexScale = Unsafe.ARRAY_BOOLEAN_INDEX_SCALE;
-                break;
-            case Byte:
-                baseOffset = Unsafe.ARRAY_BYTE_BASE_OFFSET;
-                indexScale = Unsafe.ARRAY_BYTE_INDEX_SCALE;
-                break;
-            case Short:
-                baseOffset = Unsafe.ARRAY_SHORT_BASE_OFFSET;
-                indexScale = Unsafe.ARRAY_SHORT_INDEX_SCALE;
-                break;
-            case Char:
-                baseOffset = Unsafe.ARRAY_CHAR_BASE_OFFSET;
-                indexScale = Unsafe.ARRAY_CHAR_INDEX_SCALE;
-                break;
-            case Int:
-                baseOffset = Unsafe.ARRAY_INT_BASE_OFFSET;
-                indexScale = Unsafe.ARRAY_INT_INDEX_SCALE;
-                break;
-            case Long:
-                baseOffset = Unsafe.ARRAY_LONG_BASE_OFFSET;
-                indexScale = Unsafe.ARRAY_LONG_INDEX_SCALE;
-                break;
-            case Float:
-                baseOffset = Unsafe.ARRAY_FLOAT_BASE_OFFSET;
-                indexScale = Unsafe.ARRAY_FLOAT_INDEX_SCALE;
-                break;
-            case Double:
-                baseOffset = Unsafe.ARRAY_DOUBLE_BASE_OFFSET;
-                indexScale = Unsafe.ARRAY_DOUBLE_INDEX_SCALE;
-                break;
-            case Object:
-                baseOffset = Unsafe.ARRAY_OBJECT_BASE_OFFSET;
-                indexScale = Unsafe.ARRAY_OBJECT_INDEX_SCALE;
-                break;
-            default:
-                return -1;
-        }
+    public static int entryIndexForOffset(ArrayOffsetProvider arrayOffsetProvider, long constantOffset, JavaKind expectedEntryKind, ResolvedJavaType componentType, int length) {
+        int baseOffset = arrayOffsetProvider.arrayBaseOffset(componentType.getJavaKind());
+        int indexScale = arrayOffsetProvider.arrayScalingFactor(componentType.getJavaKind());
+
         long offset;
         if (ByteOrder.nativeOrder() == ByteOrder.BIG_ENDIAN && componentType.isPrimitive()) {
             // On big endian, we expect the value to be correctly aligned in memory
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/virtual/VirtualInstanceNode.java	Fri Feb 16 12:24:38 2018 -0800
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/virtual/VirtualInstanceNode.java	Fri Feb 16 13:49:07 2018 -0800
@@ -22,6 +22,7 @@
  */
 package org.graalvm.compiler.nodes.virtual;
 
+import org.graalvm.compiler.core.common.spi.ArrayOffsetProvider;
 import org.graalvm.compiler.graph.NodeClass;
 import org.graalvm.compiler.nodeinfo.NodeInfo;
 import org.graalvm.compiler.nodeinfo.Verbosity;
@@ -100,7 +101,7 @@
     }
 
     @Override
-    public int entryIndexForOffset(long constantOffset, JavaKind expectedEntryKind) {
+    public int entryIndexForOffset(ArrayOffsetProvider arrayOffsetProvider, long constantOffset, JavaKind expectedEntryKind) {
         return fieldIndex(type.findInstanceFieldWithOffset(constantOffset, expectedEntryKind));
     }
 
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/virtual/VirtualObjectNode.java	Fri Feb 16 12:24:38 2018 -0800
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.nodes/src/org/graalvm/compiler/nodes/virtual/VirtualObjectNode.java	Fri Feb 16 13:49:07 2018 -0800
@@ -25,6 +25,7 @@
 import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_0;
 import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_0;
 
+import org.graalvm.compiler.core.common.spi.ArrayOffsetProvider;
 import org.graalvm.compiler.core.common.type.StampFactory;
 import org.graalvm.compiler.core.common.type.TypeReference;
 import org.graalvm.compiler.graph.IterableNodeType;
@@ -95,7 +96,7 @@
      * @param expectedEntryKind Specifies which type is expected at this offset (Is important when
      *            doing implicit casts, especially on big endian systems.
      */
-    public abstract int entryIndexForOffset(long constantOffset, JavaKind expectedEntryKind);
+    public abstract int entryIndexForOffset(ArrayOffsetProvider arrayOffsetProvider, long constantOffset, JavaKind expectedEntryKind);
 
     /**
      * Returns the {@link JavaKind} of the entry at the given index.
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.options/src/org/graalvm/compiler/options/EnumOptionKey.java	Fri Feb 16 12:24:38 2018 -0800
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.options/src/org/graalvm/compiler/options/EnumOptionKey.java	Fri Feb 16 13:49:07 2018 -0800
@@ -24,7 +24,7 @@
 
 import java.util.EnumSet;
 
-import org.graalvm.util.EconomicMap;
+import org.graalvm.collections.EconomicMap;
 
 public class EnumOptionKey<T extends Enum<T>> extends OptionKey<T> {
     final Class<T> enumClass;
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.options/src/org/graalvm/compiler/options/ModifiableOptionValues.java	Fri Feb 16 12:24:38 2018 -0800
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.options/src/org/graalvm/compiler/options/ModifiableOptionValues.java	Fri Feb 16 13:49:07 2018 -0800
@@ -24,10 +24,10 @@
 
 import java.util.concurrent.atomic.AtomicReference;
 
-import org.graalvm.util.EconomicMap;
-import org.graalvm.util.Equivalence;
-import org.graalvm.util.UnmodifiableEconomicMap;
-import org.graalvm.util.UnmodifiableMapCursor;
+import org.graalvm.collections.EconomicMap;
+import org.graalvm.collections.Equivalence;
+import org.graalvm.collections.UnmodifiableEconomicMap;
+import org.graalvm.collections.UnmodifiableMapCursor;
 
 /**
  * A context for obtaining values for {@link OptionKey}s that allows for key/value pairs to be
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.options/src/org/graalvm/compiler/options/OptionKey.java	Fri Feb 16 12:24:38 2018 -0800
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.options/src/org/graalvm/compiler/options/OptionKey.java	Fri Feb 16 13:49:07 2018 -0800
@@ -24,7 +24,7 @@
 
 import java.util.Formatter;
 
-import org.graalvm.util.EconomicMap;
+import org.graalvm.collections.EconomicMap;
 
 /**
  * A key for an option. The value for an option is obtained from an {@link OptionValues} object.
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.options/src/org/graalvm/compiler/options/OptionValues.java	Fri Feb 16 12:24:38 2018 -0800
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.options/src/org/graalvm/compiler/options/OptionValues.java	Fri Feb 16 13:49:07 2018 -0800
@@ -30,10 +30,10 @@
 import java.util.SortedMap;
 import java.util.TreeMap;
 
-import org.graalvm.util.EconomicMap;
-import org.graalvm.util.Equivalence;
-import org.graalvm.util.UnmodifiableEconomicMap;
-import org.graalvm.util.UnmodifiableMapCursor;
+import org.graalvm.collections.EconomicMap;
+import org.graalvm.collections.Equivalence;
+import org.graalvm.collections.UnmodifiableEconomicMap;
+import org.graalvm.collections.UnmodifiableMapCursor;
 
 /**
  * A context for obtaining values for {@link OptionKey}s.
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.options/src/org/graalvm/compiler/options/OptionsParser.java	Fri Feb 16 12:24:38 2018 -0800
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.options/src/org/graalvm/compiler/options/OptionsParser.java	Fri Feb 16 13:49:07 2018 -0800
@@ -28,9 +28,9 @@
 import java.util.List;
 import java.util.ServiceLoader;
 
+import org.graalvm.collections.EconomicMap;
+import org.graalvm.collections.MapCursor;
 import org.graalvm.util.CollectionsUtil;
-import org.graalvm.util.EconomicMap;
-import org.graalvm.util.MapCursor;
 
 /**
  * This class contains methods for parsing Graal options and matching them against a set of
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/AddressLoweringPhase.java	Fri Feb 16 12:24:38 2018 -0800
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/AddressLoweringPhase.java	Fri Feb 16 13:49:07 2018 -0800
@@ -33,6 +33,15 @@
 public class AddressLoweringPhase extends Phase {
 
     public abstract static class AddressLowering {
+
+        @SuppressWarnings("unused")
+        public void preProcess(StructuredGraph graph) {
+        }
+
+        @SuppressWarnings("unused")
+        public void postProcess(AddressNode lowered) {
+        }
+
         public abstract AddressNode lower(ValueNode base, ValueNode offset);
     }
 
@@ -45,11 +54,13 @@
 
     @Override
     protected void run(StructuredGraph graph) {
+        lowering.preProcess(graph);
         for (Node node : graph.getNodes()) {
             AddressNode lowered;
             if (node instanceof OffsetAddressNode) {
                 OffsetAddressNode address = (OffsetAddressNode) node;
                 lowered = lowering.lower(address.getBase(), address.getOffset());
+                lowering.postProcess(lowered);
             } else {
                 continue;
             }
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/ConditionalEliminationPhase.java	Fri Feb 16 12:24:38 2018 -0800
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/ConditionalEliminationPhase.java	Fri Feb 16 13:49:07 2018 -0800
@@ -26,6 +26,10 @@
 import java.util.Deque;
 import java.util.List;
 
+import org.graalvm.collections.EconomicMap;
+import org.graalvm.collections.Equivalence;
+import org.graalvm.collections.MapCursor;
+import org.graalvm.collections.Pair;
 import org.graalvm.compiler.core.common.cfg.BlockMap;
 import org.graalvm.compiler.core.common.type.ArithmeticOpTable;
 import org.graalvm.compiler.core.common.type.ArithmeticOpTable.BinaryOp;
@@ -87,10 +91,6 @@
 import org.graalvm.compiler.phases.schedule.SchedulePhase;
 import org.graalvm.compiler.phases.schedule.SchedulePhase.SchedulingStrategy;
 import org.graalvm.compiler.phases.tiers.PhaseContext;
-import org.graalvm.util.EconomicMap;
-import org.graalvm.util.Equivalence;
-import org.graalvm.util.MapCursor;
-import org.graalvm.util.Pair;
 
 import jdk.vm.ci.meta.JavaConstant;
 import jdk.vm.ci.meta.TriState;
@@ -124,7 +124,11 @@
                 if (moveGuards) {
                     cfg.visitDominatorTree(new MoveGuardsUpwards(), graph.hasValueProxies());
                 }
-                SchedulePhase.run(graph, SchedulingStrategy.EARLIEST, cfg);
+                try (DebugContext.Scope scheduleScope = graph.getDebug().scope(SchedulePhase.class)) {
+                    SchedulePhase.run(graph, SchedulingStrategy.EARLIEST_WITH_GUARD_ORDER, cfg);
+                } catch (Throwable t) {
+                    throw graph.getDebug().handle(t);
+                }
                 ScheduleResult r = graph.getLastSchedule();
                 blockToNodes = r.getBlockToNodesMap();
                 nodeToBlock = r.getNodeToBlockMap();
@@ -662,7 +666,7 @@
                      */
                     InputFilter v = new InputFilter(original);
                     thisGuard.getCondition().applyInputs(v);
-                    if (v.ok && foldGuard(thisGuard, pendingGuard, newStamp, rewireGuardFunction)) {
+                    if (v.ok && foldGuard(thisGuard, pendingGuard, result.toBoolean(), newStamp, rewireGuardFunction)) {
                         return true;
                     }
                 }
@@ -670,19 +674,34 @@
             return false;
         }
 
-        protected boolean foldGuard(DeoptimizingGuard thisGuard, DeoptimizingGuard otherGuard, Stamp guardedValueStamp, GuardRewirer rewireGuardFunction) {
+        protected boolean foldGuard(DeoptimizingGuard thisGuard, DeoptimizingGuard otherGuard, boolean outcome, Stamp guardedValueStamp, GuardRewirer rewireGuardFunction) {
             if (otherGuard.getAction() == thisGuard.getAction() && otherGuard.getSpeculation() == thisGuard.getSpeculation()) {
                 LogicNode condition = (LogicNode) thisGuard.getCondition().copyWithInputs();
+                /*
+                 * We have ...; guard(C1); guard(C2);...
+                 *
+                 * Where the first guard is `otherGuard` and the second one `thisGuard`.
+                 *
+                 * Depending on `outcome`, we have C2 => C1 or C2 => !C1.
+                 *
+                 * - If C2 => C1, `mustDeopt` below is false and we transform to ...; guard(C2); ...
+                 *
+                 * - If C2 => !C1, `mustDeopt` is true and we transform to ..; guard(C1); deopt;
+                 */
                 GuardRewirer rewirer = (guard, result, innerGuardedValueStamp, newInput) -> {
-                    if (rewireGuardFunction.rewire(guard, result, innerGuardedValueStamp, newInput)) {
-                        otherGuard.setCondition(condition, thisGuard.isNegated());
+                    // `result` is `outcome`, `guard` is `otherGuard`
+                    boolean mustDeopt = result == otherGuard.isNegated();
+                    if (rewireGuardFunction.rewire(guard, mustDeopt == thisGuard.isNegated(), innerGuardedValueStamp, newInput)) {
+                        if (!mustDeopt) {
+                            otherGuard.setCondition(condition, thisGuard.isNegated());
+                        }
                         return true;
                     }
                     condition.safeDelete();
                     return false;
                 };
                 // Move the later test up
-                return rewireGuards(otherGuard, !thisGuard.isNegated(), null, guardedValueStamp, rewirer);
+                return rewireGuards(otherGuard, outcome, null, guardedValueStamp, rewirer);
             }
             return false;
         }
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/ConvertDeoptimizeToGuardPhase.java	Fri Feb 16 12:24:38 2018 -0800
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/ConvertDeoptimizeToGuardPhase.java	Fri Feb 16 13:49:07 2018 -0800
@@ -26,8 +26,8 @@
 
 import java.util.List;
 
+import org.graalvm.compiler.core.common.GraalOptions;
 import org.graalvm.compiler.debug.DebugCloseable;
-import org.graalvm.compiler.debug.DebugContext;
 import org.graalvm.compiler.graph.Node;
 import org.graalvm.compiler.graph.spi.SimplifierTool;
 import org.graalvm.compiler.nodeinfo.InputType;
@@ -46,6 +46,8 @@
 import org.graalvm.compiler.nodes.LogicNode;
 import org.graalvm.compiler.nodes.LoopExitNode;
 import org.graalvm.compiler.nodes.ProxyNode;
+import org.graalvm.compiler.nodes.StartNode;
+import org.graalvm.compiler.nodes.StaticDeoptimizingNode;
 import org.graalvm.compiler.nodes.StructuredGraph;
 import org.graalvm.compiler.nodes.ValueNode;
 import org.graalvm.compiler.nodes.ValuePhiNode;
@@ -57,8 +59,6 @@
 
 import jdk.vm.ci.meta.Constant;
 import jdk.vm.ci.meta.DeoptimizationAction;
-import jdk.vm.ci.meta.DeoptimizationReason;
-import jdk.vm.ci.meta.JavaConstant;
 
 /**
  * This phase will find branches which always end with a {@link DeoptimizeNode} and replace their
@@ -77,18 +77,16 @@
     @SuppressWarnings("try")
     protected void run(final StructuredGraph graph, PhaseContext context) {
         assert graph.hasValueProxies() : "ConvertDeoptimizeToGuardPhase always creates proxies";
+        assert !graph.getGuardsStage().areFrameStatesAtDeopts() : graph.getGuardsStage();
 
         for (DeoptimizeNode d : graph.getNodes(DeoptimizeNode.TYPE)) {
             assert d.isAlive();
-            // Can only aggressively move deoptimization point if their action implies that
-            // the deoptimization will not be triggered again. Example for such action is
-            // reprofiling or recompiling with less aggressive options.
-            if (d.action() != DeoptimizationAction.None) {
-                try (DebugCloseable closable = d.withNodeSourcePosition()) {
-                    visitDeoptBegin(AbstractBeginNode.prevBegin(d), d.action(), d.reason(), d.getSpeculation(), graph, context != null ? context.getLowerer() : null);
-                }
+            if (d.getAction() == DeoptimizationAction.None) {
+                continue;
             }
-
+            try (DebugCloseable closable = d.withNodeSourcePosition()) {
+                propagateFixed(d, d, context != null ? context.getLowerer() : null);
+            }
         }
 
         if (context != null) {
@@ -154,71 +152,73 @@
                 ys = yPhi.valueAt(mergePredecessor).asConstant();
             }
             if (xs != null && ys != null && compare.condition().foldCondition(xs, ys, context.getConstantReflection(), compare.unorderedIsTrue()) == fixedGuard.isNegated()) {
-                visitDeoptBegin(AbstractBeginNode.prevBegin(mergePredecessor), fixedGuard.getAction(), fixedGuard.getReason(), fixedGuard.getSpeculation(), fixedGuard.graph(), context.getLowerer());
+                propagateFixed(mergePredecessor, fixedGuard, context.getLowerer());
             }
         }
     }
 
-    private void visitDeoptBegin(AbstractBeginNode deoptBegin, DeoptimizationAction deoptAction, DeoptimizationReason deoptReason, JavaConstant speculation, StructuredGraph graph,
-                    LoweringProvider loweringProvider) {
-        if (deoptBegin.predecessor() instanceof AbstractBeginNode) {
-            /*
-             * Walk up chains of LoopExitNodes to the "real" BeginNode that leads to deoptimization.
-             */
-            visitDeoptBegin((AbstractBeginNode) deoptBegin.predecessor(), deoptAction, deoptReason, speculation, graph, loweringProvider);
-            return;
-        }
+    private void propagateFixed(FixedNode from, StaticDeoptimizingNode deopt, LoweringProvider loweringProvider) {
+        Node current = from;
+        while (current != null) {
+            if (GraalOptions.GuardPriorities.getValue(from.getOptions()) && current instanceof FixedGuardNode) {
+                FixedGuardNode otherGuard = (FixedGuardNode) current;
+                if (otherGuard.computePriority().isHigherPriorityThan(deopt.computePriority())) {
+                    moveAsDeoptAfter(otherGuard, deopt);
+                    return;
+                }
+            } else if (current instanceof AbstractBeginNode) {
+                if (current instanceof AbstractMergeNode) {
+                    AbstractMergeNode mergeNode = (AbstractMergeNode) current;
+                    FixedNode next = mergeNode.next();
+                    while (mergeNode.isAlive()) {
+                        AbstractEndNode end = mergeNode.forwardEnds().first();
+                        propagateFixed(end, deopt, loweringProvider);
+                    }
+                    assert next.isAlive();
+                    propagateFixed(next, deopt, loweringProvider);
+                    return;
+                } else if (current.predecessor() instanceof IfNode) {
+                    IfNode ifNode = (IfNode) current.predecessor();
+                    StructuredGraph graph = ifNode.graph();
+                    LogicNode conditionNode = ifNode.condition();
+                    boolean negateGuardCondition = current == ifNode.trueSuccessor();
+                    FixedGuardNode guard = graph.add(new FixedGuardNode(conditionNode, deopt.getReason(), deopt.getAction(), deopt.getSpeculation(), negateGuardCondition));
+                    FixedWithNextNode pred = (FixedWithNextNode) ifNode.predecessor();
+                    AbstractBeginNode survivingSuccessor;
+                    if (negateGuardCondition) {
+                        survivingSuccessor = ifNode.falseSuccessor();
+                    } else {
+                        survivingSuccessor = ifNode.trueSuccessor();
+                    }
+                    graph.removeSplitPropagate(ifNode, survivingSuccessor);
 
-        DebugContext debug = deoptBegin.getDebug();
-        if (deoptBegin instanceof AbstractMergeNode) {
-            AbstractMergeNode mergeNode = (AbstractMergeNode) deoptBegin;
-            debug.log("Visiting %s", mergeNode);
-            FixedNode next = mergeNode.next();
-            while (mergeNode.isAlive()) {
-                AbstractEndNode end = mergeNode.forwardEnds().first();
-                AbstractBeginNode newBeginNode = AbstractBeginNode.prevBegin(end);
-                visitDeoptBegin(newBeginNode, deoptAction, deoptReason, speculation, graph, loweringProvider);
+                    Node newGuard = guard;
+                    if (survivingSuccessor instanceof LoopExitNode) {
+                        newGuard = ProxyNode.forGuard(guard, (LoopExitNode) survivingSuccessor, graph);
+                    }
+                    survivingSuccessor.replaceAtUsages(InputType.Guard, newGuard);
+
+                    graph.getDebug().log("Converting deopt on %-5s branch of %s to guard for remaining branch %s.", negateGuardCondition, ifNode, survivingSuccessor);
+                    FixedNode next = pred.next();
+                    pred.setNext(guard);
+                    guard.setNext(next);
+                    SimplifierTool simplifierTool = GraphUtil.getDefaultSimplifier(null, null, null, false, graph.getAssumptions(), graph.getOptions(), loweringProvider);
+                    survivingSuccessor.simplify(simplifierTool);
+                    return;
+                } else if (current.predecessor() == null || current.predecessor() instanceof ControlSplitNode) {
+                    assert current.predecessor() != null || (current instanceof StartNode && current == ((AbstractBeginNode) current).graph().start());
+                    moveAsDeoptAfter((AbstractBeginNode) current, deopt);
+                    return;
+                }
             }
-            assert next.isAlive();
-            AbstractBeginNode newBeginNode = AbstractBeginNode.prevBegin(next);
-            visitDeoptBegin(newBeginNode, deoptAction, deoptReason, speculation, graph, loweringProvider);
-            return;
-        } else if (deoptBegin.predecessor() instanceof IfNode) {
-            IfNode ifNode = (IfNode) deoptBegin.predecessor();
-            LogicNode conditionNode = ifNode.condition();
-            FixedGuardNode guard = graph.add(new FixedGuardNode(conditionNode, deoptReason, deoptAction, speculation, deoptBegin == ifNode.trueSuccessor()));
-            FixedWithNextNode pred = (FixedWithNextNode) ifNode.predecessor();
-            AbstractBeginNode survivingSuccessor;
-            if (deoptBegin == ifNode.trueSuccessor()) {
-                survivingSuccessor = ifNode.falseSuccessor();
-            } else {
-                survivingSuccessor = ifNode.trueSuccessor();
-            }
-            graph.removeSplitPropagate(ifNode, survivingSuccessor);
+            current = current.predecessor();
+        }
+    }
 
-            Node newGuard = guard;
-            if (survivingSuccessor instanceof LoopExitNode) {
-                newGuard = ProxyNode.forGuard(guard, (LoopExitNode) survivingSuccessor, graph);
-            }
-            survivingSuccessor.replaceAtUsages(InputType.Guard, newGuard);
-
-            debug.log("Converting deopt on %-5s branch of %s to guard for remaining branch %s.", deoptBegin == ifNode.trueSuccessor() ? "true" : "false", ifNode, survivingSuccessor);
-            FixedNode next = pred.next();
-            pred.setNext(guard);
-            guard.setNext(next);
-            SimplifierTool simplifierTool = GraphUtil.getDefaultSimplifier(null, null, null, false, graph.getAssumptions(), graph.getOptions(), loweringProvider);
-            survivingSuccessor.simplify(simplifierTool);
-            return;
-        }
-
-        // We could not convert the control split - at least cut off control flow after the split.
-        FixedWithNextNode deoptPred = deoptBegin;
-        FixedNode next = deoptPred.next();
-
-        if (!(next instanceof DeoptimizeNode)) {
-            DeoptimizeNode newDeoptNode = graph.add(new DeoptimizeNode(deoptAction, deoptReason, speculation));
-            deoptPred.setNext(newDeoptNode);
-            assert deoptPred == newDeoptNode.predecessor();
+    private static void moveAsDeoptAfter(FixedWithNextNode node, StaticDeoptimizingNode deopt) {
+        FixedNode next = node.next();
+        if (next != deopt.asNode()) {
+            node.setNext(node.graph().add(new DeoptimizeNode(deopt.getAction(), deopt.getReason(), deopt.getSpeculation())));
             GraphUtil.killCFG(next);
         }
     }
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/FixReadsPhase.java	Fri Feb 16 12:24:38 2018 -0800
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/FixReadsPhase.java	Fri Feb 16 13:49:07 2018 -0800
@@ -22,6 +22,8 @@
  */
 package org.graalvm.compiler.phases.common;
 
+import org.graalvm.collections.EconomicMap;
+import org.graalvm.collections.MapCursor;
 import org.graalvm.compiler.core.common.GraalOptions;
 import org.graalvm.compiler.core.common.cfg.BlockMap;
 import org.graalvm.compiler.core.common.type.FloatStamp;
@@ -70,8 +72,6 @@
 import org.graalvm.compiler.phases.schedule.SchedulePhase.SchedulingStrategy;
 import org.graalvm.compiler.phases.tiers.LowTierContext;
 import org.graalvm.compiler.phases.tiers.PhaseContext;
-import org.graalvm.util.EconomicMap;
-import org.graalvm.util.MapCursor;
 
 import jdk.vm.ci.meta.Constant;
 import jdk.vm.ci.meta.MetaAccessProvider;
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/FloatingReadPhase.java	Fri Feb 16 12:24:38 2018 -0800
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/FloatingReadPhase.java	Fri Feb 16 13:49:07 2018 -0800
@@ -30,6 +30,10 @@
 import java.util.Iterator;
 import java.util.List;
 
+import org.graalvm.collections.EconomicMap;
+import org.graalvm.collections.EconomicSet;
+import org.graalvm.collections.Equivalence;
+import org.graalvm.collections.UnmodifiableMapCursor;
 import org.graalvm.compiler.core.common.cfg.Loop;
 import org.graalvm.compiler.debug.DebugCloseable;
 import org.graalvm.compiler.graph.Graph.NodeEventScope;
@@ -67,10 +71,6 @@
 import org.graalvm.compiler.phases.graph.ReentrantNodeIterator;
 import org.graalvm.compiler.phases.graph.ReentrantNodeIterator.LoopInfo;
 import org.graalvm.compiler.phases.graph.ReentrantNodeIterator.NodeIteratorClosure;
-import org.graalvm.util.Equivalence;
-import org.graalvm.util.EconomicMap;
-import org.graalvm.util.EconomicSet;
-import org.graalvm.util.UnmodifiableMapCursor;
 import org.graalvm.word.LocationIdentity;
 
 public class FloatingReadPhase extends Phase {
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/FrameStateAssignmentPhase.java	Fri Feb 16 12:24:38 2018 -0800
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/FrameStateAssignmentPhase.java	Fri Feb 16 13:49:07 2018 -0800
@@ -24,6 +24,7 @@
 
 import java.util.List;
 
+import org.graalvm.collections.EconomicMap;
 import org.graalvm.compiler.debug.GraalError;
 import org.graalvm.compiler.graph.Node;
 import org.graalvm.compiler.nodes.AbstractBeginNode;
@@ -40,7 +41,6 @@
 import org.graalvm.compiler.phases.Phase;
 import org.graalvm.compiler.phases.graph.ReentrantNodeIterator;
 import org.graalvm.compiler.phases.graph.ReentrantNodeIterator.NodeIteratorClosure;
-import org.graalvm.util.EconomicMap;
 
 import jdk.vm.ci.code.BytecodeFrame;
 
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/GuardLoweringPhase.java	Fri Feb 16 12:24:38 2018 -0800
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/GuardLoweringPhase.java	Fri Feb 16 13:49:07 2018 -0800
@@ -120,7 +120,7 @@
     @Override
     protected void run(StructuredGraph graph, MidTierContext context) {
         if (graph.getGuardsStage().allowsFloatingGuards()) {
-            SchedulePhase schedulePhase = new SchedulePhase(SchedulingStrategy.EARLIEST);
+            SchedulePhase schedulePhase = new SchedulePhase(SchedulingStrategy.EARLIEST_WITH_GUARD_ORDER);
             schedulePhase.apply(graph);
             ScheduleResult schedule = graph.getLastSchedule();
 
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/PropagateDeoptimizeProbabilityPhase.java	Fri Feb 16 12:24:38 2018 -0800
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/PropagateDeoptimizeProbabilityPhase.java	Fri Feb 16 13:49:07 2018 -0800
@@ -22,6 +22,9 @@
  */
 package org.graalvm.compiler.phases.common;
 
+import org.graalvm.collections.EconomicMap;
+import org.graalvm.collections.EconomicSet;
+import org.graalvm.collections.MapCursor;
 import org.graalvm.compiler.graph.NodeStack;
 import org.graalvm.compiler.nodes.AbstractBeginNode;
 import org.graalvm.compiler.nodes.AbstractDeoptimizeNode;
@@ -32,9 +35,6 @@
 import org.graalvm.compiler.nodes.StructuredGraph;
 import org.graalvm.compiler.phases.BasePhase;
 import org.graalvm.compiler.phases.tiers.PhaseContext;
-import org.graalvm.util.EconomicMap;
-import org.graalvm.util.EconomicSet;
-import org.graalvm.util.MapCursor;
 
 /**
  * This phase will make sure that the branch leading towards this deopt has 0.0 probability.
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/UseTrappingNullChecksPhase.java	Fri Feb 16 12:24:38 2018 -0800
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/UseTrappingNullChecksPhase.java	Fri Feb 16 13:49:07 2018 -0800
@@ -50,6 +50,9 @@
 import org.graalvm.compiler.nodes.memory.FixedAccessNode;
 import org.graalvm.compiler.nodes.memory.address.AddressNode;
 import org.graalvm.compiler.nodes.util.GraphUtil;
+import org.graalvm.compiler.options.Option;
+import org.graalvm.compiler.options.OptionKey;
+import org.graalvm.compiler.options.OptionType;
 import org.graalvm.compiler.phases.BasePhase;
 import org.graalvm.compiler.phases.tiers.LowTierContext;
 
@@ -64,16 +67,24 @@
     private static final CounterKey counterTrappingNullCheckUnreached = DebugContext.counter("TrappingNullCheckUnreached");
     private static final CounterKey counterTrappingNullCheckDynamicDeoptimize = DebugContext.counter("TrappingNullCheckDynamicDeoptimize");
 
+    public static class Options {
+
+        // @formatter:off
+        @Option(help = "Use traps for null checks instead of explicit null-checks", type = OptionType.Expert)
+        public static final OptionKey<Boolean> UseTrappingNullChecks = new OptionKey<>(true);
+        // @formatter:on
+    }
+
     @Override
     protected void run(StructuredGraph graph, LowTierContext context) {
-        if (context.getTarget().implicitNullCheckLimit <= 0) {
+        if (!Options.UseTrappingNullChecks.getValue(graph.getOptions()) || context.getTarget().implicitNullCheckLimit <= 0) {
             return;
         }
         assert graph.getGuardsStage().areFrameStatesAtDeopts();
 
         long implicitNullCheckLimit = context.getTarget().implicitNullCheckLimit;
         for (DeoptimizeNode deopt : graph.getNodes(DeoptimizeNode.TYPE)) {
-            tryUseTrappingNullCheck(deopt, deopt.predecessor(), deopt.reason(), deopt.getSpeculation(), implicitNullCheckLimit);
+            tryUseTrappingNullCheck(deopt, deopt.predecessor(), deopt.getReason(), deopt.getSpeculation(), implicitNullCheckLimit);
         }
         for (DynamicDeoptimizeNode deopt : graph.getNodes(DynamicDeoptimizeNode.TYPE)) {
             tryUseTrappingNullCheck(context.getMetaAccess(), deopt, implicitNullCheckLimit);
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/inlining/InliningUtil.java	Fri Feb 16 12:24:38 2018 -0800
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/inlining/InliningUtil.java	Fri Feb 16 13:49:07 2018 -0800
@@ -33,6 +33,11 @@
 import java.util.Objects;
 import java.util.function.Consumer;
 
+import org.graalvm.collections.EconomicMap;
+import org.graalvm.collections.EconomicSet;
+import org.graalvm.collections.Equivalence;
+import org.graalvm.collections.UnmodifiableEconomicMap;
+import org.graalvm.collections.UnmodifiableMapCursor;
 import org.graalvm.compiler.api.replacements.MethodSubstitution;
 import org.graalvm.compiler.core.common.GraalOptions;
 import org.graalvm.compiler.core.common.type.Stamp;
@@ -92,11 +97,6 @@
 import org.graalvm.compiler.phases.common.inlining.info.InlineInfo;
 import org.graalvm.compiler.phases.common.util.HashSetNodeEventListener;
 import org.graalvm.compiler.phases.util.ValueMergeUtil;
-import org.graalvm.util.EconomicMap;
-import org.graalvm.util.EconomicSet;
-import org.graalvm.util.Equivalence;
-import org.graalvm.util.UnmodifiableEconomicMap;
-import org.graalvm.util.UnmodifiableMapCursor;
 
 import jdk.vm.ci.code.BytecodeFrame;
 import jdk.vm.ci.meta.Assumptions;
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/inlining/info/AbstractInlineInfo.java	Fri Feb 16 12:24:38 2018 -0800
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/inlining/info/AbstractInlineInfo.java	Fri Feb 16 13:49:07 2018 -0800
@@ -22,6 +22,7 @@
  */
 package org.graalvm.compiler.phases.common.inlining.info;
 
+import org.graalvm.collections.EconomicSet;
 import org.graalvm.compiler.graph.Node;
 import org.graalvm.compiler.nodes.Invoke;
 import org.graalvm.compiler.nodes.StructuredGraph;
@@ -31,7 +32,6 @@
 import org.graalvm.compiler.phases.common.inlining.info.elem.Inlineable;
 import org.graalvm.compiler.phases.common.inlining.info.elem.InlineableGraph;
 import org.graalvm.compiler.phases.tiers.HighTierContext;
-import org.graalvm.util.EconomicSet;
 
 import jdk.vm.ci.meta.ResolvedJavaMethod;
 
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/inlining/info/AssumptionInlineInfo.java	Fri Feb 16 12:24:38 2018 -0800
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/inlining/info/AssumptionInlineInfo.java	Fri Feb 16 13:49:07 2018 -0800
@@ -22,12 +22,12 @@
  */
 package org.graalvm.compiler.phases.common.inlining.info;
 
+import org.graalvm.collections.EconomicSet;
 import org.graalvm.compiler.graph.Node;
 import org.graalvm.compiler.nodes.CallTargetNode.InvokeKind;
 import org.graalvm.compiler.nodes.Invoke;
 import org.graalvm.compiler.phases.common.inlining.InliningUtil;
 import org.graalvm.compiler.phases.util.Providers;
-import org.graalvm.util.EconomicSet;
 
 import jdk.vm.ci.meta.Assumptions.AssumptionResult;
 import jdk.vm.ci.meta.ResolvedJavaMethod;
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/inlining/info/ExactInlineInfo.java	Fri Feb 16 12:24:38 2018 -0800
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/inlining/info/ExactInlineInfo.java	Fri Feb 16 13:49:07 2018 -0800
@@ -22,11 +22,11 @@
  */
 package org.graalvm.compiler.phases.common.inlining.info;
 
+import org.graalvm.collections.EconomicSet;
 import org.graalvm.compiler.graph.Node;
 import org.graalvm.compiler.nodes.Invoke;
 import org.graalvm.compiler.phases.common.inlining.info.elem.Inlineable;
 import org.graalvm.compiler.phases.util.Providers;
-import org.graalvm.util.EconomicSet;
 
 import jdk.vm.ci.meta.ResolvedJavaMethod;
 
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/inlining/info/InlineInfo.java	Fri Feb 16 12:24:38 2018 -0800
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/inlining/info/InlineInfo.java	Fri Feb 16 13:49:07 2018 -0800
@@ -22,6 +22,7 @@
  */
 package org.graalvm.compiler.phases.common.inlining.info;
 
+import org.graalvm.collections.EconomicSet;
 import org.graalvm.compiler.graph.Node;
 import org.graalvm.compiler.nodes.Invoke;
 import org.graalvm.compiler.nodes.StructuredGraph;
@@ -30,7 +31,6 @@
 import org.graalvm.compiler.phases.common.inlining.info.elem.Inlineable;
 import org.graalvm.compiler.phases.tiers.HighTierContext;
 import org.graalvm.compiler.phases.util.Providers;
-import org.graalvm.util.EconomicSet;
 
 import jdk.vm.ci.meta.ResolvedJavaMethod;
 
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/inlining/info/MultiTypeGuardInlineInfo.java	Fri Feb 16 12:24:38 2018 -0800
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/inlining/info/MultiTypeGuardInlineInfo.java	Fri Feb 16 13:49:07 2018 -0800
@@ -25,6 +25,8 @@
 import java.util.ArrayList;
 import java.util.List;
 
+import org.graalvm.collections.EconomicSet;
+import org.graalvm.collections.Equivalence;
 import org.graalvm.compiler.core.common.type.StampFactory;
 import org.graalvm.compiler.graph.Node;
 import org.graalvm.compiler.nodes.AbstractBeginNode;
@@ -54,8 +56,6 @@
 import org.graalvm.compiler.phases.common.inlining.InliningUtil;
 import org.graalvm.compiler.phases.common.inlining.info.elem.Inlineable;
 import org.graalvm.compiler.phases.util.Providers;
-import org.graalvm.util.EconomicSet;
-import org.graalvm.util.Equivalence;
 
 import jdk.vm.ci.meta.ConstantReflectionProvider;
 import jdk.vm.ci.meta.DeoptimizationAction;
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/inlining/info/TypeGuardInlineInfo.java	Fri Feb 16 12:24:38 2018 -0800
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/inlining/info/TypeGuardInlineInfo.java	Fri Feb 16 13:49:07 2018 -0800
@@ -22,7 +22,8 @@
  */
 package org.graalvm.compiler.phases.common.inlining.info;
 
-import org.graalvm.compiler.core.common.calc.Condition;
+import org.graalvm.collections.EconomicSet;
+import org.graalvm.compiler.core.common.calc.CanonicalCondition;
 import org.graalvm.compiler.graph.Node;
 import org.graalvm.compiler.nodes.CallTargetNode.InvokeKind;
 import org.graalvm.compiler.nodes.ConstantNode;
@@ -37,7 +38,6 @@
 import org.graalvm.compiler.phases.common.inlining.InliningUtil;
 import org.graalvm.compiler.phases.common.inlining.info.elem.Inlineable;
 import org.graalvm.compiler.phases.util.Providers;
-import org.graalvm.util.EconomicSet;
 
 import jdk.vm.ci.meta.DeoptimizationAction;
 import jdk.vm.ci.meta.DeoptimizationReason;
@@ -114,7 +114,7 @@
         LoadHubNode receiverHub = graph.unique(new LoadHubNode(providers.getStampProvider(), nonNullReceiver));
         ConstantNode typeHub = ConstantNode.forConstant(receiverHub.stamp(NodeView.DEFAULT), providers.getConstantReflection().asObjectHub(type), providers.getMetaAccess(), graph);
 
-        LogicNode typeCheck = CompareNode.createCompareNode(graph, Condition.EQ, receiverHub, typeHub, providers.getConstantReflection(), NodeView.DEFAULT);
+        LogicNode typeCheck = CompareNode.createCompareNode(graph, CanonicalCondition.EQ, receiverHub, typeHub, providers.getConstantReflection(), NodeView.DEFAULT);
         FixedGuardNode guard = graph.add(new FixedGuardNode(typeCheck, DeoptimizationReason.TypeCheckedInliningViolated, DeoptimizationAction.InvalidateReprofile));
         assert invoke.predecessor() != null;
 
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/inlining/walker/CallsiteHolderExplorable.java	Fri Feb 16 12:24:38 2018 -0800
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/inlining/walker/CallsiteHolderExplorable.java	Fri Feb 16 13:49:07 2018 -0800
@@ -26,6 +26,8 @@
 import java.util.LinkedList;
 import java.util.function.ToDoubleFunction;
 
+import org.graalvm.collections.EconomicSet;
+import org.graalvm.collections.Equivalence;
 import org.graalvm.compiler.nodes.FixedNode;
 import org.graalvm.compiler.nodes.Invoke;
 import org.graalvm.compiler.nodes.ParameterNode;
@@ -33,8 +35,6 @@
 import org.graalvm.compiler.nodes.ValueNode;
 import org.graalvm.compiler.phases.common.inlining.policy.AbstractInliningPolicy;
 import org.graalvm.compiler.phases.graph.FixedNodeProbabilityCache;
-import org.graalvm.util.Equivalence;
-import org.graalvm.util.EconomicSet;
 
 import jdk.vm.ci.meta.ResolvedJavaMethod;
 
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/inlining/walker/ComputeInliningRelevance.java	Fri Feb 16 12:24:38 2018 -0800
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/inlining/walker/ComputeInliningRelevance.java	Fri Feb 16 13:49:07 2018 -0800
@@ -25,6 +25,8 @@
 import java.util.ArrayList;
 import java.util.function.ToDoubleFunction;
 
+import org.graalvm.collections.EconomicMap;
+import org.graalvm.collections.Equivalence;
 import org.graalvm.compiler.core.common.SuppressFBWarnings;
 import org.graalvm.compiler.graph.Node;
 import org.graalvm.compiler.graph.NodeWorkList;
@@ -43,8 +45,6 @@
 import org.graalvm.compiler.nodes.StartNode;
 import org.graalvm.compiler.nodes.StructuredGraph;
 import org.graalvm.compiler.phases.common.inlining.InliningUtil;
-import org.graalvm.util.Equivalence;
-import org.graalvm.util.EconomicMap;
 
 public class ComputeInliningRelevance {
 
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/inlining/walker/InliningData.java	Fri Feb 16 12:24:38 2018 -0800
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/inlining/walker/InliningData.java	Fri Feb 16 13:49:07 2018 -0800
@@ -34,6 +34,8 @@
 import java.util.LinkedList;
 import java.util.List;
 
+import org.graalvm.collections.EconomicSet;
+import org.graalvm.collections.Equivalence;
 import org.graalvm.compiler.core.common.type.ObjectStamp;
 import org.graalvm.compiler.debug.CounterKey;
 import org.graalvm.compiler.debug.DebugContext;
@@ -64,8 +66,6 @@
 import org.graalvm.compiler.phases.common.inlining.policy.InliningPolicy;
 import org.graalvm.compiler.phases.tiers.HighTierContext;
 import org.graalvm.compiler.phases.util.Providers;
-import org.graalvm.util.EconomicSet;
-import org.graalvm.util.Equivalence;
 
 import jdk.vm.ci.code.BailoutException;
 import jdk.vm.ci.meta.Assumptions.AssumptionResult;
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/util/HashSetNodeEventListener.java	Fri Feb 16 12:24:38 2018 -0800
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases.common/src/org/graalvm/compiler/phases/common/util/HashSetNodeEventListener.java	Fri Feb 16 13:49:07 2018 -0800
@@ -26,12 +26,12 @@
 import java.util.HashSet;
 import java.util.Set;
 
+import org.graalvm.collections.EconomicSet;
+import org.graalvm.collections.Equivalence;
 import org.graalvm.compiler.graph.Graph.NodeEvent;
 import org.graalvm.compiler.graph.Graph.NodeEventListener;
 import org.graalvm.compiler.graph.Node;
 import org.graalvm.compiler.graph.Node.IndirectCanonicalization;
-import org.graalvm.util.Equivalence;
-import org.graalvm.util.EconomicSet;
 
 /**
  * A simple {@link NodeEventListener} implementation that accumulates event nodes in a
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/graph/FixedNodeProbabilityCache.java	Fri Feb 16 12:24:38 2018 -0800
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/graph/FixedNodeProbabilityCache.java	Fri Feb 16 13:49:07 2018 -0800
@@ -22,8 +22,12 @@
  */
 package org.graalvm.compiler.phases.graph;
 
+import static org.graalvm.compiler.nodes.cfg.ControlFlowGraph.multiplyProbabilities;
+
 import java.util.function.ToDoubleFunction;
 
+import org.graalvm.collections.EconomicMap;
+import org.graalvm.collections.Equivalence;
 import org.graalvm.compiler.debug.CounterKey;
 import org.graalvm.compiler.debug.DebugContext;
 import org.graalvm.compiler.graph.Node;
@@ -36,10 +40,6 @@
 import org.graalvm.compiler.nodes.FixedNode;
 import org.graalvm.compiler.nodes.LoopBeginNode;
 import org.graalvm.compiler.nodes.StartNode;
-import org.graalvm.util.EconomicMap;
-import org.graalvm.util.Equivalence;
-
-import static org.graalvm.compiler.nodes.cfg.ControlFlowGraph.multiplyProbabilities;
 
 /**
  * Compute probabilities for fixed nodes on the fly and cache them at {@link AbstractBeginNode}s.
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/graph/PostOrderNodeIterator.java	Fri Feb 16 12:24:38 2018 -0800
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/graph/PostOrderNodeIterator.java	Fri Feb 16 13:49:07 2018 -0800
@@ -27,6 +27,8 @@
 import java.util.Deque;
 import java.util.Set;
 
+import org.graalvm.collections.EconomicMap;
+import org.graalvm.collections.Equivalence;
 import org.graalvm.compiler.graph.Node;
 import org.graalvm.compiler.graph.NodeBitMap;
 import org.graalvm.compiler.nodes.AbstractBeginNode;
@@ -41,8 +43,6 @@
 import org.graalvm.compiler.nodes.LoopBeginNode;
 import org.graalvm.compiler.nodes.LoopEndNode;
 import org.graalvm.compiler.nodes.StructuredGraph;
-import org.graalvm.util.Equivalence;
-import org.graalvm.util.EconomicMap;
 
 /**
  * A PostOrderNodeIterator iterates the fixed nodes of the graph in post order starting from a
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/graph/ReentrantBlockIterator.java	Fri Feb 16 12:24:38 2018 -0800
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/graph/ReentrantBlockIterator.java	Fri Feb 16 13:49:07 2018 -0800
@@ -28,6 +28,8 @@
 import java.util.List;
 import java.util.function.Predicate;
 
+import org.graalvm.collections.EconomicMap;
+import org.graalvm.collections.Equivalence;
 import org.graalvm.compiler.core.common.PermanentBailoutException;
 import org.graalvm.compiler.core.common.RetryableBailoutException;
 import org.graalvm.compiler.core.common.cfg.Loop;
@@ -38,8 +40,6 @@
 import org.graalvm.compiler.nodes.LoopBeginNode;
 import org.graalvm.compiler.nodes.StructuredGraph;
 import org.graalvm.compiler.nodes.cfg.Block;
-import org.graalvm.util.Equivalence;
-import org.graalvm.util.EconomicMap;
 
 public final class ReentrantBlockIterator {
 
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/graph/ReentrantNodeIterator.java	Fri Feb 16 12:24:38 2018 -0800
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/graph/ReentrantNodeIterator.java	Fri Feb 16 13:49:07 2018 -0800
@@ -28,6 +28,9 @@
 import java.util.Iterator;
 import java.util.List;
 
+import org.graalvm.collections.EconomicMap;
+import org.graalvm.collections.Equivalence;
+import org.graalvm.collections.MapCursor;
 import org.graalvm.compiler.graph.Node;
 import org.graalvm.compiler.nodes.AbstractBeginNode;
 import org.graalvm.compiler.nodes.AbstractEndNode;
@@ -38,9 +41,6 @@
 import org.graalvm.compiler.nodes.LoopBeginNode;
 import org.graalvm.compiler.nodes.LoopEndNode;
 import org.graalvm.compiler.nodes.LoopExitNode;
-import org.graalvm.util.Equivalence;
-import org.graalvm.util.EconomicMap;
-import org.graalvm.util.MapCursor;
 
 public final class ReentrantNodeIterator {
 
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/graph/SinglePassNodeIterator.java	Fri Feb 16 12:24:38 2018 -0800
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/graph/SinglePassNodeIterator.java	Fri Feb 16 13:49:07 2018 -0800
@@ -27,6 +27,8 @@
 import java.util.Deque;
 import java.util.List;
 
+import org.graalvm.collections.EconomicMap;
+import org.graalvm.collections.Equivalence;
 import org.graalvm.compiler.graph.Node;
 import org.graalvm.compiler.graph.NodeBitMap;
 import org.graalvm.compiler.nodes.AbstractBeginNode;
@@ -42,8 +44,6 @@
 import org.graalvm.compiler.nodes.LoopEndNode;
 import org.graalvm.compiler.nodes.StartNode;
 import org.graalvm.compiler.nodes.StructuredGraph;
-import org.graalvm.util.Equivalence;
-import org.graalvm.util.EconomicMap;
 
 /**
  * A SinglePassNodeIterator iterates the fixed nodes of the graph in post order starting from its
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/schedule/MemoryScheduleVerification.java	Fri Feb 16 12:24:38 2018 -0800
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/schedule/MemoryScheduleVerification.java	Fri Feb 16 13:49:07 2018 -0800
@@ -24,6 +24,8 @@
 
 import java.util.List;
 
+import org.graalvm.collections.EconomicSet;
+import org.graalvm.collections.Equivalence;
 import org.graalvm.compiler.core.common.cfg.BlockMap;
 import org.graalvm.compiler.core.common.cfg.Loop;
 import org.graalvm.compiler.debug.DebugContext;
@@ -40,8 +42,6 @@
 import org.graalvm.compiler.nodes.memory.MemoryPhiNode;
 import org.graalvm.compiler.phases.graph.ReentrantBlockIterator;
 import org.graalvm.compiler.phases.graph.ReentrantBlockIterator.BlockIteratorClosure;
-import org.graalvm.util.EconomicSet;
-import org.graalvm.util.Equivalence;
 import org.graalvm.word.LocationIdentity;
 
 public final class MemoryScheduleVerification extends BlockIteratorClosure<EconomicSet<FloatingReadNode>> {
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/schedule/SchedulePhase.java	Fri Feb 16 12:24:38 2018 -0800
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/schedule/SchedulePhase.java	Fri Feb 16 13:49:07 2018 -0800
@@ -22,14 +22,23 @@
  */
 package org.graalvm.compiler.phases.schedule;
 
+import static org.graalvm.collections.Equivalence.IDENTITY;
+import static org.graalvm.compiler.core.common.GraalOptions.GuardPriorities;
 import static org.graalvm.compiler.core.common.GraalOptions.OptScheduleOutOfLoops;
 import static org.graalvm.compiler.core.common.cfg.AbstractControlFlowGraph.strictlyDominates;
 
 import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.Comparator;
+import java.util.EnumMap;
 import java.util.Formatter;
+import java.util.Iterator;
 import java.util.List;
+import java.util.SortedSet;
+import java.util.TreeSet;
+import java.util.function.Function;
 
+import org.graalvm.collections.EconomicSet;
 import org.graalvm.compiler.core.common.SuppressFBWarnings;
 import org.graalvm.compiler.core.common.cfg.AbstractControlFlowGraph;
 import org.graalvm.compiler.core.common.cfg.BlockMap;
@@ -48,7 +57,6 @@
 import org.graalvm.compiler.nodes.ControlSplitNode;
 import org.graalvm.compiler.nodes.DeoptimizeNode;
 import org.graalvm.compiler.nodes.FixedNode;
-import org.graalvm.compiler.nodes.FixedWithNextNode;
 import org.graalvm.compiler.nodes.GuardNode;
 import org.graalvm.compiler.nodes.IfNode;
 import org.graalvm.compiler.nodes.KillingBeginNode;
@@ -57,6 +65,8 @@
 import org.graalvm.compiler.nodes.PhiNode;
 import org.graalvm.compiler.nodes.ProxyNode;
 import org.graalvm.compiler.nodes.StartNode;
+import org.graalvm.compiler.nodes.StaticDeoptimizingNode;
+import org.graalvm.compiler.nodes.StaticDeoptimizingNode.GuardPriority;
 import org.graalvm.compiler.nodes.StructuredGraph;
 import org.graalvm.compiler.nodes.StructuredGraph.GuardsStage;
 import org.graalvm.compiler.nodes.StructuredGraph.ScheduleResult;
@@ -78,10 +88,19 @@
 public final class SchedulePhase extends Phase {
 
     public enum SchedulingStrategy {
+        EARLIEST_WITH_GUARD_ORDER,
         EARLIEST,
         LATEST,
         LATEST_OUT_OF_LOOPS,
-        FINAL_SCHEDULE
+        FINAL_SCHEDULE;
+
+        public boolean isEarliest() {
+            return this == EARLIEST || this == EARLIEST_WITH_GUARD_ORDER;
+        }
+
+        public boolean isLatest() {
+            return !isEarliest();
+        }
     }
 
     private final SchedulingStrategy selectedStrategy;
@@ -164,13 +183,13 @@
             this.nodeToBlockMap = currentNodeMap;
             this.blockToNodesMap = earliestBlockToNodesMap;
 
-            scheduleEarliestIterative(earliestBlockToNodesMap, currentNodeMap, visited, graph, immutableGraph);
+            scheduleEarliestIterative(earliestBlockToNodesMap, currentNodeMap, visited, graph, immutableGraph, selectedStrategy == SchedulingStrategy.EARLIEST_WITH_GUARD_ORDER);
 
-            if (selectedStrategy != SchedulingStrategy.EARLIEST) {
+            if (!selectedStrategy.isEarliest()) {
                 // For non-earliest schedules, we need to do a second pass.
                 BlockMap<List<Node>> latestBlockToNodesMap = new BlockMap<>(cfg);
                 for (Block b : cfg.getBlocks()) {
-                    latestBlockToNodesMap.put(b, new ArrayList<Node>());
+                    latestBlockToNodesMap.put(b, new ArrayList<>());
                 }
 
                 BlockMap<ArrayList<FloatingReadNode>> watchListMap = calcLatestBlocks(selectedStrategy, currentNodeMap, earliestBlockToNodesMap, visited, latestBlockToNodesMap, immutableGraph);
@@ -181,8 +200,8 @@
 
                 this.blockToNodesMap = latestBlockToNodesMap;
 
-                cfg.setNodeToBlock(currentNodeMap);
             }
+            cfg.setNodeToBlock(currentNodeMap);
 
             graph.setLastSchedule(new ScheduleResult(this.cfg, this.nodeToBlockMap, this.blockToNodesMap));
         }
@@ -524,7 +543,6 @@
                 assert latestBlock != null : currentNode;
 
                 if (strategy == SchedulingStrategy.FINAL_SCHEDULE || strategy == SchedulingStrategy.LATEST_OUT_OF_LOOPS) {
-                    assert latestBlock != null;
                     Block currentBlock = latestBlock;
                     while (currentBlock.getLoopDepth() > earliestBlock.getLoopDepth() && currentBlock != earliestBlock.getDominator()) {
                         Block previousCurrentBlock = currentBlock;
@@ -645,7 +663,7 @@
              */
             public void add(Node node) {
                 assert !(node instanceof FixedNode) : node;
-                NodeEntry newTail = new NodeEntry(node, null);
+                NodeEntry newTail = new NodeEntry(node);
                 if (tail == null) {
                     tail = head = newTail;
                 } else {
@@ -659,9 +677,18 @@
              * Number of nodes in this micro block.
              */
             public int getNodeCount() {
+                assert getActualNodeCount() == nodeCount : getActualNodeCount() + " != " + nodeCount;
                 return nodeCount;
             }
 
+            private int getActualNodeCount() {
+                int count = 0;
+                for (NodeEntry e = head; e != null; e = e.next) {
+                    count++;
+                }
+                return count;
+            }
+
             /**
              * The id of the micro block, with a block always associated with a lower id than its
              * successors.
@@ -685,6 +712,7 @@
              */
             public void prependChildrenTo(MicroBlock newBlock) {
                 if (tail != null) {
+                    assert head != null;
                     tail.next = newBlock.head;
                     newBlock.head = head;
                     head = tail = null;
@@ -697,6 +725,11 @@
             public String toString() {
                 return String.format("MicroBlock[id=%d]", id);
             }
+
+            @Override
+            public int hashCode() {
+                return id;
+            }
         }
 
         /**
@@ -706,9 +739,9 @@
             private final Node node;
             private NodeEntry next;
 
-            NodeEntry(Node node, NodeEntry next) {
+            NodeEntry(Node node) {
                 this.node = node;
-                this.next = next;
+                this.next = null;
             }
 
             public NodeEntry getNext() {
@@ -720,7 +753,8 @@
             }
         }
 
-        private void scheduleEarliestIterative(BlockMap<List<Node>> blockToNodes, NodeMap<Block> nodeToBlock, NodeBitMap visited, StructuredGraph graph, boolean immutableGraph) {
+        private void scheduleEarliestIterative(BlockMap<List<Node>> blockToNodes, NodeMap<Block> nodeToBlock, NodeBitMap visited, StructuredGraph graph, boolean immutableGraph,
+                        boolean withGuardOrder) {
 
             NodeMap<MicroBlock> entries = graph.createNodeMap();
             NodeStack stack = new NodeStack();
@@ -729,62 +763,44 @@
             MicroBlock startBlock = null;
             int nextId = 1;
             for (Block b : cfg.reversePostOrder()) {
-                FixedNode current = b.getBeginNode();
-                while (true) {
+                for (FixedNode current : b.getBeginNode().getBlockNodes()) {
                     MicroBlock microBlock = new MicroBlock(nextId++);
-                    entries.put(current, microBlock);
-                    visited.checkAndMarkInc(current);
-
+                    entries.set(current, microBlock);
+                    boolean isNew = visited.checkAndMarkInc(current);
+                    assert isNew;
                     if (startBlock == null) {
                         startBlock = microBlock;
                     }
-
-                    // Process inputs of this fixed node.
-                    for (Node input : current.inputs()) {
-                        if (entries.get(input) == null) {
-                            processStack(input, startBlock, entries, visited, stack);
-                        }
-                    }
-
-                    if (current == b.getEndNode()) {
-                        // Break loop when reaching end node.
-                        break;
-                    }
-
-                    current = ((FixedWithNextNode) current).next();
                 }
             }
 
-            // Now process guards.
-            for (GuardNode guardNode : graph.getNodes(GuardNode.TYPE)) {
-                if (entries.get(guardNode) == null) {
-                    processStack(guardNode, startBlock, entries, visited, stack);
+            if (graph.getGuardsStage().allowsFloatingGuards() && graph.getNodes(GuardNode.TYPE).isNotEmpty()) {
+                // Now process guards.
+                if (GuardPriorities.getValue(graph.getOptions()) && withGuardOrder) {
+                    EnumMap<GuardPriority, List<GuardNode>> guardsByPriority = new EnumMap<>(GuardPriority.class);
+                    for (GuardNode guard : graph.getNodes(GuardNode.TYPE)) {
+                        guardsByPriority.computeIfAbsent(guard.computePriority(), p -> new ArrayList<>()).add(guard);
+                    }
+                    // `EnumMap.values` returns values in "natural" key order
+                    for (List<GuardNode> guards : guardsByPriority.values()) {
+                        processNodes(visited, entries, stack, startBlock, guards);
+                    }
+                    GuardOrder.resortGuards(graph, entries, stack);
+                } else {
+                    processNodes(visited, entries, stack, startBlock, graph.getNodes(GuardNode.TYPE));
                 }
+            } else {
+                assert graph.getNodes(GuardNode.TYPE).isEmpty();
             }
 
             // Now process inputs of fixed nodes.
             for (Block b : cfg.reversePostOrder()) {
-                FixedNode current = b.getBeginNode();
-                while (true) {
-
-                    // Process inputs of this fixed node.
-                    for (Node input : current.inputs()) {
-                        if (entries.get(input) == null) {
-                            processStack(input, startBlock, entries, visited, stack);
-                        }
-                    }
-
-                    if (current == b.getEndNode()) {
-                        // Break loop when reaching end node.
-                        break;
-                    }
-
-                    current = ((FixedWithNextNode) current).next();
+                for (FixedNode current : b.getBeginNode().getBlockNodes()) {
+                    processNodes(visited, entries, stack, startBlock, current.inputs());
                 }
             }
 
             if (visited.getCounter() < graph.getNodeCount()) {
-
                 // Visit back input edges of loop phis.
                 boolean changed;
                 boolean unmarkedPhi;
@@ -829,36 +845,29 @@
                 if (fixedNode instanceof ControlSplitNode) {
                     ControlSplitNode controlSplitNode = (ControlSplitNode) fixedNode;
                     MicroBlock endBlock = entries.get(fixedNode);
-                    MicroBlock primarySuccessor = entries.get(controlSplitNode.getPrimarySuccessor());
-                    endBlock.prependChildrenTo(primarySuccessor);
+                    AbstractBeginNode primarySuccessor = controlSplitNode.getPrimarySuccessor();
+                    if (primarySuccessor != null) {
+                        endBlock.prependChildrenTo(entries.get(primarySuccessor));
+                    } else {
+                        assert endBlock.tail == null;
+                    }
                 }
             }
 
-            // Initialize with begin nodes
+            // Create lists for each block
             for (Block b : cfg.reversePostOrder()) {
-
-                FixedNode current = b.getBeginNode();
+                // Count nodes in block
                 int totalCount = 0;
-                while (true) {
-
+                for (FixedNode current : b.getBeginNode().getBlockNodes()) {
                     MicroBlock microBlock = entries.get(current);
                     totalCount += microBlock.getNodeCount() + 1;
-
-                    if (current == b.getEndNode()) {
-                        // Break loop when reaching end node.
-                        break;
-                    }
-
-                    current = ((FixedWithNextNode) current).next();
                 }
 
                 // Initialize with begin node, it is always the first node.
                 ArrayList<Node> nodes = new ArrayList<>(totalCount);
                 blockToNodes.put(b, nodes);
 
-                current = b.getBeginNode();
-                while (true) {
-
+                for (FixedNode current : b.getBeginNode().getBlockNodes()) {
                     MicroBlock microBlock = entries.get(current);
                     nodeToBlock.set(current, b);
                     nodes.add(current);
@@ -869,19 +878,20 @@
                         nodes.add(nextNode);
                         next = next.getNext();
                     }
-
-                    if (current == b.getEndNode()) {
-                        // Break loop when reaching end node.
-                        break;
-                    }
-
-                    current = ((FixedWithNextNode) current).next();
                 }
             }
 
             assert (!Assertions.detailedAssertionsEnabled(cfg.graph.getOptions())) || MemoryScheduleVerification.check(cfg.getStartBlock(), blockToNodes);
         }
 
+        private static void processNodes(NodeBitMap visited, NodeMap<MicroBlock> entries, NodeStack stack, MicroBlock startBlock, Iterable<? extends Node> nodes) {
+            for (Node node : nodes) {
+                if (entries.get(node) == null) {
+                    processStack(node, startBlock, entries, visited, stack);
+                }
+            }
+        }
+
         private static void processStackPhi(NodeStack stack, PhiNode phiNode, NodeMap<MicroBlock> nodeToBlock, NodeBitMap visited) {
             stack.pop();
             if (visited.checkAndMarkInc(phiNode)) {
@@ -944,6 +954,166 @@
             }
         }
 
+        private static class GuardOrder {
+            /**
+             * After an earliest schedule, this will re-sort guards to honor their
+             * {@linkplain StaticDeoptimizingNode#computePriority() priority}.
+             *
+             * Note that this only changes the order of nodes within {@linkplain MicroBlock
+             * micro-blocks}, nodes will not be moved from one micro-block to another.
+             */
+            private static void resortGuards(StructuredGraph graph, NodeMap<MicroBlock> entries, NodeStack stack) {
+                assert stack.isEmpty();
+                EconomicSet<MicroBlock> blocksWithGuards = EconomicSet.create(IDENTITY);
+                for (GuardNode guard : graph.getNodes(GuardNode.TYPE)) {
+                    MicroBlock block = entries.get(guard);
+                    assert block != null : guard + "should already be scheduled to a micro-block";
+                    blocksWithGuards.add(block);
+                }
+                assert !blocksWithGuards.isEmpty();
+                NodeMap<GuardPriority> priorities = graph.createNodeMap();
+                NodeBitMap blockNodes = graph.createNodeBitMap();
+                for (MicroBlock block : blocksWithGuards) {
+                    MicroBlock newBlock = resortGuards(block, stack, blockNodes, priorities);
+                    assert stack.isEmpty();
+                    assert blockNodes.isEmpty();
+                    if (newBlock != null) {
+                        assert block.getNodeCount() == newBlock.getNodeCount();
+                        block.head = newBlock.head;
+                        block.tail = newBlock.tail;
+                    }
+                }
+            }
+
+            /**
+             * This resorts guards within one micro-block.
+             *
+             * {@code stack}, {@code blockNodes} and {@code priorities} are just temporary
+             * data-structures which are allocated once by the callers of this method. They should
+             * be in their "initial"/"empty" state when calling this method and when it returns.
+             */
+            private static MicroBlock resortGuards(MicroBlock block, NodeStack stack, NodeBitMap blockNodes, NodeMap<GuardPriority> priorities) {
+                if (!propagatePriority(block, stack, priorities, blockNodes)) {
+                    return null;
+                }
+
+                Function<GuardNode, GuardPriority> transitiveGuardPriorityGetter = priorities::get;
+                Comparator<GuardNode> globalGuardPriorityComparator = Comparator.comparing(transitiveGuardPriorityGetter).thenComparing(GuardNode::computePriority).thenComparingInt(Node::hashCode);
+
+                SortedSet<GuardNode> availableGuards = new TreeSet<>(globalGuardPriorityComparator);
+                MicroBlock newBlock = new MicroBlock(block.getId());
+
+                NodeBitMap sorted = blockNodes;
+                sorted.invert();
+
+                for (NodeEntry e = block.head; e != null; e = e.next) {
+                    checkIfAvailable(e.node, stack, sorted, newBlock, availableGuards, false);
+                }
+                do {
+                    while (!stack.isEmpty()) {
+                        checkIfAvailable(stack.pop(), stack, sorted, newBlock, availableGuards, true);
+                    }
+                    Iterator<GuardNode> iterator = availableGuards.iterator();
+                    if (iterator.hasNext()) {
+                        addNodeToResort(iterator.next(), stack, sorted, newBlock, true);
+                        iterator.remove();
+                    }
+                } while (!stack.isEmpty() || !availableGuards.isEmpty());
+
+                blockNodes.clearAll();
+                return newBlock;
+            }
+
+            /**
+             * This checks if {@code n} can be scheduled, if it is the case, it schedules it now by
+             * calling {@link #addNodeToResort(Node, NodeStack, NodeBitMap, MicroBlock, boolean)}.
+             */
+            private static void checkIfAvailable(Node n, NodeStack stack, NodeBitMap sorted, Instance.MicroBlock newBlock, SortedSet<GuardNode> availableGuardNodes, boolean pushUsages) {
+                if (sorted.isMarked(n)) {
+                    return;
+                }
+                for (Node in : n.inputs()) {
+                    if (!sorted.isMarked(in)) {
+                        return;
+                    }
+                }
+                if (n instanceof GuardNode) {
+                    availableGuardNodes.add((GuardNode) n);
+                } else {
+                    addNodeToResort(n, stack, sorted, newBlock, pushUsages);
+                }
+            }
+
+            /**
+             * Add a node to the re-sorted micro-block. This also pushes nodes that need to be
+             * (re-)examined on the stack.
+             */
+            private static void addNodeToResort(Node n, NodeStack stack, NodeBitMap sorted, MicroBlock newBlock, boolean pushUsages) {
+                sorted.mark(n);
+                newBlock.add(n);
+                if (pushUsages) {
+                    for (Node u : n.usages()) {
+                        if (!sorted.isMarked(u)) {
+                            stack.push(u);
+                        }
+                    }
+                }
+            }
+
+            /**
+             * This fills in a map of transitive priorities ({@code priorities}). It also marks the
+             * nodes from this micro-block in {@code blockNodes}.
+             *
+             * The transitive priority of a guard is the highest of its priority and the priority of
+             * the guards that depend on it (transitively).
+             *
+             * This method returns {@code false} if no re-ordering is necessary in this micro-block.
+             */
+            private static boolean propagatePriority(MicroBlock block, NodeStack stack, NodeMap<GuardPriority> priorities, NodeBitMap blockNodes) {
+                assert stack.isEmpty();
+                assert blockNodes.isEmpty();
+                GuardPriority lowestPriority = GuardPriority.highest();
+                for (NodeEntry e = block.head; e != null; e = e.next) {
+                    blockNodes.mark(e.node);
+                    if (e.node instanceof GuardNode) {
+                        GuardNode guard = (GuardNode) e.node;
+                        GuardPriority priority = guard.computePriority();
+                        if (lowestPriority != null) {
+                            if (priority.isLowerPriorityThan(lowestPriority)) {
+                                lowestPriority = priority;
+                            } else if (priority.isHigherPriorityThan(lowestPriority)) {
+                                lowestPriority = null;
+                            }
+                        }
+                        stack.push(guard);
+                        priorities.set(guard, priority);
+                    }
+                }
+                if (lowestPriority != null) {
+                    stack.clear();
+                    blockNodes.clearAll();
+                    return false;
+                }
+
+                do {
+                    Node current = stack.pop();
+                    assert blockNodes.isMarked(current);
+                    GuardPriority priority = priorities.get(current);
+                    for (Node input : current.inputs()) {
+                        if (!blockNodes.isMarked(input)) {
+                            continue;
+                        }
+                        GuardPriority inputPriority = priorities.get(input);
+                        if (inputPriority == null || inputPriority.isLowerPriorityThan(priority)) {
+                            priorities.set(input, priority);
+                            stack.push(input);
+                        }
+                    }
+                } while (!stack.isEmpty());
+                return true;
+            }
+        }
+
         /**
          * Processes the inputs of given block. Pushes unprocessed inputs onto the stack. Returns
          * null if there were still unprocessed inputs, otherwise returns the earliest block given
@@ -960,7 +1130,7 @@
                 if (inputBlock == null) {
                     earliestBlock = null;
                     stack.push(input);
-                } else if (earliestBlock != null && inputBlock.getId() >= earliestBlock.getId()) {
+                } else if (earliestBlock != null && inputBlock.getId() > earliestBlock.getId()) {
                     earliestBlock = inputBlock;
                 }
             }
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/util/GraphOrder.java	Fri Feb 16 12:24:38 2018 -0800
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/util/GraphOrder.java	Fri Feb 16 13:49:07 2018 -0800
@@ -25,6 +25,8 @@
 import java.util.ArrayList;
 import java.util.List;
 
+import org.graalvm.collections.EconomicMap;
+import org.graalvm.collections.Equivalence;
 import org.graalvm.compiler.core.common.cfg.Loop;
 import org.graalvm.compiler.debug.GraalError;
 import org.graalvm.compiler.graph.GraalGraphError;
@@ -55,8 +57,6 @@
 import org.graalvm.compiler.phases.graph.StatelessPostOrderNodeIterator;
 import org.graalvm.compiler.phases.schedule.SchedulePhase;
 import org.graalvm.compiler.phases.schedule.SchedulePhase.SchedulingStrategy;
-import org.graalvm.util.EconomicMap;
-import org.graalvm.util.Equivalence;
 
 public final class GraphOrder {
 
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/util/Providers.java	Fri Feb 16 12:24:38 2018 -0800
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/util/Providers.java	Fri Feb 16 13:49:07 2018 -0800
@@ -22,6 +22,7 @@
  */
 package org.graalvm.compiler.phases.util;
 
+import org.graalvm.compiler.core.common.spi.ArrayOffsetProvider;
 import org.graalvm.compiler.core.common.spi.CodeGenProviders;
 import org.graalvm.compiler.core.common.spi.ConstantFieldProvider;
 import org.graalvm.compiler.core.common.spi.ForeignCallsProvider;
@@ -90,6 +91,11 @@
     }
 
     @Override
+    public ArrayOffsetProvider getArrayOffsetProvider() {
+        return lowerer;
+    }
+
+    @Override
     public ConstantReflectionProvider getConstantReflection() {
         return constantReflection;
     }
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/verify/VerifyDebugUsage.java	Fri Feb 16 12:24:38 2018 -0800
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/verify/VerifyDebugUsage.java	Fri Feb 16 13:49:07 2018 -0800
@@ -143,9 +143,9 @@
                     "org.graalvm.compiler.phases.BasePhase.dumpAfter",
                     "org.graalvm.compiler.phases.BasePhase.dumpBefore",
                     "org.graalvm.compiler.core.GraalCompiler.emitFrontEnd",
-                    "org.graalvm.compiler.truffle.PartialEvaluator.fastPartialEvaluation",
-                    "org.graalvm.compiler.truffle.PartialEvaluator$PerformanceInformationHandler.reportPerformanceWarnings",
-                    "org.graalvm.compiler.truffle.TruffleCompiler.compileMethodHelper",
+                    "org.graalvm.compiler.truffle.compiler.PartialEvaluator.fastPartialEvaluation",
+                    "org.graalvm.compiler.truffle.compiler.PartialEvaluator$PerformanceInformationHandler.reportPerformanceWarnings",
+                    "org.graalvm.compiler.truffle.compiler.TruffleCompilerImpl.compilePEGraph",
                     "org.graalvm.compiler.core.test.VerifyDebugUsageTest$ValidDumpUsagePhase.run",
                     "org.graalvm.compiler.core.test.VerifyDebugUsageTest$InvalidConcatDumpUsagePhase.run",
                     "org.graalvm.compiler.core.test.VerifyDebugUsageTest$InvalidDumpUsagePhase.run"));
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/verify/VerifyGraphAddUsage.java	Fri Feb 16 12:24:38 2018 -0800
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.phases/src/org/graalvm/compiler/phases/verify/VerifyGraphAddUsage.java	Fri Feb 16 13:49:07 2018 -0800
@@ -22,8 +22,10 @@
  */
 package org.graalvm.compiler.phases.verify;
 
-import jdk.vm.ci.meta.ResolvedJavaMethod;
-import jdk.vm.ci.meta.ResolvedJavaType;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Method;
+
+import org.graalvm.collections.EconomicSet;
 import org.graalvm.compiler.debug.GraalError;
 import org.graalvm.compiler.graph.Graph;
 import org.graalvm.compiler.graph.Node;
@@ -40,10 +42,9 @@
 import org.graalvm.compiler.nodes.spi.LoweringProvider;
 import org.graalvm.compiler.phases.VerifyPhase;
 import org.graalvm.compiler.phases.tiers.PhaseContext;
-import org.graalvm.util.EconomicSet;
 
-import java.lang.reflect.Constructor;
-import java.lang.reflect.Method;
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+import jdk.vm.ci.meta.ResolvedJavaType;
 
 public class VerifyGraphAddUsage extends VerifyPhase<PhaseContext> {
     private static final Method ADD_OR_UNIQUE;
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.printer/src/org/graalvm/compiler/printer/CFGPrinter.java	Fri Feb 16 12:24:38 2018 -0800
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.printer/src/org/graalvm/compiler/printer/CFGPrinter.java	Fri Feb 16 13:49:07 2018 -0800
@@ -33,6 +33,7 @@
 import java.util.Map;
 import java.util.TreeMap;
 
+import org.graalvm.collections.UnmodifiableMapCursor;
 import org.graalvm.compiler.bytecode.Bytecode;
 import org.graalvm.compiler.bytecode.BytecodeDisassembler;
 import org.graalvm.compiler.core.common.alloc.Trace;
@@ -66,7 +67,6 @@
 import org.graalvm.compiler.nodes.calc.FloatingNode;
 import org.graalvm.compiler.nodes.cfg.Block;
 import org.graalvm.compiler.nodes.cfg.ControlFlowGraph;
-import org.graalvm.util.UnmodifiableMapCursor;
 
 import jdk.vm.ci.code.DebugInfo;
 import jdk.vm.ci.code.TargetDescription;
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.amd64/src/org/graalvm/compiler/replacements/amd64/AMD64StringSubstitutions.java	Fri Feb 16 12:24:38 2018 -0800
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.amd64/src/org/graalvm/compiler/replacements/amd64/AMD64StringSubstitutions.java	Fri Feb 16 13:49:07 2018 -0800
@@ -23,12 +23,15 @@
 package org.graalvm.compiler.replacements.amd64;
 
 import org.graalvm.compiler.api.replacements.ClassSubstitution;
+import org.graalvm.compiler.api.replacements.Fold;
+import org.graalvm.compiler.api.replacements.Fold.InjectedParameter;
 import org.graalvm.compiler.api.replacements.MethodSubstitution;
+import org.graalvm.compiler.core.common.spi.ArrayOffsetProvider;
 import org.graalvm.compiler.graph.Node.ConstantNodeParameter;
 import org.graalvm.compiler.word.Word;
 import org.graalvm.word.Pointer;
 
-import sun.misc.Unsafe;
+import jdk.vm.ci.meta.JavaKind;
 
 // JaCoCo Exclude
 
@@ -38,6 +41,19 @@
 @ClassSubstitution(String.class)
 public class AMD64StringSubstitutions {
 
+    @Fold
+    static int charArrayBaseOffset(@InjectedParameter ArrayOffsetProvider arrayOffsetProvider) {
+        return arrayOffsetProvider.arrayBaseOffset(JavaKind.Char);
+    }
+
+    @Fold
+    static int charArrayIndexScale(@InjectedParameter ArrayOffsetProvider arrayOffsetProvider) {
+        return arrayOffsetProvider.arrayScalingFactor(JavaKind.Char);
+    }
+
+    /** Marker value for the {@link InjectedParameter} injected parameter. */
+    static final ArrayOffsetProvider INJECTED = null;
+
     // Only exists in JDK <= 8
     @MethodSubstitution(isStatic = true, optional = true)
     public static int indexOf(char[] source, int sourceOffset, int sourceCount,
@@ -62,8 +78,8 @@
         }
         assert sourceCount - fromIndex > 0 && targetCount > 0;
 
-        Pointer sourcePointer = Word.objectToTrackedPointer(source).add(Unsafe.ARRAY_CHAR_BASE_OFFSET).add(totalOffset * Unsafe.ARRAY_CHAR_INDEX_SCALE);
-        Pointer targetPointer = Word.objectToTrackedPointer(target).add(Unsafe.ARRAY_CHAR_BASE_OFFSET).add(targetOffset * Unsafe.ARRAY_CHAR_INDEX_SCALE);
+        Pointer sourcePointer = Word.objectToTrackedPointer(source).add(charArrayBaseOffset(INJECTED)).add(totalOffset * charArrayIndexScale(INJECTED));
+        Pointer targetPointer = Word.objectToTrackedPointer(target).add(charArrayBaseOffset(INJECTED)).add(targetOffset * charArrayIndexScale(INJECTED));
         int result = AMD64StringIndexOfNode.optimizedStringIndexPointer(sourcePointer, sourceCount - fromIndex, targetPointer, targetCount);
         if (result >= 0) {
             return result + totalOffset;
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/FoldTest.java	Fri Feb 16 12:24:38 2018 -0800
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/FoldTest.java	Fri Feb 16 13:49:07 2018 -0800
@@ -79,7 +79,7 @@
 
     @Override
     protected void registerInvocationPlugins(InvocationPlugins invocationPlugins) {
-        InjectionProvider injection = new NodeIntrinsificationProvider(getMetaAccess(), getSnippetReflection(), getProviders().getForeignCalls(), null);
+        InjectionProvider injection = new NodeIntrinsificationProvider(getMetaAccess(), getSnippetReflection(), getProviders().getForeignCalls(), getProviders().getLowerer(), null);
         new PluginFactory_FoldTest().registerPlugins(invocationPlugins, injection);
         BytecodeProvider replacementBytecodeProvider = getSystemClassLoaderBytecodeProvider();
         Registration r = new Registration(invocationPlugins, TestMethod.class, replacementBytecodeProvider);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements.test/src/org/graalvm/compiler/replacements/test/NestedExceptionHandlerTest.java	Fri Feb 16 13:49:07 2018 -0800
@@ -0,0 +1,66 @@
+/*
+ * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.compiler.replacements.test;
+
+import org.graalvm.compiler.api.directives.GraalDirectives;
+import org.graalvm.compiler.core.phases.HighTier;
+import org.graalvm.compiler.core.test.GraalCompilerTest;
+import org.graalvm.compiler.options.OptionValues;
+import org.junit.Test;
+
+public class NestedExceptionHandlerTest extends GraalCompilerTest {
+
+    @BytecodeParserNeverInline(invokeWithException = true)
+    public static void foo() {
+    }
+
+    @BytecodeParserNeverInline(invokeWithException = true)
+    public static void bar() {
+        throw new NegativeArraySizeException();
+    }
+
+    public static int nestedExceptionHandler() {
+        int flag = 0;
+        try {
+            try {
+                try {
+                    foo();
+                } catch (NegativeArraySizeException e) {
+                    flag = -1;
+                }
+                bar();
+            } catch (NullPointerException e) {
+                flag = -2;
+            }
+        } catch (Throwable e) {
+            GraalDirectives.deoptimize();
+        }
+        return flag;
+    }
+
+    @Test
+    public void testNestedExceptionHandler() {
+        test(new OptionValues(getInitialOptions(), HighTier.Options.Inline, false), "nestedExceptionHandler");
+    }
+
+}
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/CachingPEGraphDecoder.java	Fri Feb 16 12:24:38 2018 -0800
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/CachingPEGraphDecoder.java	Fri Feb 16 13:49:07 2018 -0800
@@ -24,6 +24,7 @@
 
 import static org.graalvm.compiler.nodes.graphbuilderconf.IntrinsicContext.CompilationContext.INLINE_AFTER_PARSING;
 
+import org.graalvm.collections.EconomicMap;
 import org.graalvm.compiler.bytecode.BytecodeProvider;
 import org.graalvm.compiler.debug.DebugContext;
 import org.graalvm.compiler.java.GraphBuilderPhase;
@@ -43,7 +44,6 @@
 import org.graalvm.compiler.phases.common.ConvertDeoptimizeToGuardPhase;
 import org.graalvm.compiler.phases.tiers.PhaseContext;
 import org.graalvm.compiler.phases.util.Providers;
-import org.graalvm.util.EconomicMap;
 
 import jdk.vm.ci.code.Architecture;
 import jdk.vm.ci.meta.ResolvedJavaMethod;
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/ConstantStringIndexOfSnippets.java	Fri Feb 16 12:24:38 2018 -0800
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/ConstantStringIndexOfSnippets.java	Fri Feb 16 13:49:07 2018 -0800
@@ -24,10 +24,13 @@
 
 import static org.graalvm.compiler.replacements.SnippetTemplate.DEFAULT_REPLACER;
 
+import org.graalvm.compiler.api.replacements.Fold;
+import org.graalvm.compiler.api.replacements.Fold.InjectedParameter;
 import org.graalvm.compiler.api.replacements.Snippet;
 import org.graalvm.compiler.api.replacements.Snippet.ConstantParameter;
+import org.graalvm.compiler.api.replacements.SnippetReflectionProvider;
+import org.graalvm.compiler.core.common.spi.ArrayOffsetProvider;
 import org.graalvm.compiler.debug.DebugHandlersFactory;
-import org.graalvm.compiler.api.replacements.SnippetReflectionProvider;
 import org.graalvm.compiler.nodes.StructuredGraph;
 import org.graalvm.compiler.nodes.spi.LoweringTool;
 import org.graalvm.compiler.options.OptionValues;
@@ -38,7 +41,7 @@
 import org.graalvm.compiler.replacements.nodes.ExplodeLoopNode;
 
 import jdk.vm.ci.code.TargetDescription;
-import sun.misc.Unsafe;
+import jdk.vm.ci.meta.JavaKind;
 
 public class ConstantStringIndexOfSnippets implements Snippets {
     public static class Templates extends AbstractTemplates {
@@ -91,6 +94,14 @@
         return cache;
     }
 
+    @Fold
+    static int charArrayBaseOffset(@InjectedParameter ArrayOffsetProvider arrayOffsetProvider) {
+        return arrayOffsetProvider.arrayBaseOffset(JavaKind.Char);
+    }
+
+    /** Marker value for the {@link InjectedParameter} injected parameter. */
+    static final ArrayOffsetProvider INJECTED = null;
+
     @Snippet
     public static int indexOfConstant(char[] source, int sourceOffset, int sourceCount,
                     @ConstantParameter char[] target, int targetOffset, int targetCount,
@@ -109,7 +120,7 @@
         int targetCountLess1 = targetCount - 1;
         int sourceEnd = sourceCount - targetCountLess1;
 
-        long base = Unsafe.ARRAY_CHAR_BASE_OFFSET;
+        long base = charArrayBaseOffset(INJECTED);
         int lastChar = UnsafeAccess.UNSAFE.getChar(target, base + targetCountLess1 * 2);
 
         outer_loop: for (long i = sourceOffset + fromIndex; i < sourceEnd;) {
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/DefaultJavaLoweringProvider.java	Fri Feb 16 12:24:38 2018 -0800
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/DefaultJavaLoweringProvider.java	Fri Feb 16 13:49:07 2018 -0800
@@ -921,8 +921,7 @@
 
     public abstract int arrayLengthOffset();
 
-    public abstract int arrayBaseOffset(JavaKind elementKind);
-
+    @Override
     public int arrayScalingFactor(JavaKind elementKind) {
         return target.arch.getPlatformKind(elementKind).getSizeInBytes();
     }
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/InstanceOfSnippetsTemplates.java	Fri Feb 16 12:24:38 2018 -0800
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/InstanceOfSnippetsTemplates.java	Fri Feb 16 13:49:07 2018 -0800
@@ -27,7 +27,7 @@
 import java.util.List;
 
 import org.graalvm.compiler.api.replacements.SnippetReflectionProvider;
-import org.graalvm.compiler.core.common.calc.Condition;
+import org.graalvm.compiler.core.common.calc.CanonicalCondition;
 import org.graalvm.compiler.debug.DebugHandlersFactory;
 import org.graalvm.compiler.graph.Node;
 import org.graalvm.compiler.nodes.ConditionAnchorNode;
@@ -184,7 +184,7 @@
             }
             if (condition == null || (!(condition instanceof CompareNode)) || ((CompareNode) condition).getY() != testValue) {
                 // Re-use previously generated condition if the trueValue for the test is the same
-                condition = createCompareNode(result.graph(), Condition.EQ, result, testValue, null, NodeView.DEFAULT);
+                condition = createCompareNode(result.graph(), CanonicalCondition.EQ, result, testValue, null, NodeView.DEFAULT);
             }
             return condition;
         }
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/NodeIntrinsificationProvider.java	Fri Feb 16 12:24:38 2018 -0800
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/NodeIntrinsificationProvider.java	Fri Feb 16 13:49:07 2018 -0800
@@ -23,6 +23,7 @@
 package org.graalvm.compiler.replacements;
 
 import org.graalvm.compiler.api.replacements.SnippetReflectionProvider;
+import org.graalvm.compiler.core.common.spi.ArrayOffsetProvider;
 import org.graalvm.compiler.core.common.spi.ForeignCallsProvider;
 import org.graalvm.compiler.core.common.type.Stamp;
 import org.graalvm.compiler.core.common.type.StampFactory;
@@ -40,12 +41,15 @@
     private final MetaAccessProvider metaAccess;
     private final SnippetReflectionProvider snippetReflection;
     private final ForeignCallsProvider foreignCalls;
+    private final ArrayOffsetProvider arrayOffsetProvider;
     private final WordTypes wordTypes;
 
-    public NodeIntrinsificationProvider(MetaAccessProvider metaAccess, SnippetReflectionProvider snippetReflection, ForeignCallsProvider foreignCalls, WordTypes wordTypes) {
+    public NodeIntrinsificationProvider(MetaAccessProvider metaAccess, SnippetReflectionProvider snippetReflection, ForeignCallsProvider foreignCalls, ArrayOffsetProvider arrayOffsetProvider,
+                    WordTypes wordTypes) {
         this.metaAccess = metaAccess;
         this.snippetReflection = snippetReflection;
         this.foreignCalls = foreignCalls;
+        this.arrayOffsetProvider = arrayOffsetProvider;
         this.wordTypes = wordTypes;
     }
 
@@ -73,6 +77,8 @@
             return type.cast(foreignCalls);
         } else if (type.equals(SnippetReflectionProvider.class)) {
             return type.cast(snippetReflection);
+        } else if (type.equals(ArrayOffsetProvider.class)) {
+            return type.cast(arrayOffsetProvider);
         } else {
             throw new GraalError("Cannot handle injected argument of type %s.", type.getName());
         }
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/PEGraphDecoder.java	Fri Feb 16 12:24:38 2018 -0800
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/PEGraphDecoder.java	Fri Feb 16 13:49:07 2018 -0800
@@ -32,6 +32,8 @@
 import java.util.List;
 import java.util.Map;
 
+import org.graalvm.collections.EconomicMap;
+import org.graalvm.collections.Equivalence;
 import org.graalvm.compiler.bytecode.Bytecode;
 import org.graalvm.compiler.bytecode.BytecodeProvider;
 import org.graalvm.compiler.core.common.PermanentBailoutException;
@@ -102,8 +104,6 @@
 import org.graalvm.compiler.options.OptionType;
 import org.graalvm.compiler.options.OptionValues;
 import org.graalvm.compiler.phases.common.inlining.InliningUtil;
-import org.graalvm.util.EconomicMap;
-import org.graalvm.util.Equivalence;
 
 import jdk.vm.ci.code.Architecture;
 import jdk.vm.ci.code.BailoutException;
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/ReplacementsImpl.java	Fri Feb 16 12:24:38 2018 -0800
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/ReplacementsImpl.java	Fri Feb 16 13:49:07 2018 -0800
@@ -36,6 +36,8 @@
 import java.util.concurrent.ConcurrentMap;
 import java.util.concurrent.atomic.AtomicInteger;
 
+import org.graalvm.collections.EconomicMap;
+import org.graalvm.collections.Equivalence;
 import org.graalvm.compiler.api.replacements.Fold;
 import org.graalvm.compiler.api.replacements.MethodSubstitution;
 import org.graalvm.compiler.api.replacements.Snippet;
@@ -47,9 +49,9 @@
 import org.graalvm.compiler.core.common.GraalOptions;
 import org.graalvm.compiler.core.common.spi.ConstantFieldProvider;
 import org.graalvm.compiler.debug.DebugCloseable;
-import org.graalvm.compiler.debug.DebugHandlersFactory;
 import org.graalvm.compiler.debug.DebugContext;
 import org.graalvm.compiler.debug.DebugContext.Description;
+import org.graalvm.compiler.debug.DebugHandlersFactory;
 import org.graalvm.compiler.debug.GraalError;
 import org.graalvm.compiler.debug.TimerKey;
 import org.graalvm.compiler.graph.Node;
@@ -81,8 +83,6 @@
 import org.graalvm.compiler.phases.util.Providers;
 import org.graalvm.compiler.word.Word;
 import org.graalvm.compiler.word.WordOperationPlugin;
-import org.graalvm.util.EconomicMap;
-import org.graalvm.util.Equivalence;
 
 import jdk.vm.ci.code.TargetDescription;
 import jdk.vm.ci.meta.ConstantReflectionProvider;
@@ -274,10 +274,13 @@
             if (plugin instanceof MethodSubstitutionPlugin) {
                 MethodSubstitutionPlugin msPlugin = (MethodSubstitutionPlugin) plugin;
                 ResolvedJavaMethod substitute = msPlugin.getSubstitute(metaAccess);
-                StructuredGraph graph = graphs.get(substitute);
+                StructuredGraph graph = UseSnippetGraphCache.getValue(options) ? graphs.get(substitute) : null;
                 if (graph == null) {
                     try (DebugContext debug = openDebugContext("Substitution_", method)) {
                         graph = makeGraph(debug, msPlugin.getBytecodeProvider(), substitute, null, method);
+                        if (!UseSnippetGraphCache.getValue(options)) {
+                            return graph;
+                        }
                         graph.freeze();
                         graphs.putIfAbsent(substitute, graph);
                         graph = graphs.get(substitute);
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/SnippetTemplate.java	Fri Feb 16 12:24:38 2018 -0800
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/SnippetTemplate.java	Fri Feb 16 13:49:07 2018 -0800
@@ -47,11 +47,27 @@
 import java.util.concurrent.atomic.AtomicReference;
 import java.util.function.Predicate;
 
+import jdk.vm.ci.code.TargetDescription;
+import jdk.vm.ci.meta.Constant;
+import jdk.vm.ci.meta.JavaConstant;
+import jdk.vm.ci.meta.JavaKind;
+import jdk.vm.ci.meta.Local;
+import jdk.vm.ci.meta.LocalVariableTable;
+import jdk.vm.ci.meta.MetaAccessProvider;
+import jdk.vm.ci.meta.ResolvedJavaMethod;
+import jdk.vm.ci.meta.ResolvedJavaType;
+import jdk.vm.ci.meta.Signature;
+import jdk.vm.ci.meta.ResolvedJavaMethod.Parameter;
+
+import org.graalvm.collections.EconomicMap;
+import org.graalvm.collections.EconomicSet;
+import org.graalvm.collections.Equivalence;
+import org.graalvm.collections.UnmodifiableEconomicMap;
 import org.graalvm.compiler.api.replacements.Snippet;
+import org.graalvm.compiler.api.replacements.SnippetReflectionProvider;
 import org.graalvm.compiler.api.replacements.Snippet.ConstantParameter;
 import org.graalvm.compiler.api.replacements.Snippet.NonNullParameter;
 import org.graalvm.compiler.api.replacements.Snippet.VarargsParameter;
-import org.graalvm.compiler.api.replacements.SnippetReflectionProvider;
 import org.graalvm.compiler.core.common.GraalOptions;
 import org.graalvm.compiler.core.common.type.Stamp;
 import org.graalvm.compiler.core.common.type.StampFactory;
@@ -59,15 +75,15 @@
 import org.graalvm.compiler.core.common.type.TypeReference;
 import org.graalvm.compiler.debug.CounterKey;
 import org.graalvm.compiler.debug.DebugCloseable;
+import org.graalvm.compiler.debug.DebugContext;
 import org.graalvm.compiler.debug.DebugHandlersFactory;
-import org.graalvm.compiler.debug.DebugContext;
-import org.graalvm.compiler.debug.DebugContext.Description;
 import org.graalvm.compiler.debug.GraalError;
 import org.graalvm.compiler.debug.TimerKey;
-import org.graalvm.compiler.graph.Graph.Mark;
+import org.graalvm.compiler.debug.DebugContext.Description;
 import org.graalvm.compiler.graph.Node;
 import org.graalvm.compiler.graph.NodeClass;
 import org.graalvm.compiler.graph.Position;
+import org.graalvm.compiler.graph.Graph.Mark;
 import org.graalvm.compiler.loop.LoopEx;
 import org.graalvm.compiler.loop.LoopsData;
 import org.graalvm.compiler.loop.phases.LoopTransformations;
@@ -86,15 +102,15 @@
 import org.graalvm.compiler.nodes.NodeView;
 import org.graalvm.compiler.nodes.ParameterNode;
 import org.graalvm.compiler.nodes.PhiNode;
-import org.graalvm.compiler.nodes.PiNode.Placeholder;
-import org.graalvm.compiler.nodes.PiNode.PlaceholderStamp;
 import org.graalvm.compiler.nodes.ReturnNode;
 import org.graalvm.compiler.nodes.StartNode;
 import org.graalvm.compiler.nodes.StateSplit;
 import org.graalvm.compiler.nodes.StructuredGraph;
-import org.graalvm.compiler.nodes.StructuredGraph.GuardsStage;
 import org.graalvm.compiler.nodes.ValueNode;
 import org.graalvm.compiler.nodes.ValueNodeUtil;
+import org.graalvm.compiler.nodes.PiNode.Placeholder;
+import org.graalvm.compiler.nodes.PiNode.PlaceholderStamp;
+import org.graalvm.compiler.nodes.StructuredGraph.GuardsStage;
 import org.graalvm.compiler.nodes.calc.FloatingNode;
 import org.graalvm.compiler.nodes.java.LoadIndexedNode;
 import org.graalvm.compiler.nodes.java.StoreIndexedNode;
@@ -115,35 +131,19 @@
 import org.graalvm.compiler.phases.common.CanonicalizerPhase;
 import org.graalvm.compiler.phases.common.DeadCodeEliminationPhase;
 import org.graalvm.compiler.phases.common.FloatingReadPhase;
-import org.graalvm.compiler.phases.common.FloatingReadPhase.MemoryMapImpl;
 import org.graalvm.compiler.phases.common.GuardLoweringPhase;
 import org.graalvm.compiler.phases.common.LoweringPhase;
 import org.graalvm.compiler.phases.common.RemoveValueProxyPhase;
+import org.graalvm.compiler.phases.common.FloatingReadPhase.MemoryMapImpl;
 import org.graalvm.compiler.phases.common.inlining.InliningUtil;
 import org.graalvm.compiler.phases.tiers.PhaseContext;
 import org.graalvm.compiler.phases.util.Providers;
 import org.graalvm.compiler.replacements.nodes.ExplodeLoopNode;
 import org.graalvm.compiler.replacements.nodes.LoadSnippetVarargParameterNode;
 import org.graalvm.util.CollectionsUtil;
-import org.graalvm.util.EconomicMap;
-import org.graalvm.util.EconomicSet;
-import org.graalvm.util.Equivalence;
-import org.graalvm.util.UnmodifiableEconomicMap;
 import org.graalvm.word.LocationIdentity;
 import org.graalvm.word.WordBase;
 
-import jdk.vm.ci.code.TargetDescription;
-import jdk.vm.ci.meta.Constant;
-import jdk.vm.ci.meta.JavaConstant;
-import jdk.vm.ci.meta.JavaKind;
-import jdk.vm.ci.meta.Local;
-import jdk.vm.ci.meta.LocalVariableTable;
-import jdk.vm.ci.meta.MetaAccessProvider;
-import jdk.vm.ci.meta.ResolvedJavaMethod;
-import jdk.vm.ci.meta.ResolvedJavaMethod.Parameter;
-import jdk.vm.ci.meta.ResolvedJavaType;
-import jdk.vm.ci.meta.Signature;
-
 /**
  * A snippet template is a graph created by parsing a snippet method and then specialized by binding
  * constants to the snippet's {@link ConstantParameter} parameters.
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/StandardGraphBuilderPlugins.java	Fri Feb 16 12:24:38 2018 -0800
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/StandardGraphBuilderPlugins.java	Fri Feb 16 13:49:07 2018 -0800
@@ -37,10 +37,13 @@
 import java.lang.reflect.Field;
 import java.util.Arrays;
 
+import jdk.vm.ci.code.BytecodePosition;
+import jdk.vm.ci.meta.SpeculationLog;
 import org.graalvm.compiler.api.directives.GraalDirectives;
 import org.graalvm.compiler.api.replacements.SnippetReflectionProvider;
 import org.graalvm.compiler.bytecode.BytecodeProvider;
 import org.graalvm.compiler.core.common.calc.Condition;
+import org.graalvm.compiler.core.common.calc.Condition.CanonicalizedCondition;
 import org.graalvm.compiler.core.common.calc.UnsignedMath;
 import org.graalvm.compiler.core.common.type.ObjectStamp;
 import org.graalvm.compiler.core.common.type.Stamp;
@@ -456,23 +459,16 @@
 
         @Override
         public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode x, ValueNode y) {
-            // the mirroring and negation operations get the condition into canonical form
-            boolean mirror = condition.canonicalMirror();
-            boolean negate = condition.canonicalNegate();
+            CanonicalizedCondition canonical = condition.canonicalize();
             StructuredGraph graph = b.getGraph();
 
-            ValueNode lhs = mirror ? y : x;
-            ValueNode rhs = mirror ? x : y;
-
-            ValueNode trueValue = ConstantNode.forBoolean(!negate, graph);
-            ValueNode falseValue = ConstantNode.forBoolean(negate, graph);
+            ValueNode lhs = canonical.mustMirror() ? y : x;
+            ValueNode rhs = canonical.mustMirror() ? x : y;
 
-            Condition cond = mirror ? condition.mirror() : condition;
-            if (negate) {
-                cond = cond.negate();
-            }
+            ValueNode trueValue = ConstantNode.forBoolean(!canonical.mustNegate(), graph);
+            ValueNode falseValue = ConstantNode.forBoolean(canonical.mustNegate(), graph);
 
-            LogicNode compare = CompareNode.createCompareNode(graph, b.getConstantReflection(), b.getMetaAccess(), b.getOptions(), null, cond, lhs, rhs, NodeView.DEFAULT);
+            LogicNode compare = CompareNode.createCompareNode(graph, b.getConstantReflection(), b.getMetaAccess(), b.getOptions(), null, canonical.getCanonicalCondition(), lhs, rhs, NodeView.DEFAULT);
             b.addPush(JavaKind.Boolean, new ConditionalNode(compare, trueValue, falseValue));
             return true;
         }
@@ -728,6 +724,24 @@
         }
     }
 
+    private static final class DirectiveSpeculationReason implements SpeculationLog.SpeculationReason {
+        private final BytecodePosition pos;
+
+        private DirectiveSpeculationReason(BytecodePosition pos) {
+            this.pos = pos;
+        }
+
+        @Override
+        public int hashCode() {
+            return pos.hashCode();
+        }
+
+        @Override
+        public boolean equals(Object obj) {
+            return obj instanceof DirectiveSpeculationReason && ((DirectiveSpeculationReason) obj).pos.equals(this.pos);
+        }
+    }
+
     private static void registerGraalDirectivesPlugins(InvocationPlugins plugins) {
         Registration r = new Registration(plugins, GraalDirectives.class);
         r.register0("deoptimize", new InvocationPlugin() {
@@ -746,6 +760,23 @@
             }
         });
 
+        r.register0("deoptimizeAndInvalidateWithSpeculation", new InvocationPlugin() {
+            @Override
+            public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver) {
+                GraalError.guarantee(b.getGraph().getSpeculationLog() != null, "A speculation log is need to use `deoptimizeAndInvalidateWithSpeculation`");
+                BytecodePosition pos = new BytecodePosition(null, b.getMethod(), b.bci());
+                DirectiveSpeculationReason reason = new DirectiveSpeculationReason(pos);
+                JavaConstant speculation;
+                if (b.getGraph().getSpeculationLog().maySpeculate(reason)) {
+                    speculation = b.getGraph().getSpeculationLog().speculate(reason);
+                } else {
+                    speculation = JavaConstant.defaultForKind(JavaKind.Object);
+                }
+                b.add(new DeoptimizeNode(DeoptimizationAction.InvalidateReprofile, DeoptimizationReason.TransferToInterpreter, speculation));
+                return true;
+            }
+        });
+
         r.register0("inCompiledCode", new InvocationPlugin() {
             @Override
             public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver) {
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/classfile/Classfile.java	Fri Feb 16 12:24:38 2018 -0800
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/classfile/Classfile.java	Fri Feb 16 13:49:07 2018 -0800
@@ -46,8 +46,8 @@
     private final ResolvedJavaType type;
     private final List<ClassfileBytecode> codeAttributes;
 
-    private static final int MAJOR_VERSION_JAVA_MIN = 51;
-    private static final int MAJOR_VERSION_JAVA_MAX = 55;
+    private static final int MAJOR_VERSION_JAVA_MIN = 51; // JDK7
+    private static final int MAJOR_VERSION_JAVA_MAX = 55; // JDK11
     private static final int MAGIC = 0xCAFEBABE;
 
     /**
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/classfile/ClassfileBytecodeProvider.java	Fri Feb 16 12:24:38 2018 -0800
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/classfile/ClassfileBytecodeProvider.java	Fri Feb 16 13:49:07 2018 -0800
@@ -29,12 +29,12 @@
 import java.io.IOException;
 import java.io.InputStream;
 
+import org.graalvm.collections.EconomicMap;
+import org.graalvm.collections.Equivalence;
 import org.graalvm.compiler.api.replacements.SnippetReflectionProvider;
 import org.graalvm.compiler.bytecode.Bytecode;
 import org.graalvm.compiler.bytecode.BytecodeProvider;
 import org.graalvm.compiler.serviceprovider.JDK9Method;
-import org.graalvm.util.EconomicMap;
-import org.graalvm.util.Equivalence;
 
 import jdk.vm.ci.meta.JavaKind;
 import jdk.vm.ci.meta.MetaAccessProvider;
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/classfile/ClassfileConstant.java	Fri Feb 16 12:24:38 2018 -0800
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/classfile/ClassfileConstant.java	Fri Feb 16 13:49:07 2018 -0800
@@ -54,6 +54,7 @@
     public static final byte CONSTANT_NameAndType        = 12;
     public static final byte CONSTANT_MethodHandle       = 15;
     public static final byte CONSTANT_MethodType         = 16;
+    public static final byte CONSTANT_Dynamic            = 17;
     public static final byte CONSTANT_InvokeDynamic      = 18;
     // @formatter:on
 
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/classfile/ClassfileConstantPool.java	Fri Feb 16 12:24:38 2018 -0800
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/classfile/ClassfileConstantPool.java	Fri Feb 16 13:49:07 2018 -0800
@@ -112,6 +112,9 @@
             case ClassfileConstant.CONSTANT_MethodType:
                 skipFully(stream, 2); // descriptor_index
                 return new ClassfileConstant.Unsupported(tag, "CONSTANT_MethodType_info");
+            case ClassfileConstant.CONSTANT_Dynamic:
+                skipFully(stream, 4); // bootstrap_method_attr_index, name_and_type_index
+                return new ClassfileConstant.Unsupported(tag, "CONSTANT_Dynamic_info");
             case ClassfileConstant.CONSTANT_InvokeDynamic:
                 skipFully(stream, 4); // bootstrap_method_attr_index, name_and_type_index
                 return new ClassfileConstant.Unsupported(tag, "CONSTANT_InvokeDynamic_info");
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/nodes/BasicObjectCloneNode.java	Fri Feb 16 12:24:38 2018 -0800
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.replacements/src/org/graalvm/compiler/replacements/nodes/BasicObjectCloneNode.java	Fri Feb 16 13:49:07 2018 -0800
@@ -62,7 +62,7 @@
 
     @Override
     public boolean inferStamp() {
-        return updateStamp(computeStamp(getObject()));
+        return updateStamp(stamp.improveWith(computeStamp(getObject())));
     }
 
     protected Stamp computeStamp(ValueNode object) {
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.serviceprovider.processor/src/org/graalvm/compiler/serviceprovider/processor/ServiceProviderProcessor.java	Fri Feb 16 12:24:38 2018 -0800
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.serviceprovider.processor/src/org/graalvm/compiler/serviceprovider/processor/ServiceProviderProcessor.java	Fri Feb 16 13:49:07 2018 -0800
@@ -37,6 +37,8 @@
 import javax.annotation.processing.SupportedAnnotationTypes;
 import javax.lang.model.SourceVersion;
 import javax.lang.model.element.Element;
+import javax.lang.model.element.ElementKind;
+import javax.lang.model.element.PackageElement;
 import javax.lang.model.element.TypeElement;
 import javax.lang.model.type.MirroredTypeException;
 import javax.lang.model.type.TypeMirror;
@@ -84,8 +86,8 @@
             try {
                 annotation.value();
             } catch (MirroredTypeException ex) {
-                TypeMirror serviceInterface = ex.getTypeMirror();
-                if (verifyAnnotation(serviceInterface, serviceProvider)) {
+                TypeMirror service = ex.getTypeMirror();
+                if (verifyAnnotation(service, serviceProvider)) {
                     if (serviceProvider.getNestingKind().isNested()) {
                         /*
                          * This is a simplifying constraint that means we don't have to process the
@@ -94,7 +96,30 @@
                         String msg = String.format("Service provider class %s must be a top level class", serviceProvider.getSimpleName());
                         processingEnv.getMessager().printMessage(Kind.ERROR, msg, serviceProvider);
                     } else {
-                        serviceProviders.put(serviceProvider, ex.getTypeMirror().toString());
+                        /*
+                         * Since the definition of the service class is not necessarily modifiable,
+                         * we need to support a non-top-level service class and ensure its name is
+                         * properly expressed with '$' separating nesting levels instead of '.'.
+                         */
+                        TypeElement serviceElement = (TypeElement) processingEnv.getTypeUtils().asElement(service);
+                        String serviceName = serviceElement.getSimpleName().toString();
+                        Element enclosing = serviceElement.getEnclosingElement();
+                        while (enclosing != null) {
+                            final ElementKind kind = enclosing.getKind();
+                            if (kind == ElementKind.PACKAGE) {
+                                serviceName = ((PackageElement) enclosing).getQualifiedName().toString() + "." + serviceName;
+                                break;
+                            } else if (kind == ElementKind.CLASS || kind == ElementKind.INTERFACE) {
+                                serviceName = ((TypeElement) enclosing).getSimpleName().toString() + "$" + serviceName;
+                                enclosing = enclosing.getEnclosingElement();
+                            } else {
+                                String msg = String.format("Cannot generate provider descriptor for service class %s as it is not nested in a package, class or interface",
+                                                serviceElement.getQualifiedName());
+                                processingEnv.getMessager().printMessage(Kind.ERROR, msg, serviceProvider);
+                                return;
+                            }
+                        }
+                        serviceProviders.put(serviceProvider, serviceName);
                     }
                 }
             }
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.test/src/org/graalvm/compiler/test/GraalTest.java	Fri Feb 16 12:24:38 2018 -0800
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.test/src/org/graalvm/compiler/test/GraalTest.java	Fri Feb 16 13:49:07 2018 -0800
@@ -24,7 +24,6 @@
 
 import static org.graalvm.compiler.debug.DebugContext.DEFAULT_LOG_STREAM;
 import static org.graalvm.compiler.debug.DebugContext.NO_DESCRIPTION;
-import static org.graalvm.compiler.debug.DebugContext.NO_GLOBAL_METRIC_VALUES;
 
 import java.io.PrintStream;
 import java.io.PrintWriter;
@@ -36,16 +35,17 @@
 import java.util.Collections;
 import java.util.List;
 
-import jdk.vm.ci.meta.ResolvedJavaMethod;
-import org.graalvm.compiler.debug.DebugHandlersFactory;
 import org.graalvm.compiler.debug.DebugContext;
 import org.graalvm.compiler.debug.DebugDumpHandler;
+import org.graalvm.compiler.debug.DebugHandlersFactory;
+import org.graalvm.compiler.debug.GlobalMetrics;
 import org.graalvm.compiler.options.OptionValues;
 import org.junit.After;
 import org.junit.Assert;
 import org.junit.internal.ComparisonCriteria;
 import org.junit.internal.ExactComparisonCriteria;
 
+import jdk.vm.ci.meta.ResolvedJavaMethod;
 import sun.misc.Unsafe;
 
 /**
@@ -398,7 +398,7 @@
 
     /**
      * Gets a {@link DebugContext} object corresponding to {@code options}, creating a new one if
-     * none currently exists.Debug contexts created by this method will have their
+     * none currently exists. Debug contexts created by this method will have their
      * {@link DebugDumpHandler}s closed in {@link #afterTest()}.
      *
      * @param options currently active options
@@ -423,11 +423,21 @@
         } else {
             descr = new DebugContext.Description(method, id == null ? method.getName() : id);
         }
-        DebugContext debug = DebugContext.create(options, descr, NO_GLOBAL_METRIC_VALUES, DEFAULT_LOG_STREAM, getDebugHandlersFactories());
+        DebugContext debug = DebugContext.create(options, descr, globalMetrics, DEFAULT_LOG_STREAM, getDebugHandlersFactories());
         cached.add(debug);
         return debug;
     }
 
+    private static final GlobalMetrics globalMetrics = new GlobalMetrics();
+
+    static {
+        Runtime.getRuntime().addShutdownHook(new Thread("GlobalMetricsPrinter") {
+            @Override
+            public void run() {
+                globalMetrics.print(new OptionValues(OptionValues.newOptionMap()));
+            }
+        });
+    }
     private final ThreadLocal<List<DebugContext>> cachedDebugs = new ThreadLocal<>();
 
     @After
@@ -435,6 +445,7 @@
         List<DebugContext> cached = cachedDebugs.get();
         if (cached != null) {
             for (DebugContext debug : cached) {
+                debug.close();
                 debug.closeDumpHandlers(true);
             }
         }
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.test/src/org/graalvm/compiler/test/SubprocessUtil.java	Fri Feb 16 12:24:38 2018 -0800
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.test/src/org/graalvm/compiler/test/SubprocessUtil.java	Fri Feb 16 13:49:07 2018 -0800
@@ -22,8 +22,6 @@
  */
 package org.graalvm.compiler.test;
 
-import org.graalvm.util.CollectionsUtil;
-
 import java.io.BufferedReader;
 import java.io.File;
 import java.io.IOException;
@@ -37,6 +35,8 @@
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 
+import org.graalvm.util.CollectionsUtil;
+
 /**
  * Utility methods for spawning a VM in a subprocess during unit tests.
  */
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.virtual/src/org/graalvm/compiler/virtual/phases/ea/EffectsBlockState.java	Fri Feb 16 12:24:38 2018 -0800
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.virtual/src/org/graalvm/compiler/virtual/phases/ea/EffectsBlockState.java	Fri Feb 16 13:49:07 2018 -0800
@@ -25,8 +25,8 @@
 import java.util.Iterator;
 import java.util.Map;
 
-import org.graalvm.util.EconomicMap;
-import org.graalvm.util.UnmodifiableMapCursor;
+import org.graalvm.collections.EconomicMap;
+import org.graalvm.collections.UnmodifiableMapCursor;
 
 public abstract class EffectsBlockState<T extends EffectsBlockState<T>> {
 
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.virtual/src/org/graalvm/compiler/virtual/phases/ea/EffectsClosure.java	Fri Feb 16 12:24:38 2018 -0800
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.virtual/src/org/graalvm/compiler/virtual/phases/ea/EffectsClosure.java	Fri Feb 16 13:49:07 2018 -0800
@@ -25,6 +25,9 @@
 import java.util.ArrayList;
 import java.util.List;
 
+import org.graalvm.collections.EconomicMap;
+import org.graalvm.collections.EconomicSet;
+import org.graalvm.collections.Equivalence;
 import org.graalvm.compiler.core.common.cfg.BlockMap;
 import org.graalvm.compiler.core.common.cfg.Loop;
 import org.graalvm.compiler.core.common.type.Stamp;
@@ -59,9 +62,6 @@
 import org.graalvm.compiler.phases.graph.ReentrantBlockIterator;
 import org.graalvm.compiler.phases.graph.ReentrantBlockIterator.BlockIteratorClosure;
 import org.graalvm.compiler.phases.graph.ReentrantBlockIterator.LoopInfo;
-import org.graalvm.util.EconomicMap;
-import org.graalvm.util.EconomicSet;
-import org.graalvm.util.Equivalence;
 import org.graalvm.word.LocationIdentity;
 
 public abstract class EffectsClosure<BlockT extends EffectsBlockState<BlockT>> extends EffectsPhase.Closure<BlockT> {
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.virtual/src/org/graalvm/compiler/virtual/phases/ea/EffectsPhase.java	Fri Feb 16 12:24:38 2018 -0800
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.virtual/src/org/graalvm/compiler/virtual/phases/ea/EffectsPhase.java	Fri Feb 16 13:49:07 2018 -0800
@@ -24,6 +24,7 @@
 
 import static org.graalvm.compiler.phases.common.DeadCodeEliminationPhase.Optionality.Required;
 
+import org.graalvm.collections.EconomicSet;
 import org.graalvm.compiler.core.common.util.CompilationAlarm;
 import org.graalvm.compiler.debug.DebugContext;
 import org.graalvm.compiler.graph.Graph.NodeEventScope;
@@ -39,7 +40,6 @@
 import org.graalvm.compiler.phases.graph.ReentrantBlockIterator;
 import org.graalvm.compiler.phases.schedule.SchedulePhase;
 import org.graalvm.compiler.phases.tiers.PhaseContext;
-import org.graalvm.util.EconomicSet;
 
 public abstract class EffectsPhase<PhaseContextT extends PhaseContext> extends BasePhase<PhaseContextT> {
 
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.virtual/src/org/graalvm/compiler/virtual/phases/ea/PEReadEliminationBlockState.java	Fri Feb 16 12:24:38 2018 -0800
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.virtual/src/org/graalvm/compiler/virtual/phases/ea/PEReadEliminationBlockState.java	Fri Feb 16 13:49:07 2018 -0800
@@ -25,6 +25,8 @@
 import java.util.Iterator;
 import java.util.List;
 
+import org.graalvm.collections.EconomicMap;
+import org.graalvm.collections.Equivalence;
 import org.graalvm.compiler.core.common.type.IntegerStamp;
 import org.graalvm.compiler.core.common.type.Stamp;
 import org.graalvm.compiler.debug.DebugContext;
@@ -35,8 +37,6 @@
 import org.graalvm.compiler.nodes.virtual.VirtualInstanceNode;
 import org.graalvm.compiler.nodes.virtual.VirtualObjectNode;
 import org.graalvm.compiler.options.OptionValues;
-import org.graalvm.util.EconomicMap;
-import org.graalvm.util.Equivalence;
 import org.graalvm.word.LocationIdentity;
 
 import jdk.vm.ci.meta.JavaKind;
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.virtual/src/org/graalvm/compiler/virtual/phases/ea/PEReadEliminationClosure.java	Fri Feb 16 12:24:38 2018 -0800
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.virtual/src/org/graalvm/compiler/virtual/phases/ea/PEReadEliminationClosure.java	Fri Feb 16 13:49:07 2018 -0800
@@ -29,6 +29,11 @@
 import java.util.Iterator;
 import java.util.List;
 
+import org.graalvm.collections.EconomicMap;
+import org.graalvm.collections.EconomicSet;
+import org.graalvm.collections.Equivalence;
+import org.graalvm.collections.MapCursor;
+import org.graalvm.collections.Pair;
 import org.graalvm.compiler.core.common.cfg.Loop;
 import org.graalvm.compiler.core.common.spi.ConstantFieldProvider;
 import org.graalvm.compiler.graph.Node;
@@ -61,11 +66,6 @@
 import org.graalvm.compiler.nodes.virtual.VirtualArrayNode;
 import org.graalvm.compiler.options.OptionValues;
 import org.graalvm.compiler.virtual.phases.ea.PEReadEliminationBlockState.ReadCacheEntry;
-import org.graalvm.util.EconomicMap;
-import org.graalvm.util.EconomicSet;
-import org.graalvm.util.Equivalence;
-import org.graalvm.util.MapCursor;
-import org.graalvm.util.Pair;
 import org.graalvm.word.LocationIdentity;
 
 import jdk.vm.ci.meta.ConstantReflectionProvider;
@@ -186,7 +186,7 @@
                 JavaKind accessKind = load.accessKind();
                 JavaKind componentKind = type.getComponentType().getJavaKind();
                 long offset = load.offset().asJavaConstant().asLong();
-                int index = VirtualArrayNode.entryIndexForOffset(offset, accessKind, type.getComponentType(), Integer.MAX_VALUE);
+                int index = VirtualArrayNode.entryIndexForOffset(tool.getArrayOffsetProvider(), offset, accessKind, type.getComponentType(), Integer.MAX_VALUE);
                 ValueNode object = GraphUtil.unproxify(load.object());
                 LocationIdentity location = NamedLocationIdentity.getArrayLocation(componentKind);
                 ValueNode cachedValue = state.getReadCache(object, location, index, accessKind, this);
@@ -212,7 +212,7 @@
             if (store.offset().isConstant()) {
                 long offset = store.offset().asJavaConstant().asLong();
                 boolean overflowAccess = isOverflowAccess(accessKind, componentKind);
-                int index = overflowAccess ? -1 : VirtualArrayNode.entryIndexForOffset(offset, accessKind, type.getComponentType(), Integer.MAX_VALUE);
+                int index = overflowAccess ? -1 : VirtualArrayNode.entryIndexForOffset(tool.getArrayOffsetProvider(), offset, accessKind, type.getComponentType(), Integer.MAX_VALUE);
                 return processStore(store, store.object(), location, index, accessKind, overflowAccess, store.value(), state, effects);
             } else {
                 processIdentity(state, location);
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.virtual/src/org/graalvm/compiler/virtual/phases/ea/PartialEscapeClosure.java	Fri Feb 16 12:24:38 2018 -0800
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.virtual/src/org/graalvm/compiler/virtual/phases/ea/PartialEscapeClosure.java	Fri Feb 16 13:49:07 2018 -0800
@@ -28,6 +28,9 @@
 import java.util.List;
 import java.util.function.IntUnaryOperator;
 
+import org.graalvm.collections.EconomicMap;
+import org.graalvm.collections.EconomicSet;
+import org.graalvm.collections.Equivalence;
 import org.graalvm.compiler.core.common.GraalOptions;
 import org.graalvm.compiler.core.common.cfg.Loop;
 import org.graalvm.compiler.core.common.spi.ConstantFieldProvider;
@@ -68,9 +71,6 @@
 import org.graalvm.compiler.nodes.virtual.AllocatedObjectNode;
 import org.graalvm.compiler.nodes.virtual.VirtualObjectNode;
 import org.graalvm.compiler.virtual.nodes.VirtualObjectState;
-import org.graalvm.util.EconomicMap;
-import org.graalvm.util.EconomicSet;
-import org.graalvm.util.Equivalence;
 
 import jdk.vm.ci.meta.ConstantReflectionProvider;
 import jdk.vm.ci.meta.JavaConstant;
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.virtual/src/org/graalvm/compiler/virtual/phases/ea/PartialEscapePhase.java	Fri Feb 16 12:24:38 2018 -0800
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.virtual/src/org/graalvm/compiler/virtual/phases/ea/PartialEscapePhase.java	Fri Feb 16 13:49:07 2018 -0800
@@ -25,6 +25,7 @@
 import static org.graalvm.compiler.core.common.GraalOptions.EscapeAnalysisIterations;
 import static org.graalvm.compiler.core.common.GraalOptions.EscapeAnalyzeOnly;
 
+import org.graalvm.collections.EconomicSet;
 import org.graalvm.compiler.graph.Node;
 import org.graalvm.compiler.nodes.StructuredGraph;
 import org.graalvm.compiler.nodes.StructuredGraph.ScheduleResult;
@@ -37,7 +38,6 @@
 import org.graalvm.compiler.phases.BasePhase;
 import org.graalvm.compiler.phases.common.CanonicalizerPhase;
 import org.graalvm.compiler.phases.tiers.PhaseContext;
-import org.graalvm.util.EconomicSet;
 
 public class PartialEscapePhase extends EffectsPhase<PhaseContext> {
 
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.virtual/src/org/graalvm/compiler/virtual/phases/ea/ReadEliminationBlockState.java	Fri Feb 16 12:24:38 2018 -0800
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.virtual/src/org/graalvm/compiler/virtual/phases/ea/ReadEliminationBlockState.java	Fri Feb 16 13:49:07 2018 -0800
@@ -24,10 +24,10 @@
 
 import java.util.Iterator;
 
+import org.graalvm.collections.EconomicMap;
+import org.graalvm.collections.Equivalence;
 import org.graalvm.compiler.nodes.ValueNode;
-import org.graalvm.util.Equivalence;
 import org.graalvm.word.LocationIdentity;
-import org.graalvm.util.EconomicMap;
 
 /**
  * This class maintains a set of known values, identified by base object, locations and offset.
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.virtual/src/org/graalvm/compiler/virtual/phases/ea/ReadEliminationClosure.java	Fri Feb 16 12:24:38 2018 -0800
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.virtual/src/org/graalvm/compiler/virtual/phases/ea/ReadEliminationClosure.java	Fri Feb 16 13:49:07 2018 -0800
@@ -28,7 +28,10 @@
 import java.util.Iterator;
 import java.util.List;
 
-import jdk.vm.ci.meta.ResolvedJavaType;
+import org.graalvm.collections.EconomicMap;
+import org.graalvm.collections.EconomicSet;
+import org.graalvm.collections.Equivalence;
+import org.graalvm.collections.MapCursor;
 import org.graalvm.compiler.core.common.cfg.Loop;
 import org.graalvm.compiler.core.common.type.Stamp;
 import org.graalvm.compiler.graph.Node;
@@ -60,13 +63,10 @@
 import org.graalvm.compiler.virtual.phases.ea.ReadEliminationBlockState.CacheEntry;
 import org.graalvm.compiler.virtual.phases.ea.ReadEliminationBlockState.LoadCacheEntry;
 import org.graalvm.compiler.virtual.phases.ea.ReadEliminationBlockState.UnsafeLoadCacheEntry;
-import org.graalvm.util.EconomicMap;
-import org.graalvm.util.EconomicSet;
-import org.graalvm.util.Equivalence;
-import org.graalvm.util.MapCursor;
 import org.graalvm.word.LocationIdentity;
 
 import jdk.vm.ci.meta.JavaKind;
+import jdk.vm.ci.meta.ResolvedJavaType;
 
 /**
  * This closure initially handled a set of nodes that is disjunct from
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.virtual/src/org/graalvm/compiler/virtual/phases/ea/VirtualUtil.java	Fri Feb 16 12:24:38 2018 -0800
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.virtual/src/org/graalvm/compiler/virtual/phases/ea/VirtualUtil.java	Fri Feb 16 13:49:07 2018 -0800
@@ -26,6 +26,8 @@
 
 import java.util.List;
 
+import org.graalvm.collections.EconomicMap;
+import org.graalvm.collections.Equivalence;
 import org.graalvm.compiler.debug.DebugContext;
 import org.graalvm.compiler.debug.GraalError;
 import org.graalvm.compiler.debug.TTY;
@@ -35,8 +37,6 @@
 import org.graalvm.compiler.nodes.FixedNode;
 import org.graalvm.compiler.nodes.StructuredGraph;
 import org.graalvm.compiler.options.OptionValues;
-import org.graalvm.util.EconomicMap;
-import org.graalvm.util.Equivalence;
 
 import jdk.vm.ci.meta.ResolvedJavaMethod;
 
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.virtual/src/org/graalvm/compiler/virtual/phases/ea/VirtualizerToolImpl.java	Fri Feb 16 12:24:38 2018 -0800
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.virtual/src/org/graalvm/compiler/virtual/phases/ea/VirtualizerToolImpl.java	Fri Feb 16 13:49:07 2018 -0800
@@ -26,6 +26,7 @@
 
 import java.util.List;
 
+import org.graalvm.compiler.core.common.spi.ArrayOffsetProvider;
 import org.graalvm.compiler.core.common.spi.ConstantFieldProvider;
 import org.graalvm.compiler.debug.DebugContext;
 import org.graalvm.compiler.graph.Node;
@@ -108,6 +109,11 @@
         return constantFieldProvider;
     }
 
+    @Override
+    public ArrayOffsetProvider getArrayOffsetProvider() {
+        return loweringProvider;
+    }
+
     public void reset(PartialEscapeBlockState<?> newState, ValueNode newCurrent, FixedNode newPosition, GraphEffectList newEffects) {
         deleted = false;
         state = newState;
@@ -160,7 +166,7 @@
                  * Special case: Allow storing a single long or double value into two consecutive
                  * int slots.
                  */
-                int nextIndex = virtual.entryIndexForOffset(offset + 4, JavaKind.Int);
+                int nextIndex = virtual.entryIndexForOffset(getArrayOffsetProvider(), offset + 4, JavaKind.Int);
                 if (nextIndex != -1) {
                     canVirtualize = true;
                     assert nextIndex == index + 1 : "expected to be sequential";
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.word/src/org/graalvm/compiler/word/WordOperationPlugin.java	Fri Feb 16 12:24:38 2018 -0800
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.compiler.word/src/org/graalvm/compiler/word/WordOperationPlugin.java	Fri Feb 16 13:49:07 2018 -0800
@@ -31,7 +31,9 @@
 
 import org.graalvm.compiler.api.replacements.SnippetReflectionProvider;
 import org.graalvm.compiler.bytecode.BridgeMethodUtils;
+import org.graalvm.compiler.core.common.calc.CanonicalCondition;
 import org.graalvm.compiler.core.common.calc.Condition;
+import org.graalvm.compiler.core.common.calc.Condition.CanonicalizedCondition;
 import org.graalvm.compiler.core.common.type.Stamp;
 import org.graalvm.compiler.core.common.type.StampFactory;
 import org.graalvm.compiler.core.common.type.StampPair;
@@ -409,31 +411,30 @@
     private ValueNode comparisonOp(GraphBuilderContext graph, Condition condition, ValueNode left, ValueNode right) {
         assert left.getStackKind() == wordKind && right.getStackKind() == wordKind;
 
-        // mirroring gets the condition into canonical form
-        boolean mirror = condition.canonicalMirror();
+        CanonicalizedCondition canonical = condition.canonicalize();
 
-        ValueNode a = mirror ? right : left;
-        ValueNode b = mirror ? left : right;
+        ValueNode a = canonical.mustMirror() ? right : left;
+        ValueNode b = canonical.mustMirror() ? left : right;
 
         CompareNode comparison;
-        if (condition == Condition.EQ || condition == Condition.NE) {
+        if (canonical.getCanonicalCondition() == CanonicalCondition.EQ) {
             comparison = new IntegerEqualsNode(a, b);
-        } else if (condition.isUnsigned()) {
+        } else if (canonical.getCanonicalCondition() == CanonicalCondition.BT) {
             comparison = new IntegerBelowNode(a, b);
         } else {
+            assert canonical.getCanonicalCondition() == CanonicalCondition.LT;
             comparison = new IntegerLessThanNode(a, b);
         }
 
         ConstantNode trueValue = graph.add(forInt(1));
         ConstantNode falseValue = graph.add(forInt(0));
 
-        if (condition.canonicalNegate()) {
+        if (canonical.mustNegate()) {
             ConstantNode temp = trueValue;
             trueValue = falseValue;
             falseValue = temp;
         }
-        ConditionalNode materialize = graph.add(new ConditionalNode(graph.add(comparison), trueValue, falseValue));
-        return materialize;
+        return graph.add(new ConditionalNode(graph.add(comparison), trueValue, falseValue));
     }
 
     protected ValueNode readOp(GraphBuilderContext b, JavaKind readKind, AddressNode address, LocationIdentity location, Opcode op) {
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.graphio/src/org/graalvm/graphio/GraphJavadocSnippets.java	Fri Feb 16 13:49:07 2018 -0800
@@ -0,0 +1,285 @@
+/*
+ * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package org.graalvm.graphio;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.nio.channels.FileChannel;
+import java.nio.channels.WritableByteChannel;
+import java.util.Collection;
+import java.util.LinkedHashSet;
+import java.util.Map;
+import java.util.Set;
+
+final class GraphJavadocSnippets {
+    static GraphStructure<AcmeGraph, AcmeNode, AcmeNodeType, AcmePorts> acmeGraphStructure() {
+        // @formatter:off
+        // BEGIN: org.graalvm.graphio.GraphJavadocSnippets#acmeGraphStructure
+        class AcmeGraphStructure implements
+        GraphStructure<AcmeGraph, AcmeNode, AcmeNodeType, AcmePorts> {
+
+            @Override
+            public AcmeGraph graph(AcmeGraph currentGraph, Object obj) {
+                return obj instanceof AcmeGraph ? (AcmeGraph) obj : null;
+            }
+
+            @Override
+            public Iterable<? extends AcmeNode> nodes(AcmeGraph graph) {
+                return graph.allNodes();
+            }
+
+            @Override
+            public int nodesCount(AcmeGraph graph) {
+                return graph.allNodes().size();
+            }
+
+            @Override
+            public int nodeId(AcmeNode node) {
+                return node.id;
+            }
+
+            @Override
+            public boolean nodeHasPredecessor(AcmeNode node) {
+                return node.id > 0;
+            }
+
+            @Override
+            public void nodeProperties(
+                AcmeGraph graph, AcmeNode node, Map<String, ? super Object> properties
+            ) {
+                properties.put("id", node.id);
+            }
+
+            @Override
+            public AcmeNodeType nodeClass(Object obj) {
+                return obj instanceof AcmeNodeType ? (AcmeNodeType) obj : null;
+            }
+
+            @Override
+            public AcmeNode node(Object obj) {
+                return obj instanceof AcmeNode ? (AcmeNode) obj : null;
+            }
+
+            @Override
+            public AcmeNodeType classForNode(AcmeNode node) {
+                // we have only one type of nodes
+                return AcmeNodeType.STANDARD;
+            }
+
+
+            @Override
+            public String nameTemplate(AcmeNodeType nodeClass) {
+                return "Acme ({p#id})";
+            }
+
+            @Override
+            public Object nodeClassType(AcmeNodeType nodeClass) {
+                return nodeClass.getClass();
+            }
+
+            @Override
+            public AcmePorts portInputs(AcmeNodeType nodeClass) {
+                return AcmePorts.INPUT;
+            }
+
+            @Override
+            public AcmePorts portOutputs(AcmeNodeType nodeClass) {
+                return AcmePorts.OUTPUT;
+            }
+
+            @Override
+            public int portSize(AcmePorts port) {
+                return port == AcmePorts.OUTPUT ? 1 : 0;
+            }
+
+            @Override
+            public boolean edgeDirect(AcmePorts port, int index) {
+                return false;
+            }
+
+            @Override
+            public String edgeName(AcmePorts port, int index) {
+                return port.name();
+            }
+
+            @Override
+            public Object edgeType(AcmePorts port, int index) {
+                return port;
+            }
+
+            @Override
+            public Collection<? extends AcmeNode> edgeNodes(
+                AcmeGraph graph, AcmeNode node, AcmePorts port, int index
+            ) {
+                if (port == AcmePorts.OUTPUT) {
+                    return node.outgoing.targets;
+                }
+                return null;
+            }
+        }
+
+        // END: org.graalvm.graphio.GraphJavadocSnippets#acmeGraphStructure
+
+        return new AcmeGraphStructure();
+    }
+
+    // BEGIN: org.graalvm.graphio.GraphJavadocSnippets#buildOutput
+    static GraphOutput<AcmeGraph, ?> buildOutput(WritableByteChannel channel)
+    throws IOException {
+        return GraphOutput.newBuilder(acmeGraphStructure()).
+            // use the latest version; currently 5.0
+            protocolVersion(5, 0).
+            build(channel);
+    }
+    // END: org.graalvm.graphio.GraphJavadocSnippets#buildOutput
+
+    // BEGIN: org.graalvm.graphio.GraphJavadocSnippets#buildAll
+    static GraphOutput<AcmeGraph, ?> buildAll(WritableByteChannel channel)
+    throws IOException {
+        GraphBlocks<AcmeGraph, AcmeBlocks, AcmeNode> graphBlocks = acmeBlocks();
+        GraphElements<AcmeMethod, AcmeField,
+            AcmeSignature, AcmeCodePosition> graphElements = acmeElements();
+        GraphTypes graphTypes = acmeTypes();
+
+        return GraphOutput.newBuilder(acmeGraphStructure()).
+            protocolVersion(5, 0).
+            blocks(graphBlocks).
+            elements(graphElements).
+            types(graphTypes).
+            build(channel);
+    }
+    // END: org.graalvm.graphio.GraphJavadocSnippets#buildAll
+
+    private static GraphTypes acmeTypes() {
+        GraphTypes graphTypes = null;
+        // in real world don't return null
+        return graphTypes;
+    }
+
+    private static GraphElements<AcmeMethod, AcmeField, AcmeSignature, AcmeCodePosition> acmeElements() {
+        GraphElements<AcmeMethod, AcmeField, AcmeSignature, AcmeCodePosition> graphElements = null;
+        // in real world don't return null
+        return graphElements;
+    }
+
+    private static GraphBlocks<AcmeGraph, AcmeBlocks, AcmeNode> acmeBlocks() {
+        GraphBlocks<AcmeGraph, AcmeBlocks, AcmeNode> graphBlocks = null;
+        // in real world don't return null
+        return graphBlocks;
+    }
+
+    private static class AcmeGraph {
+        final AcmeNode root;
+
+        AcmeGraph(AcmeNode root) {
+            this.root = root;
+        }
+
+        Set<AcmeNode> allNodes() {
+            return allNodes(root, new LinkedHashSet<>());
+        }
+
+        private static Set<AcmeNode> allNodes(AcmeNode node, Set<AcmeNode> collectTo) {
+            if (collectTo.add(node)) {
+                for (AcmeNode target : node.outgoing.targets) {
+                    allNodes(target, collectTo);
+                }
+            }
+            return collectTo;
+        }
+    }
+
+    private static class AcmeNode {
+        final int id;
+        final AcmeEdges outgoing;
+
+        AcmeNode(int id) {
+            this.id = id;
+            this.outgoing = new AcmeEdges();
+        }
+
+        void linkTo(AcmeNode target) {
+            outgoing.targets.add(target);
+        }
+    }
+
+    private enum AcmeNodeType {
+        STANDARD
+    }
+
+    private enum AcmePorts {
+        INPUT,
+        OUTPUT;
+    }
+
+    private static class AcmeEdges {
+        final Set<AcmeNode> targets;
+
+        AcmeEdges() {
+            this.targets = new LinkedHashSet<>();
+        }
+    }
+
+    private static class AcmeBlocks {
+    }
+
+    private static class AcmeMethod {
+    }
+
+    private static class AcmeField {
+    }
+
+    private static class AcmeSignature {
+    }
+
+    private static class AcmeCodePosition {
+    }
+
+    // BEGIN: org.graalvm.graphio.GraphJavadocSnippets#dump
+    static void dump(File toFile) throws IOException {
+        try (
+            FileChannel ch = new FileOutputStream(toFile).getChannel();
+            GraphOutput<AcmeGraph, ?> output = buildOutput(ch);
+        ) {
+            AcmeNode root = new AcmeNode(0);
+            AcmeNode n1 = new AcmeNode(1);
+            AcmeNode n2 = new AcmeNode(2);
+            AcmeNode n3 = new AcmeNode(3);
+
+            root.linkTo(n1);
+            root.linkTo(n2);
+            n1.linkTo(n3);
+            n2.linkTo(n3);
+
+            AcmeGraph diamondGraph = new AcmeGraph(root);
+
+            output.beginGroup(diamondGraph, "Diamond", "dia", null, 0, null);
+            output.print(diamondGraph, null, 0, "Diamond graph #%d", 1);
+            output.endGroup();
+        }
+    }
+    // END: org.graalvm.graphio.GraphJavadocSnippets#dump
+
+}
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.graphio/src/org/graalvm/graphio/GraphSnippets.java	Fri Feb 16 12:24:38 2018 -0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,285 +0,0 @@
-/*
- * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-
-package org.graalvm.graphio;
-
-import java.io.File;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.nio.channels.FileChannel;
-import java.nio.channels.WritableByteChannel;
-import java.util.Collection;
-import java.util.LinkedHashSet;
-import java.util.Map;
-import java.util.Set;
-
-final class GraphSnippets {
-    static GraphStructure<AcmeGraph, AcmeNode, AcmeNodeType, AcmePorts> acmeGraphStructure() {
-        // @formatter:off
-        // BEGIN: org.graalvm.graphio.GraphSnippets#acmeGraphStructure
-        class AcmeGraphStructure implements
-        GraphStructure<AcmeGraph, AcmeNode, AcmeNodeType, AcmePorts> {
-
-            @Override
-            public AcmeGraph graph(AcmeGraph currentGraph, Object obj) {
-                return obj instanceof AcmeGraph ? (AcmeGraph) obj : null;
-            }
-
-            @Override
-            public Iterable<? extends AcmeNode> nodes(AcmeGraph graph) {
-                return graph.allNodes();
-            }
-
-            @Override
-            public int nodesCount(AcmeGraph graph) {
-                return graph.allNodes().size();
-            }
-
-            @Override
-            public int nodeId(AcmeNode node) {
-                return node.id;
-            }
-
-            @Override
-            public boolean nodeHasPredecessor(AcmeNode node) {
-                return node.id > 0;
-            }
-
-            @Override
-            public void nodeProperties(
-                AcmeGraph graph, AcmeNode node, Map<String, ? super Object> properties
-            ) {
-                properties.put("id", node.id);
-            }
-
-            @Override
-            public AcmeNodeType nodeClass(Object obj) {
-                return obj instanceof AcmeNodeType ? (AcmeNodeType) obj : null;
-            }
-
-            @Override
-            public AcmeNode node(Object obj) {
-                return obj instanceof AcmeNode ? (AcmeNode) obj : null;
-            }
-
-            @Override
-            public AcmeNodeType classForNode(AcmeNode node) {
-                // we have only one type of nodes
-                return AcmeNodeType.STANDARD;
-            }
-
-
-            @Override
-            public String nameTemplate(AcmeNodeType nodeClass) {
-                return "Acme ({p#id})";
-            }
-
-            @Override
-            public Object nodeClassType(AcmeNodeType nodeClass) {
-                return nodeClass.getClass();
-            }
-
-            @Override
-            public AcmePorts portInputs(AcmeNodeType nodeClass) {
-                return AcmePorts.INPUT;
-            }
-
-            @Override
-            public AcmePorts portOutputs(AcmeNodeType nodeClass) {
-                return AcmePorts.OUTPUT;
-            }
-
-            @Override
-            public int portSize(AcmePorts port) {
-                return port == AcmePorts.OUTPUT ? 1 : 0;
-            }
-
-            @Override
-            public boolean edgeDirect(AcmePorts port, int index) {
-                return false;
-            }
-
-            @Override
-            public String edgeName(AcmePorts port, int index) {
-                return port.name();
-            }
-
-            @Override
-            public Object edgeType(AcmePorts port, int index) {
-                return port;
-            }
-
-            @Override
-            public Collection<? extends AcmeNode> edgeNodes(
-                AcmeGraph graph, AcmeNode node, AcmePorts port, int index
-            ) {
-                if (port == AcmePorts.OUTPUT) {
-                    return node.outgoing.targets;
-                }
-                return null;
-            }
-        }
-
-        // END: org.graalvm.graphio.GraphSnippets#acmeGraphStructure
-
-        return new AcmeGraphStructure();
-    }
-
-    // BEGIN: org.graalvm.graphio.GraphSnippets#buildOutput
-    static GraphOutput<AcmeGraph, ?> buildOutput(WritableByteChannel channel)
-    throws IOException {
-        return GraphOutput.newBuilder(acmeGraphStructure()).
-            // use the latest version; currently 5.0
-            protocolVersion(5, 0).
-            build(channel);
-    }
-    // END: org.graalvm.graphio.GraphSnippets#buildOutput
-
-    // BEGIN: org.graalvm.graphio.GraphSnippets#buildAll
-    static GraphOutput<AcmeGraph, ?> buildAll(WritableByteChannel channel)
-    throws IOException {
-        GraphBlocks<AcmeGraph, AcmeBlocks, AcmeNode> graphBlocks = acmeBlocks();
-        GraphElements<AcmeMethod, AcmeField,
-            AcmeSignature, AcmeCodePosition> graphElements = acmeElements();
-        GraphTypes graphTypes = acmeTypes();
-
-        return GraphOutput.newBuilder(acmeGraphStructure()).
-            protocolVersion(5, 0).
-            blocks(graphBlocks).
-            elements(graphElements).
-            types(graphTypes).
-            build(channel);
-    }
-    // END: org.graalvm.graphio.GraphSnippets#buildAll
-
-    private static GraphTypes acmeTypes() {
-        GraphTypes graphTypes = null;
-        // in real world don't return null
-        return graphTypes;
-    }
-
-    private static GraphElements<AcmeMethod, AcmeField, AcmeSignature, AcmeCodePosition> acmeElements() {
-        GraphElements<AcmeMethod, AcmeField, AcmeSignature, AcmeCodePosition> graphElements = null;
-        // in real world don't return null
-        return graphElements;
-    }
-
-    private static GraphBlocks<AcmeGraph, AcmeBlocks, AcmeNode> acmeBlocks() {
-        GraphBlocks<AcmeGraph, AcmeBlocks, AcmeNode> graphBlocks = null;
-        // in real world don't return null
-        return graphBlocks;
-    }
-
-    private static class AcmeGraph {
-        final AcmeNode root;
-
-        AcmeGraph(AcmeNode root) {
-            this.root = root;
-        }
-
-        Set<AcmeNode> allNodes() {
-            return allNodes(root, new LinkedHashSet<>());
-        }
-
-        private static Set<AcmeNode> allNodes(AcmeNode node, Set<AcmeNode> collectTo) {
-            if (collectTo.add(node)) {
-                for (AcmeNode target : node.outgoing.targets) {
-                    allNodes(target, collectTo);
-                }
-            }
-            return collectTo;
-        }
-    }
-
-    private static class AcmeNode {
-        final int id;
-        final AcmeEdges outgoing;
-
-        AcmeNode(int id) {
-            this.id = id;
-            this.outgoing = new AcmeEdges();
-        }
-
-        void linkTo(AcmeNode target) {
-            outgoing.targets.add(target);
-        }
-    }
-
-    private enum AcmeNodeType {
-        STANDARD
-    }
-
-    private enum AcmePorts {
-        INPUT,
-        OUTPUT;
-    }
-
-    private static class AcmeEdges {
-        final Set<AcmeNode> targets;
-
-        AcmeEdges() {
-            this.targets = new LinkedHashSet<>();
-        }
-    }
-
-    private static class AcmeBlocks {
-    }
-
-    private static class AcmeMethod {
-    }
-
-    private static class AcmeField {
-    }
-
-    private static class AcmeSignature {
-    }
-
-    private static class AcmeCodePosition {
-    }
-
-    // BEGIN: org.graalvm.graphio.GraphSnippets#dump
-    static void dump(File toFile) throws IOException {
-        try (
-            FileChannel ch = new FileOutputStream(toFile).getChannel();
-            GraphOutput<AcmeGraph, ?> output = buildOutput(ch);
-        ) {
-            AcmeNode root = new AcmeNode(0);
-            AcmeNode n1 = new AcmeNode(1);
-            AcmeNode n2 = new AcmeNode(2);
-            AcmeNode n3 = new AcmeNode(3);
-
-            root.linkTo(n1);
-            root.linkTo(n2);
-            n1.linkTo(n3);
-            n2.linkTo(n3);
-
-            AcmeGraph diamondGraph = new AcmeGraph(root);
-
-            output.beginGroup(diamondGraph, "Diamond", "dia", null, 0, null);
-            output.print(diamondGraph, null, 0, "Diamond graph #%d", 1);
-            output.endGroup();
-        }
-    }
-    // END: org.graalvm.graphio.GraphSnippets#dump
-
-}
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.graphio/src/org/graalvm/graphio/package-info.java	Fri Feb 16 12:24:38 2018 -0800
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.graphio/src/org/graalvm/graphio/package-info.java	Fri Feb 16 13:49:07 2018 -0800
@@ -24,13 +24,12 @@
 
 /**
  * Send your graphs to <b>IGV</b> via a socket or a file. This package allows one to easily encode
- * any graph-like data structure and send it for visualization to
- * <em>OracleLab's Ideal Graph Visualizer</em> tool. Assuming you already have your own data
- * structure that contains <b>nodes</b> and <b>edges</b> among them, creating a
- * {@link org.graalvm.graphio.GraphOutput} specialized for your data is a matter of implementing a
- * single interface:
+ * any graph-like data structure and send it for visualization to <em>OracleLab's Ideal Graph
+ * Visualizer</em> tool. Assuming you already have your own data structure that contains
+ * <b>nodes</b> and <b>edges</b> among them, creating a {@link org.graalvm.graphio.GraphOutput}
+ * specialized for your data is a matter of implementing a single interface:
  *
- * {@link org.graalvm.graphio.GraphSnippets#acmeGraphStructure}
+ * {@link org.graalvm.graphio.GraphJavadocSnippets#acmeGraphStructure}
  *
  * The {@link org.graalvm.graphio.GraphStructure} interface defines the set of operations that are
  * needed by the <em>graph protocol</em> to encode a graph into the <b>IGV</b> expected format. The
@@ -43,7 +42,7 @@
  * {@link org.graalvm.graphio.GraphOutput}. To do so use the associated
  * {@link org.graalvm.graphio.GraphOutput.Builder builder} just like shown in the following method:
  *
- * {@link org.graalvm.graphio.GraphSnippets#buildOutput}
+ * {@link org.graalvm.graphio.GraphJavadocSnippets#buildOutput}
  *
  * Now you are ready to dump your graph into <b>IGV</b>. Where to obtain the right channel? One
  * option is to create a {@link java.nio.channels.FileChannel} and dump the data into a file
@@ -51,7 +50,7 @@
  * <code>4445</code> (the default port <b>IGV</b> listens to) and dump the data there. Here is an
  * example:
  *
- * {@link org.graalvm.graphio.GraphSnippets#dump}
+ * {@link org.graalvm.graphio.GraphJavadocSnippets#dump}
  *
  * Call the {@code dump} method with pointer to file {@code diamond.bgv} and then you can open the
  * file in <b>IGV</b>. The result will look like this:
@@ -75,7 +74,7 @@
  * {@link org.graalvm.graphio.GraphOutput.Builder} instance methods, which may, but need not be
  * called at all. Here is an example:
  *
- * {@link org.graalvm.graphio.GraphSnippets#buildAll}
+ * {@link org.graalvm.graphio.GraphJavadocSnippets#buildAll}
  *
  * All these interfaces follow the
  * <a href="http://wiki.apidesign.org/wiki/Singletonizer">singletonizer</a> API pattern again - e.g.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.util.test/src/org/graalvm/util/test/CollectionSizeTest.java	Fri Feb 16 13:49:07 2018 -0800
@@ -0,0 +1,95 @@
+/*
+ * Copyright (c) 2017, 2017, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.util.test;
+
+import static org.junit.Assert.assertEquals;
+
+import org.graalvm.collections.EconomicMap;
+import org.graalvm.collections.Equivalence;
+import org.graalvm.compiler.test.GraalTest;
+import org.graalvm.util.ObjectSizeEstimate;
+import org.junit.Assume;
+import org.junit.Test;
+
+public class CollectionSizeTest {
+
+    /**
+     * Tests the memory size of an empty map and a map with only one or two entries.
+     */
+    @Test
+    public void testSize() {
+        Assume.assumeTrue("Not working in JDK9 due to module visibility.", GraalTest.Java8OrEarlier);
+        EconomicMap<Object, Object> map = EconomicMap.create(Equivalence.IDENTITY);
+        assertEquals(49, ObjectSizeEstimate.forObject(map).getTotalBytes());
+
+        Integer value = 1;
+        map.put(value, value);
+        assertEquals(153, ObjectSizeEstimate.forObject(map).getTotalBytes());
+
+        Integer secondValue = 2;
+        map.put(secondValue, secondValue);
+        assertEquals(153 + 20, ObjectSizeEstimate.forObject(map).getTotalBytes());
+    }
+
+    /**
+     * Tests whether the map actually compresses the entries array when a large number of entries
+     * are deleted.
+     */
+    @Test
+    public void testCompress() {
+        Assume.assumeTrue("Not working in JDK9 due to module visibility.", GraalTest.Java8OrEarlier);
+        EconomicMap<Object, Object> map = EconomicMap.create();
+
+        // Measuring size of map with one entry.
+        Object firstValue = 0;
+        map.put(firstValue, firstValue);
+        ObjectSizeEstimate afterFirstValue = ObjectSizeEstimate.forObject(map);
+
+        // Add 999 more entries.
+        for (int i = 1; i < 1000; ++i) {
+            Object value = i;
+            map.put(value, value);
+        }
+        ObjectSizeEstimate beforeRemove = ObjectSizeEstimate.forObject(map);
+
+        // Remove 999 first entries.
+        for (int i = 0; i < 999; ++i) {
+            map.removeKey(i);
+        }
+        ObjectSizeEstimate afterRemove = ObjectSizeEstimate.forObject(map);
+
+        // Check that size is same size as with one entry.
+        assertEquals(afterFirstValue, afterRemove);
+
+        // Add 999 new entries.
+        for (int i = 0; i < 999; ++i) {
+            Object value = i;
+            map.put(value, value);
+        }
+        ObjectSizeEstimate afterAdd = ObjectSizeEstimate.forObject(map);
+
+        // Check that entries array is same size again.
+        assertEquals(beforeRemove.getPointerCount(), afterAdd.getPointerCount());
+    }
+
+}
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.util.test/src/org/graalvm/util/test/CollectionTest.java	Fri Feb 16 12:24:38 2018 -0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,536 +0,0 @@
-/*
- * Copyright (c) 2017, 2017, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package org.graalvm.util.test;
-
-import static org.junit.Assert.assertEquals;
-
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.Iterator;
-import java.util.LinkedHashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.NoSuchElementException;
-import java.util.Objects;
-import java.util.Random;
-import java.util.function.BiFunction;
-
-import org.graalvm.util.CollectionsUtil;
-import org.graalvm.util.EconomicMap;
-import org.graalvm.util.EconomicSet;
-import org.graalvm.util.Equivalence;
-import org.graalvm.util.MapCursor;
-import org.graalvm.util.ObjectSizeEstimate;
-import org.graalvm.util.UnmodifiableMapCursor;
-import org.junit.Assert;
-import org.junit.Test;
-
-public class CollectionTest {
-
-    /**
-     * Tests the memory size of an empty map and a map with only one or two entries.
-     */
-    @Test
-    public void testSize() {
-        EconomicMap<Object, Object> map = EconomicMap.create(Equivalence.IDENTITY);
-        assertEquals(48, ObjectSizeEstimate.forObject(map).getTotalBytes());
-
-        Integer value = 1;
-        map.put(value, value);
-        assertEquals(152, ObjectSizeEstimate.forObject(map).getTotalBytes());
-
-        Integer secondValue = 2;
-        map.put(secondValue, secondValue);
-        assertEquals(152 + 20, ObjectSizeEstimate.forObject(map).getTotalBytes());
-    }
-
-    /**
-     * Tests whether the map actually compresses the entries array when a large number of entries
-     * are deleted.
-     */
-    @Test
-    public void testCompress() {
-        EconomicMap<Object, Object> map = EconomicMap.create();
-
-        // Measuring size of map with one entry.
-        Object firstValue = 0;
-        map.put(firstValue, firstValue);
-        ObjectSizeEstimate afterFirstValue = ObjectSizeEstimate.forObject(map);
-
-        // Add 999 more entries.
-        for (int i = 1; i < 1000; ++i) {
-            Object value = i;
-            map.put(value, value);
-        }
-        ObjectSizeEstimate beforeRemove = ObjectSizeEstimate.forObject(map);
-
-        // Remove 999 first entries.
-        for (int i = 0; i < 999; ++i) {
-            map.removeKey(i);
-        }
-        ObjectSizeEstimate afterRemove = ObjectSizeEstimate.forObject(map);
-
-        // Check that size is same size as with one entry.
-        assertEquals(afterFirstValue, afterRemove);
-
-        // Add 999 new entries.
-        for (int i = 0; i < 999; ++i) {
-            Object value = i;
-            map.put(value, value);
-        }
-        ObjectSizeEstimate afterAdd = ObjectSizeEstimate.forObject(map);
-
-        // Check that entries array is same size again.
-        assertEquals(beforeRemove.getPointerCount(), afterAdd.getPointerCount());
-    }
-
-    private static int[] createRandomRange(Random random, int count) {
-        int[] result = new int[count];
-        for (int i = 0; i < count; ++i) {
-            int range = random.nextInt(14);
-            if (range == 0 || range > 10) {
-                range = Integer.MAX_VALUE;
-            } else if (range == 10) {
-                range = 100;
-            }
-            result[i] = range;
-        }
-        return result;
-    }
-
-    private static final class BadHashClass {
-        private int value;
-
-        BadHashClass(int randomInt) {
-            this.value = randomInt;
-        }
-
-        @Override
-        public int hashCode() {
-            return 0;
-        }
-
-        @Override
-        public boolean equals(Object other) {
-            if (other instanceof BadHashClass) {
-                BadHashClass badHashClass = (BadHashClass) other;
-                return badHashClass.value == value;
-            }
-            return false;
-        }
-    }
-
-    interface MapAction {
-        Object perform(EconomicMap<Object, Object> map, int randomInt);
-    }
-
-    static final Object EXISTING_VALUE = new Object();
-
-    static final MapAction[] INCREASE_ACTIONS = new MapAction[]{
-                    (map, randomInt) -> map.put(randomInt, "value"),
-                    (map, randomInt) -> map.get(randomInt)
-    };
-
-    static final MapAction[] ACTIONS = new MapAction[]{
-                    (map, randomInt) -> map.removeKey(randomInt),
-                    (map, randomInt) -> map.put(randomInt, "value"),
-                    (map, randomInt) -> map.put(randomInt, null),
-                    (map, randomInt) -> map.put(EXISTING_VALUE, randomInt),
-                    (map, randomInt) -> {
-                        if (randomInt == 0) {
-                            map.clear();
-                        }
-                        return map.isEmpty();
-                    },
-                    (map, randomInt) -> map.containsKey(randomInt),
-                    (map, randomInt) -> map.get(randomInt),
-                    (map, randomInt) -> map.put(new BadHashClass(randomInt), "unique"),
-                    (map, randomInt) -> {
-                        if (randomInt == 0) {
-                            map.replaceAll((key, value) -> Objects.toString(value) + "!");
-                        }
-                        return map.isEmpty();
-                    }
-
-    };
-
-    @Test
-    public void testVeryLarge() {
-        EconomicMap<Object, Object> map = EconomicMap.create();
-        EconomicMap<Object, Object> referenceMap = createDebugMap();
-
-        Random random = new Random(0);
-        for (int i = 0; i < 200000; ++i) {
-            for (int j = 0; j < INCREASE_ACTIONS.length; ++j) {
-                int nextInt = random.nextInt(10000000);
-                MapAction action = INCREASE_ACTIONS[j];
-                Object result = action.perform(map, nextInt);
-                Object referenceResult = action.perform(referenceMap, nextInt);
-                Assert.assertEquals(result, referenceResult);
-            }
-        }
-    }
-
-    /**
-     * Tests a sequence of random operations on the map.
-     */
-    @Test
-    public void testAddRemove() {
-        EconomicMap<Object, Object> map = EconomicMap.create();
-        EconomicMap<Object, Object> referenceMap = createDebugMap();
-
-        for (int seed = 0; seed < 10; ++seed) {
-            Random random = new Random(seed);
-            int[] ranges = createRandomRange(random, ACTIONS.length);
-            int value = random.nextInt(10000);
-            for (int i = 0; i < value; ++i) {
-                for (int j = 0; j < ACTIONS.length; ++j) {
-                    if (random.nextInt(ranges[j]) == 0) {
-                        int nextInt = random.nextInt(100);
-                        MapAction action = ACTIONS[j];
-                        Object result = action.perform(map, nextInt);
-                        Object referenceResult = action.perform(referenceMap, nextInt);
-                        Assert.assertEquals(result, referenceResult);
-                        if (j % 100 == 0) {
-                            checkEquality(map, referenceMap);
-                        }
-                    }
-                }
-
-                if (random.nextInt(20) == 0) {
-                    removeElement(random.nextInt(100), map, referenceMap);
-                }
-            }
-        }
-    }
-
-    private static void removeElement(int index, EconomicMap<?, ?> map, EconomicMap<?, ?> referenceMap) {
-        Assert.assertEquals(referenceMap.size(), map.size());
-        MapCursor<?, ?> cursor = map.getEntries();
-        MapCursor<?, ?> referenceCursor = referenceMap.getEntries();
-        int z = 0;
-        while (cursor.advance()) {
-            Assert.assertTrue(referenceCursor.advance());
-            Assert.assertEquals(referenceCursor.getKey(), cursor.getKey());
-            Assert.assertEquals(referenceCursor.getValue(), cursor.getValue());
-            if (index == z) {
-                cursor.remove();
-                referenceCursor.remove();
-            }
-            ++z;
-        }
-
-        Assert.assertFalse(referenceCursor.advance());
-    }
-
-    private static void checkEquality(EconomicMap<?, ?> map, EconomicMap<?, ?> referenceMap) {
-        Assert.assertEquals(referenceMap.size(), map.size());
-
-        // Check entries.
-        UnmodifiableMapCursor<?, ?> cursor = map.getEntries();
-        UnmodifiableMapCursor<?, ?> referenceCursor = referenceMap.getEntries();
-        while (cursor.advance()) {
-            Assert.assertTrue(referenceCursor.advance());
-            Assert.assertEquals(referenceCursor.getKey(), cursor.getKey());
-            Assert.assertEquals(referenceCursor.getValue(), cursor.getValue());
-        }
-
-        // Check keys.
-        Iterator<?> iterator = map.getKeys().iterator();
-        Iterator<?> referenceIterator = referenceMap.getKeys().iterator();
-        while (iterator.hasNext()) {
-            Assert.assertTrue(referenceIterator.hasNext());
-            Assert.assertEquals(iterator.next(), referenceIterator.next());
-        }
-
-        // Check values.
-        iterator = map.getValues().iterator();
-        referenceIterator = referenceMap.getValues().iterator();
-        while (iterator.hasNext()) {
-            Assert.assertTrue(referenceIterator.hasNext());
-            Assert.assertEquals(iterator.next(), referenceIterator.next());
-        }
-        Assert.assertFalse(referenceIterator.hasNext());
-    }
-
-    public static <K, V> EconomicMap<K, V> createDebugMap() {
-        final LinkedHashMap<K, V> linkedMap = new LinkedHashMap<>();
-        final EconomicMap<K, V> sparseMap = EconomicMap.create();
-        return new EconomicMap<K, V>() {
-
-            @Override
-            public V get(K key) {
-                V result = linkedMap.get(key);
-                V sparseResult = sparseMap.get(key);
-                assert Objects.equals(result, sparseResult);
-                return result;
-            }
-
-            @Override
-            public V put(K key, V value) {
-                V result = linkedMap.put(key, value);
-                assert Objects.equals(result, sparseMap.put(key, value));
-                return result;
-            }
-
-            @Override
-            public int size() {
-                int result = linkedMap.size();
-                assert result == sparseMap.size();
-                return result;
-            }
-
-            @Override
-            public boolean containsKey(K key) {
-                boolean result = linkedMap.containsKey(key);
-                assert result == sparseMap.containsKey(key);
-                return result;
-            }
-
-            @Override
-            public void clear() {
-                linkedMap.clear();
-                sparseMap.clear();
-            }
-
-            @Override
-            public V removeKey(K key) {
-                V result = linkedMap.remove(key);
-                assert Objects.equals(result, sparseMap.removeKey(key));
-                return result;
-            }
-
-            @Override
-            public Iterable<V> getValues() {
-
-                Iterator<V> iterator = linkedMap.values().iterator();
-                Iterator<V> sparseIterator = sparseMap.getValues().iterator();
-                return new Iterable<V>() {
-
-                    @Override
-                    public Iterator<V> iterator() {
-                        return new Iterator<V>() {
-
-                            @Override
-                            public boolean hasNext() {
-                                boolean result = iterator.hasNext();
-                                boolean otherResult = sparseIterator.hasNext();
-                                assert result == otherResult;
-                                return result;
-                            }
-
-                            @Override
-                            public V next() {
-                                V sparseNext = sparseIterator.next();
-                                V next = iterator.next();
-                                assert Objects.equals(sparseNext, next);
-                                return next;
-                            }
-
-                            @Override
-                            public void remove() {
-                                iterator.remove();
-                                sparseIterator.remove();
-                            }
-                        };
-                    }
-
-                };
-            }
-
-            @Override
-            public Iterable<K> getKeys() {
-
-                Iterator<K> iterator = linkedMap.keySet().iterator();
-                Iterator<K> sparseIterator = sparseMap.getKeys().iterator();
-                return new Iterable<K>() {
-
-                    @Override
-                    public Iterator<K> iterator() {
-                        return new Iterator<K>() {
-
-                            @Override
-                            public boolean hasNext() {
-                                boolean result = iterator.hasNext();
-                                boolean otherResult = sparseIterator.hasNext();
-                                assert result == otherResult;
-                                return result;
-                            }
-
-                            @Override
-                            public K next() {
-                                K sparseNext = sparseIterator.next();
-                                K next = iterator.next();
-                                assert Objects.equals(sparseNext, next);
-                                return next;
-                            }
-
-                            @Override
-                            public void remove() {
-                                iterator.remove();
-                                sparseIterator.remove();
-                            }
-                        };
-                    }
-
-                };
-            }
-
-            @Override
-            public boolean isEmpty() {
-                boolean result = linkedMap.isEmpty();
-                assert result == sparseMap.isEmpty();
-                return result;
-            }
-
-            @Override
-            public MapCursor<K, V> getEntries() {
-                Iterator<java.util.Map.Entry<K, V>> iterator = linkedMap.entrySet().iterator();
-                MapCursor<K, V> cursor = sparseMap.getEntries();
-                return new MapCursor<K, V>() {
-
-                    private Map.Entry<K, V> current;
-
-                    @Override
-                    public boolean advance() {
-                        boolean result = iterator.hasNext();
-                        boolean otherResult = cursor.advance();
-                        assert result == otherResult;
-                        if (result) {
-                            current = iterator.next();
-                        }
-
-                        return result;
-                    }
-
-                    @Override
-                    public K getKey() {
-                        K key = current.getKey();
-                        assert key == cursor.getKey();
-                        return key;
-                    }
-
-                    @Override
-                    public V getValue() {
-                        V value = current.getValue();
-                        assert Objects.equals(value, cursor.getValue());
-                        return value;
-                    }
-
-                    @Override
-                    public void remove() {
-                        iterator.remove();
-                        cursor.remove();
-                    }
-                };
-            }
-
-            @Override
-            public void replaceAll(BiFunction<? super K, ? super V, ? extends V> function) {
-                linkedMap.replaceAll(function);
-                sparseMap.replaceAll(function);
-            }
-        };
-    }
-
-    @Test
-    public void testIterableConcat() {
-        List<String> i1 = Arrays.asList("1", "2", "3");
-        List<String> i2 = Arrays.asList();
-        List<String> i3 = Arrays.asList("4", "5");
-        List<String> i4 = Arrays.asList();
-        List<String> i5 = Arrays.asList("6");
-        List<String> iNull = null;
-
-        List<String> actual = new ArrayList<>();
-        List<String> expected = new ArrayList<>();
-        expected.addAll(i1);
-        expected.addAll(i2);
-        expected.addAll(i3);
-        expected.addAll(i4);
-        expected.addAll(i5);
-        Iterable<String> iterable = CollectionsUtil.concat(Arrays.asList(i1, i2, i3, i4, i5));
-        for (String s : iterable) {
-            actual.add(s);
-        }
-        Assert.assertEquals(expected, actual);
-
-        Iterator<String> iter = iterable.iterator();
-        while (iter.hasNext()) {
-            iter.next();
-        }
-        try {
-            iter.next();
-            Assert.fail("Expected NoSuchElementException");
-        } catch (NoSuchElementException e) {
-            // Expected
-        }
-        try {
-            CollectionsUtil.concat(i1, iNull);
-            Assert.fail("Expected NullPointerException");
-        } catch (NullPointerException e) {
-            // Expected
-        }
-
-        Iterable<Object> emptyIterable = CollectionsUtil.concat(Collections.emptyList());
-        Assert.assertFalse(emptyIterable.iterator().hasNext());
-    }
-
-    @Test
-    public void testSetRemoval() {
-        ArrayList<Integer> initialList = new ArrayList<>();
-        ArrayList<Integer> removalList = new ArrayList<>();
-        ArrayList<Integer> finalList = new ArrayList<>();
-        EconomicSet<Integer> set = EconomicSet.create(Equivalence.IDENTITY);
-        set.add(1);
-        set.add(2);
-        set.add(3);
-        set.add(4);
-        set.add(5);
-        set.add(6);
-        set.add(7);
-        set.add(8);
-        set.add(9);
-        Iterator<Integer> i1 = set.iterator();
-        while (i1.hasNext()) {
-            initialList.add(i1.next());
-        }
-        int size = 0;
-        Iterator<Integer> i2 = set.iterator();
-        while (i2.hasNext()) {
-            Integer elem = i2.next();
-            if (size++ < 8) {
-                i2.remove();
-            }
-            removalList.add(elem);
-        }
-        Iterator<Integer> i3 = set.iterator();
-        while (i3.hasNext()) {
-            finalList.add(i3.next());
-        }
-        Assert.assertEquals(initialList, removalList);
-        Assert.assertEquals(1, finalList.size());
-        Assert.assertEquals(new Integer(9), finalList.get(0));
-    }
-}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.util.test/src/org/graalvm/util/test/CollectionUtilTest.java	Fri Feb 16 13:49:07 2018 -0800
@@ -0,0 +1,150 @@
+/*
+ * Copyright (c) 2017, 2017, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.graalvm.util.test;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.List;
+import java.util.NoSuchElementException;
+
+import org.graalvm.util.CollectionsUtil;
+import org.junit.Assert;
+import org.junit.Test;
+
+public class CollectionUtilTest {
+
+    private static int sum(Iterable<Integer> iterable) {
+        int sum = 0;
+        for (int i : iterable) {
+            sum += i;
+        }
+        return sum;
+    }
+
+    private static int indexOf(Iterable<Integer> iterable, int element) {
+        int index = 0;
+        for (int i : iterable) {
+            if (i == element) {
+                return index;
+            }
+            index++;
+        }
+        return -1;
+    }
+
+    @Test
+    public void testConcat() {
+        List<Integer> a = Arrays.asList(1, 2);
+        List<Integer> b = Arrays.asList(3, 4, 5);
+        Assert.assertEquals(sum(CollectionsUtil.concat(a, b)), 15);
+        Assert.assertEquals(sum(CollectionsUtil.concat(b, a)), 15);
+        Assert.assertEquals(indexOf(CollectionsUtil.concat(a, b), 5), 4);
+        Assert.assertEquals(indexOf(CollectionsUtil.concat(b, a), 5), 2);
+    }
+
+    @Test
+    public void testMatch() {
+        String[] array = {"a", "b", "c", "d", "e"};
+        Assert.assertTrue(CollectionsUtil.allMatch(array, s -> !s.isEmpty()));
+        Assert.assertFalse(CollectionsUtil.allMatch(array, s -> !s.startsWith("c")));
+        Assert.assertFalse(CollectionsUtil.anyMatch(array, String::isEmpty));
+        Assert.assertTrue(CollectionsUtil.anyMatch(array, s -> s.startsWith("c")));
+    }
+
+    @Test
+    public void testFilterToList() {
+        String[] array = {"a", "b", "", "d", "e"};
+        Assert.assertEquals(CollectionsUtil.filterToList(Arrays.asList(array), String::isEmpty).size(), 1);
+    }
+
+    @Test
+    public void testFilterAndMapToArray() {
+        String[] array = {"a", "b", "", "d", "e"};
+        String[] newArray = CollectionsUtil.filterAndMapToArray(array, s -> !s.isEmpty(), String::toUpperCase, String[]::new);
+        Assert.assertArrayEquals(newArray, new String[]{"A", "B", "D", "E"});
+    }
+
+    @Test
+    public void testMapToArray() {
+        String[] array = {"a", "b", "c", "d", "e"};
+        String[] newArray = CollectionsUtil.mapToArray(array, String::toUpperCase, String[]::new);
+        Assert.assertArrayEquals(newArray, new String[]{"A", "B", "C", "D", "E"});
+    }
+
+    @Test
+    public void testMapAndJoin() {
+        String[] array = {"a", "b", "c", "d", "e"};
+        Assert.assertEquals(CollectionsUtil.mapAndJoin(array, String::toUpperCase, ", "), "A, B, C, D, E");
+        Assert.assertEquals(CollectionsUtil.mapAndJoin(array, String::toUpperCase, ", ", "'"), "'A, 'B, 'C, 'D, 'E");
+        Assert.assertEquals(CollectionsUtil.mapAndJoin(array, String::toUpperCase, ", ", "'", "'"), "'A', 'B', 'C', 'D', 'E'");
+
+        Assert.assertEquals(CollectionsUtil.mapAndJoin(Arrays.asList(array), String::toUpperCase, ", "), "A, B, C, D, E");
+        Assert.assertEquals(CollectionsUtil.mapAndJoin(Arrays.asList(array), String::toUpperCase, ", ", "'"), "'A, 'B, 'C, 'D, 'E");
+    }
+
+    @Test
+    public void testIterableConcat() {
+        List<String> i1 = Arrays.asList("1", "2", "3");
+        List<String> i2 = Arrays.asList();
+        List<String> i3 = Arrays.asList("4", "5");
+        List<String> i4 = Arrays.asList();
+        List<String> i5 = Arrays.asList("6");
+        List<String> iNull = null;
+
+        List<String> actual = new ArrayList<>();
+        List<String> expected = new ArrayList<>();
+        expected.addAll(i1);
+        expected.addAll(i2);
+        expected.addAll(i3);
+        expected.addAll(i4);
+        expected.addAll(i5);
+        Iterable<String> iterable = CollectionsUtil.concat(Arrays.asList(i1, i2, i3, i4, i5));
+        for (String s : iterable) {
+            actual.add(s);
+        }
+        Assert.assertEquals(expected, actual);
+
+        Iterator<String> iter = iterable.iterator();
+        while (iter.hasNext()) {
+            iter.next();
+        }
+        try {
+            iter.next();
+            Assert.fail("Expected NoSuchElementException");
+        } catch (NoSuchElementException e) {
+            // Expected
+        }
+        try {
+            CollectionsUtil.concat(i1, iNull);
+            Assert.fail("Expected NullPointerException");
+        } catch (NullPointerException e) {
+            // Expected
+        }
+
+        Iterable<Object> emptyIterable = CollectionsUtil.concat(Collections.emptyList());
+        Assert.assertFalse(emptyIterable.iterator().hasNext());
+    }
+
+}
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.util/src/org/graalvm/util/CollectionsUtil.java	Fri Feb 16 12:24:38 2018 -0800
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.util/src/org/graalvm/util/CollectionsUtil.java	Fri Feb 16 13:49:07 2018 -0800
@@ -37,7 +37,10 @@
 /**
  * This class contains utility methods for commonly used functional patterns for collections.
  */
-public class CollectionsUtil {
+public final class CollectionsUtil {
+
+    private CollectionsUtil() {
+    }
 
     /**
      * Concatenates two iterables into a single iterable. The iterator exposed by the returned
@@ -93,10 +96,26 @@
         };
     }
 
+    /**
+     * Returns whether all elements in {@code inputs} match {@code predicate}. May not evaluate
+     * {@code predicate} on all elements if not necessary for determining the result. If
+     * {@code inputs} is empty then {@code true} is returned and {@code predicate} is not evaluated.
+     *
+     * @return {@code true} if either all elements in {@code inputs} match {@code predicate} or
+     *         {@code inputs} is empty, otherwise {@code false}.
+     */
     public static <T> boolean allMatch(T[] inputs, Predicate<T> predicate) {
         return allMatch(Arrays.asList(inputs), predicate);
     }
 
+    /**
+     * Returns whether all elements in {@code inputs} match {@code predicate}. May not evaluate
+     * {@code predicate} on all elements if not necessary for determining the result. If
+     * {@code inputs} is empty then {@code true} is returned and {@code predicate} is not evaluated.
+     *
+     * @return {@code true} if either all elements in {@code inputs} match {@code predicate} or
+     *         {@code inputs} is empty, otherwise {@code false}.
+     */
     public static <T> boolean allMatch(Iterable<T> inputs, Predicate<T> predicate) {
         for (T t : inputs) {
             if (!predicate.test(t)) {
@@ -106,10 +125,28 @@
         return true;
     }
 
+    /**
+     * Returns whether any elements in {@code inputs} match {@code predicate}. May not evaluate
+     * {@code predicate} on all elements if not necessary for determining the result. If
+     * {@code inputs} is empty then {@code false} is returned and {@code predicate} is not
+     * evaluated.
+     *
+     * @return {@code true} if any elements in {@code inputs} match {@code predicate}, otherwise
+     *         {@code false}.
+     */
     public static <T> boolean anyMatch(T[] inputs, Predicate<T> predicate) {
         return anyMatch(Arrays.asList(inputs), predicate);
     }
 
+    /**
+     * Returns whether any elements in {@code inputs} match {@code predicate}. May not evaluate
+     * {@code predicate} on all elements if not necessary for determining the result. If
+     * {@code inputs} is empty then {@code false} is returned and {@code predicate} is not
+     * evaluated.
+     *
+     * @return {@code true} if any elements in {@code inputs} match {@code predicate}, otherwise
+     *         {@code false}.
+     */
     public static <T> boolean anyMatch(Iterable<T> inputs, Predicate<T> predicate) {
         for (T t : inputs) {
             if (predicate.test(t)) {
@@ -119,10 +156,21 @@
         return false;
     }
 
+    /**
+     * Returns a new list consisting of the elements in {@code inputs} that match {@code predicate}.
+     *
+     * @return the new list.
+     */
     public static <T> List<T> filterToList(List<T> inputs, Predicate<? super T> predicate) {
         return filterToList(inputs, predicate, ArrayList::new);
     }
 
+    /**
+     * Appends elements of {@code inputs} that match {@code predicate} to the list generated by
+     * {@code listGenerator}.
+     *
+     * @return the list generated by {@code listGenerator}.
+     */
     public static <T> List<T> filterToList(List<T> inputs, Predicate<? super T> predicate, Supplier<List<T>> listGenerator) {
         List<T> resultList = listGenerator.get();
         for (T t : inputs) {
@@ -134,8 +182,10 @@
     }
 
     /**
-     * Filters the inputs, maps them given the mapping function and adds them in the array provided
-     * by the generator.
+     * Filters {@code inputs} with {@code predicate}, applies {@code mapper} and adds them in the
+     * array provided by {@code arrayGenerator}.
+     *
+     * @return the array provided by {@code arrayGenerator}.
      */
     public static <T, R> R[] filterAndMapToArray(T[] inputs, Predicate<? super T> predicate, Function<? super T, ? extends R> mapper, IntFunction<R[]> arrayGenerator) {
         List<R> resultList = new ArrayList<>();
@@ -148,13 +198,21 @@
     }
 
     /**
-     * Maps the inputs given the mapping function and adds them in the array provided by the
-     * generator.
+     * Applies {@code mapper} on the elements in {@code inputs} and adds them in the array provided
+     * by {@code arrayGenerator}.
+     *
+     * @return the array provided by {@code arrayGenerator}.
      */
     public static <T, R> R[] mapToArray(T[] inputs, Function<? super T, ? extends R> mapper, IntFunction<R[]> arrayGenerator) {
         return mapToArray(Arrays.asList(inputs), mapper, arrayGenerator);
     }
 
+    /**
+     * Applies {@code mapper} on the elements in {@code inputs} and adds them in the array provided
+     * by {@code arrayGenerator}.
+     *
+     * @return the array provided by {@code arrayGenerator}.
+     */
     public static <T, R> R[] mapToArray(Collection<T> inputs, Function<? super T, ? extends R> mapper, IntFunction<R[]> arrayGenerator) {
         R[] result = arrayGenerator.apply(inputs.size());
         int idx = 0;
@@ -164,26 +222,62 @@
         return result;
     }
 
+    /**
+     * Applies {@code mapper} on the elements in {@code inputs}, and joins them together separated
+     * by {@code delimiter}.
+     *
+     * @return a new String that is composed from {@code inputs}.
+     */
     public static <T, R> String mapAndJoin(T[] inputs, Function<? super T, ? extends R> mapper, String delimiter) {
         return mapAndJoin(Arrays.asList(inputs), mapper, delimiter, "", "");
     }
 
+    /**
+     * Applies {@code mapper} on the elements in {@code inputs}, and joins them together separated
+     * by {@code delimiter} and starting with {@code prefix}.
+     *
+     * @return a new String that is composed from {@code inputs}.
+     */
     public static <T, R> String mapAndJoin(T[] inputs, Function<? super T, ? extends R> mapper, String delimiter, String prefix) {
         return mapAndJoin(Arrays.asList(inputs), mapper, delimiter, prefix, "");
     }
 
+    /**
+     * Applies {@code mapper} on the elements in {@code inputs}, and joins them together separated
+     * by {@code delimiter} and starting with {@code prefix} and ending with {@code suffix}.
+     *
+     * @return a new String that is composed from {@code inputs}.
+     */
     public static <T, R> String mapAndJoin(T[] inputs, Function<? super T, ? extends R> mapper, String delimiter, String prefix, String suffix) {
         return mapAndJoin(Arrays.asList(inputs), mapper, delimiter, prefix, suffix);
     }
 
+    /**
+     * Applies {@code mapper} on the elements in {@code inputs}, and joins them together separated
+     * by {@code delimiter}.
+     *
+     * @return a new String that is composed from {@code inputs}.
+     */
     public static <T, R> String mapAndJoin(Iterable<T> inputs, Function<? super T, ? extends R> mapper, String delimiter) {
         return mapAndJoin(inputs, mapper, delimiter, "", "");
     }
 
+    /**
+     * Applies {@code mapper} on the elements in {@code inputs}, and joins them together separated
+     * by {@code delimiter} and starting with {@code prefix}.
+     *
+     * @return a new String that is composed from {@code inputs}.
+     */
     public static <T, R> String mapAndJoin(Iterable<T> inputs, Function<? super T, ? extends R> mapper, String delimiter, String prefix) {
         return mapAndJoin(inputs, mapper, delimiter, prefix, "");
     }
 
+    /**
+     * Applies {@code mapper} on the elements in {@code inputs}, and joins them together separated
+     * by {@code delimiter} and starting with {@code prefix} and ending with {@code suffix}.
+     *
+     * @return a new String that is composed from {@code inputs}.
+     */
     public static <T, R> String mapAndJoin(Iterable<T> inputs, Function<? super T, ? extends R> mapper, String delimiter, String prefix, String suffix) {
         StringBuilder strb = new StringBuilder();
         String sep = "";
@@ -193,4 +287,5 @@
         }
         return strb.toString();
     }
+
 }
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.util/src/org/graalvm/util/EconomicMap.java	Fri Feb 16 12:24:38 2018 -0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,206 +0,0 @@
-/*
- * Copyright (c) 2017, 2017, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package org.graalvm.util;
-
-import java.util.Iterator;
-import java.util.Map;
-import java.util.function.BiFunction;
-
-import org.graalvm.util.impl.EconomicMapImpl;
-
-/**
- * Memory efficient map data structure.
- */
-public interface EconomicMap<K, V> extends UnmodifiableEconomicMap<K, V> {
-
-    V put(K key, V value);
-
-    default void putAll(EconomicMap<K, V> other) {
-        MapCursor<K, V> e = other.getEntries();
-        while (e.advance()) {
-            put(e.getKey(), e.getValue());
-        }
-    }
-
-    void clear();
-
-    V removeKey(K key);
-
-    @Override
-    MapCursor<K, V> getEntries();
-
-    void replaceAll(BiFunction<? super K, ? super V, ? extends V> function);
-
-    default void putAll(UnmodifiableEconomicMap<? extends K, ? extends V> other) {
-        UnmodifiableMapCursor<? extends K, ? extends V> entry = other.getEntries();
-        while (entry.advance()) {
-            put(entry.getKey(), entry.getValue());
-        }
-    }
-
-    /**
-     * Creates a new map that guarantees insertion order on the key set with the default
-     * {@link Equivalence#DEFAULT} comparison strategy for keys.
-     */
-    static <K, V> EconomicMap<K, V> create() {
-        return EconomicMap.create(Equivalence.DEFAULT);
-    }
-
-    /**
-     * Creates a new map that guarantees insertion order on the key set with the default
-     * {@link Equivalence#DEFAULT} comparison strategy for keys and initializes with a specified
-     * capacity.
-     */
-    static <K, V> EconomicMap<K, V> create(int initialCapacity) {
-        return EconomicMap.create(Equivalence.DEFAULT, initialCapacity);
-    }
-
-    /**
-     * Creates a new map that guarantees insertion order on the key set with the given comparison
-     * strategy for keys.
-     */
-    static <K, V> EconomicMap<K, V> create(Equivalence strategy) {
-        return EconomicMapImpl.create(strategy);
-    }
-
-    /**
-     * Creates a new map that guarantees insertion order on the key set with the default
-     * {@link Equivalence#DEFAULT} comparison strategy for keys and copies all elements from the
-     * specified existing map.
-     */
-    static <K, V> EconomicMap<K, V> create(UnmodifiableEconomicMap<K, V> m) {
-        return EconomicMap.create(Equivalence.DEFAULT, m);
-    }
-
-    /**
-     * Creates a new map that guarantees insertion order on the key set and copies all elements from
-     * the specified existing map.
-     */
-    static <K, V> EconomicMap<K, V> create(Equivalence strategy, UnmodifiableEconomicMap<K, V> m) {
-        return EconomicMapImpl.create(strategy, m);
-    }
-
-    /**
-     * Creates a new map that guarantees insertion order on the key set and initializes with a
-     * specified capacity.
-     */
-    static <K, V> EconomicMap<K, V> create(Equivalence strategy, int initialCapacity) {
-        return EconomicMapImpl.create(strategy, initialCapacity);
-    }
-
-    /**
-     * Wraps an existing {@link java.util.Map} as an {@link org.graalvm.util.EconomicMap}.
-     */
-    static <K, V> EconomicMap<K, V> wrapMap(Map<K, V> map) {
-        return new EconomicMap<K, V>() {
-
-            @Override
-            public V get(K key) {
-                V result = map.get(key);
-                return result;
-            }
-
-            @Override
-            public V put(K key, V value) {
-                V result = map.put(key, value);
-                return result;
-            }
-
-            @Override
-            public int size() {
-                int result = map.size();
-                return result;
-            }
-
-            @Override
-            public boolean containsKey(K key) {
-                return map.containsKey(key);
-            }
-
-            @Override
-            public void clear() {
-                map.clear();
-            }
-
-            @Override
-            public V removeKey(K key) {
-                V result = map.remove(key);
-                return result;
-            }
-
-            @Override
-            public Iterable<V> getValues() {
-                return map.values();
-            }
-
-            @Override
-            public Iterable<K> getKeys() {
-                return map.keySet();
-            }
-
-            @Override
-            public boolean isEmpty() {
-                return map.isEmpty();
-            }
-
-            @Override
-            public MapCursor<K, V> getEntries() {
-                Iterator<java.util.Map.Entry<K, V>> iterator = map.entrySet().iterator();
-                return new MapCursor<K, V>() {
-
-                    private Map.Entry<K, V> current;
-
-                    @Override
-                    public boolean advance() {
-                        boolean result = iterator.hasNext();
-                        if (result) {
-                            current = iterator.next();
-                        }
-
-                        return result;
-                    }
-
-                    @Override
-                    public K getKey() {
-                        return current.getKey();
-                    }
-
-                    @Override
-                    public V getValue() {
-                        return current.getValue();
-                    }
-
-                    @Override
-                    public void remove() {
-                        iterator.remove();
-                    }
-                };
-            }
-
-            @Override
-            public void replaceAll(BiFunction<? super K, ? super V, ? extends V> function) {
-                map.replaceAll(function);
-            }
-        };
-    }
-}
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.util/src/org/graalvm/util/EconomicSet.java	Fri Feb 16 12:24:38 2018 -0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,126 +0,0 @@
-/*
- * Copyright (c) 2017, 2017, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package org.graalvm.util;
-
-import java.util.Iterator;
-
-import org.graalvm.util.impl.EconomicMapImpl;
-
-/**
- * Memory efficient set data structure.
- */
-public interface EconomicSet<E> extends UnmodifiableEconomicSet<E> {
-
-    boolean add(E element);
-
-    void remove(E element);
-
-    void clear();
-
-    default void addAll(EconomicSet<E> values) {
-        addAll(values.iterator());
-    }
-
-    default void addAll(Iterable<E> values) {
-        addAll(values.iterator());
-    }
-
-    default void addAll(Iterator<E> values) {
-        while (values.hasNext()) {
-            add(values.next());
-        }
-    }
-
-    default void removeAll(EconomicSet<E> values) {
-        removeAll(values.iterator());
-    }
-
-    default void removeAll(Iterable<E> values) {
-        removeAll(values.iterator());
-    }
-
-    default void removeAll(Iterator<E> values) {
-        while (values.hasNext()) {
-            remove(values.next());
-        }
-    }
-
-    default void retainAll(EconomicSet<E> values) {
-        Iterator<E> iterator = iterator();
-        while (iterator.hasNext()) {
-            E key = iterator.next();
-            if (!values.contains(key)) {
-                iterator.remove();
-            }
-        }
-    }
-
-    /**
-     * Creates a new set guaranteeing insertion order when iterating over its elements with the
-     * default {@link Equivalence#DEFAULT} comparison strategy.
-     */
-    static <E> EconomicSet<E> create() {
-        return EconomicSet.create(Equivalence.DEFAULT);
-    }
-
-    /**
-     * Creates a new set guaranteeing insertion order when iterating over its elements.
-     */
-    static <E> EconomicSet<E> create(Equivalence strategy) {
-        return EconomicMapImpl.create(strategy);
-    }
-
-    /**
-     * Creates a new set guaranteeing insertion order when iterating over its elements with the
-     * default {@link Equivalence#DEFAULT} comparison strategy and inserts all elements of the
-     * specified collection.
-     */
-    static <E> EconomicSet<E> create(int initialCapacity) {
-        return EconomicSet.create(Equivalence.DEFAULT, initialCapacity);
-    }
-
-    /**
-     * Creates a new set guaranteeing insertion order when iterating over its elements with the
-     * default {@link Equivalence#DEFAULT} comparison strategy and inserts all elements of the
-     * specified collection.
-     */
-    static <E> EconomicSet<E> create(UnmodifiableEconomicSet<E> c) {
-        return EconomicSet.create(Equivalence.DEFAULT, c);
-    }
-
-    /**
-     * Creates a new set guaranteeing insertion order when iterating over its elements and
-     * initializes with the given capacity.
-     */
-    static <E> EconomicSet<E> create(Equivalence strategy, int initialCapacity) {
-        return EconomicMapImpl.create(strategy, initialCapacity);
-    }
-
-    /**
-     * Creates a new set guaranteeing insertion order when iterating over its elements and inserts
-     * all elements of the specified collection.
-     */
-    static <E> EconomicSet<E> create(Equivalence strategy, UnmodifiableEconomicSet<E> c) {
-        return EconomicMapImpl.create(strategy, c);
-    }
-}
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.util/src/org/graalvm/util/Equivalence.java	Fri Feb 16 12:24:38 2018 -0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,93 +0,0 @@
-/*
- * Copyright (c) 2017, 2017, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package org.graalvm.util;
-
-/**
- * Strategy for comparing two objects. Default predefined strategies are {@link #DEFAULT},
- * {@link #IDENTITY}, and {@link #IDENTITY_WITH_SYSTEM_HASHCODE}.
- */
-public abstract class Equivalence {
-
-    /**
-     * Default equivalence calling {@link #equals(Object)} to check equality and {@link #hashCode()}
-     * for obtaining hash values. Do not change the logic of this class as it may be inlined in
-     * other places.
-     */
-    public static final Equivalence DEFAULT = new Equivalence() {
-
-        @Override
-        public boolean equals(Object a, Object b) {
-            return a.equals(b);
-        }
-
-        @Override
-        public int hashCode(Object o) {
-            return o.hashCode();
-        }
-    };
-
-    /**
-     * Identity equivalence using {@code ==} to check equality and {@link #hashCode()} for obtaining
-     * hash values. Do not change the logic of this class as it may be inlined in other places.
-     */
-    public static final Equivalence IDENTITY = new Equivalence() {
-
-        @Override
-        public boolean equals(Object a, Object b) {
-            return a == b;
-        }
-
-        @Override
-        public int hashCode(Object o) {
-            return o.hashCode();
-        }
-    };
-
-    /**
-     * Identity equivalence using {@code ==} to check equality and
-     * {@link System#identityHashCode(Object)} for obtaining hash values. Do not change the logic of
-     * this class as it may be inlined in other places.
-     */
-    public static final Equivalence IDENTITY_WITH_SYSTEM_HASHCODE = new Equivalence() {
-
-        @Override
-        public boolean equals(Object a, Object b) {
-            return a == b;
-        }
-
-        @Override
-        public int hashCode(Object o) {
-            return System.identityHashCode(o);
-        }
-    };
-
-    /**
-     * Subclass for creating custom equivalence definitions.
-     */
-    protected Equivalence() {
-    }
-
-    public abstract boolean equals(Object a, Object b);
-
-    public abstract int hashCode(Object o);
-}
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.util/src/org/graalvm/util/MapCursor.java	Fri Feb 16 12:24:38 2018 -0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,35 +0,0 @@
-/*
- * Copyright (c) 2017, 2017, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package org.graalvm.util;
-
-/**
- * Cursor to iterate over a mutable map.
- */
-public interface MapCursor<K, V> extends UnmodifiableMapCursor<K, V> {
-    /**
-     * Remove the current entry from the map. May only be called once. After calling
-     * {@link #remove()}, it is no longer valid to call {@link #getKey()} or {@link #getValue()} on
-     * the current entry.
-     */
-    void remove();
-}
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.util/src/org/graalvm/util/ObjectSizeEstimate.java	Fri Feb 16 12:24:38 2018 -0800
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.util/src/org/graalvm/util/ObjectSizeEstimate.java	Fri Feb 16 13:49:07 2018 -0800
@@ -26,6 +26,9 @@
 import java.lang.reflect.Modifier;
 import java.util.ArrayList;
 
+import org.graalvm.collections.EconomicMap;
+import org.graalvm.collections.Equivalence;
+
 /**
  * Calculates approximate estimates of the size of an object graph.
  *
@@ -193,8 +196,8 @@
                             } else {
                                 size.recordPointer();
                                 if (maxDepth > 1) {
-                                    f.setAccessible(true);
                                     try {
+                                        f.setAccessible(true);
                                         Object inner = f.get(o);
                                         if (inner != null) {
                                             if (depth < maxDepth && !identityHashMap.containsKey(inner)) {
@@ -205,6 +208,14 @@
                                         }
                                     } catch (IllegalArgumentException | IllegalAccessException e) {
                                         throw new UnsupportedOperationException("Must have access privileges to traverse object graph");
+                                    } catch (RuntimeException e) {
+                                        if ("java.lang.reflect.InaccessibleObjectException".equals(e.getClass().getName())) {
+                                            // This is a newly introduced exception in JDK9 and thus
+                                            // cannot be declared in the catch clause.
+                                            throw new UnsupportedOperationException("Target class is not exported to the current module.", e);
+                                        } else {
+                                            throw e;
+                                        }
                                     }
                                 }
                             }
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.util/src/org/graalvm/util/Pair.java	Fri Feb 16 12:24:38 2018 -0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,102 +0,0 @@
-/*
- * Copyright (c) 2017, 2017, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package org.graalvm.util;
-
-import java.util.Objects;
-
-/**
- * Utility class representing a pair of values.
- */
-public final class Pair<L, R> {
-    private static final Pair<Object, Object> EMPTY = new Pair<>(null, null);
-
-    private final L left;
-    private final R right;
-
-    @SuppressWarnings("unchecked")
-    public static <L, R> Pair<L, R> empty() {
-        return (Pair<L, R>) EMPTY;
-    }
-
-    public static <L, R> Pair<L, R> createLeft(L left) {
-        if (left == null) {
-            return empty();
-        } else {
-            return new Pair<>(left, null);
-        }
-    }
-
-    public static <L, R> Pair<L, R> createRight(R right) {
-        if (right == null) {
-            return empty();
-        } else {
-            return new Pair<>(null, right);
-        }
-    }
-
-    public static <L, R> Pair<L, R> create(L left, R right) {
-        if (right == null && left == null) {
-            return empty();
-        } else {
-            return new Pair<>(left, right);
-        }
-    }
-
-    private Pair(L left, R right) {
-        this.left = left;
-        this.right = right;
-    }
-
-    public L getLeft() {
-        return left;
-    }
-
-    public R getRight() {
-        return right;
-    }
-
-    @Override
-    public int hashCode() {
-        return Objects.hashCode(left) + 31 * Objects.hashCode(right);
-    }
-
-    @SuppressWarnings("unchecked")
-    @Override
-    public boolean equals(Object obj) {
-        if (obj == this) {
-            return true;
-        }
-
-        if (obj instanceof Pair) {
-            Pair<L, R> pair = (Pair<L, R>) obj;
-            return Objects.equals(left, pair.left) && Objects.equals(right, pair.right);
-        }
-
-        return false;
-    }
-
-    @Override
-    public String toString() {
-        return String.format("(%s, %s)", left, right);
-    }
-}
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.util/src/org/graalvm/util/UnmodifiableEconomicMap.java	Fri Feb 16 12:24:38 2018 -0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,51 +0,0 @@
-/*
- * Copyright (c) 2017, 2017, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package org.graalvm.util;
-
-/**
- * Unmodifiable memory efficient map data structure.
- */
-public interface UnmodifiableEconomicMap<K, V> {
-
-    V get(K key);
-
-    default V get(K key, V defaultValue) {
-        V v = get(key);
-        if (v == null) {
-            return defaultValue;
-        }
-        return v;
-    }
-
-    boolean containsKey(K key);
-
-    int size();
-
-    boolean isEmpty();
-
-    Iterable<V> getValues();
-
-    Iterable<K> getKeys();
-
-    UnmodifiableMapCursor<K, V> getEntries();
-}
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.util/src/org/graalvm/util/UnmodifiableEconomicSet.java	Fri Feb 16 12:24:38 2018 -0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,48 +0,0 @@
-/*
- * Copyright (c) 2017, 2017, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package org.graalvm.util;
-
-/**
- * Unmodifiable memory efficient set data structure.
- */
-public interface UnmodifiableEconomicSet<E> extends Iterable<E> {
-
-    boolean contains(E element);
-
-    int size();
-
-    boolean isEmpty();
-
-    default E[] toArray(E[] target) {
-        if (target.length != size()) {
-            throw new UnsupportedOperationException("Length of target array must equal the size of the set.");
-        }
-
-        int index = 0;
-        for (E element : this) {
-            target[index++] = element;
-        }
-
-        return target;
-    }
-}
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.util/src/org/graalvm/util/UnmodifiableMapCursor.java	Fri Feb 16 12:24:38 2018 -0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,45 +0,0 @@
-/*
- * Copyright (c) 2017, 2017, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package org.graalvm.util;
-
-/**
- * Cursor to iterate over a map without changing its contents.
- */
-public interface UnmodifiableMapCursor<K, V> {
-    /**
-     * Advances to the next entry.
-     *
-     * @return {@code true} if a next entry exists, {@code false} if there is no next entry.
-     */
-    boolean advance();
-
-    /**
-     * The key of the current entry.
-     */
-    K getKey();
-
-    /**
-     * The value of the current entry.
-     */
-    V getValue();
-}
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.util/src/org/graalvm/util/impl/EconomicMapImpl.java	Fri Feb 16 12:24:38 2018 -0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,852 +0,0 @@
-/*
- * Copyright (c) 2017, 2017, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- */
-package org.graalvm.util.impl;
-
-import java.util.Iterator;
-import java.util.Objects;
-import java.util.function.BiFunction;
-
-import org.graalvm.util.Equivalence;
-import org.graalvm.util.EconomicMap;
-import org.graalvm.util.EconomicSet;
-import org.graalvm.util.UnmodifiableEconomicMap;
-import org.graalvm.util.UnmodifiableEconomicSet;
-import org.graalvm.util.MapCursor;
-
-/**
- * Implementation of a map with a memory-efficient structure that always preserves insertion order
- * when iterating over keys. Particularly efficient when number of entries is 0 or smaller equal
- * {@link #INITIAL_CAPACITY} or smaller 256.
- *
- * The key/value pairs are kept in an expanding flat object array with keys at even indices and
- * values at odd indices. If the map has smaller or equal to {@link #HASH_THRESHOLD} entries, there
- * is no additional hash data structure and comparisons are done via linear checking of the
- * key/value pairs. For the case where the equality check is particularly cheap (e.g., just an
- * object identity comparison), this limit below which the map is without an actual hash table is
- * higher and configured at {@link #HASH_THRESHOLD_IDENTITY_COMPARE}.
- *
- * When the hash table needs to be constructed, the field {@link #hashArray} becomes a new hash
- * array where an entry of 0 means no hit and otherwise denotes the entry number in the
- * {@link #entries} array. The hash array is interpreted as an actual byte array if the indices fit
- * within 8 bit, or as an array of short values if the indices fit within 16 bit, or as an array of
- * integer values in other cases.
- *
- * Hash collisions are handled by chaining a linked list of {@link CollisionLink} objects that take
- * the place of the values in the {@link #entries} array.
- *
- * Removing entries will put {@code null} into the {@link #entries} array. If the occupation of the
- * map falls below a specific threshold, the map will be compressed via the
- * {@link #maybeCompress(int)} method.
- */
-public final class EconomicMapImpl<K, V> implements EconomicMap<K, V>, EconomicSet<K> {
-
-    /**
-     * Initial number of key/value pair entries that is allocated in the first entries array.
-     */
-    private static final int INITIAL_CAPACITY = 4;
-
-    /**
-     * Maximum number of entries that are moved linearly forward if a key is removed.
-     */
-    private static final int COMPRESS_IMMEDIATE_CAPACITY = 8;
-
-    /**
-     * Minimum number of key/value pair entries added when the entries array is increased in size.
-     */
-    private static final int MIN_CAPACITY_INCREASE = 8;
-
-    /**
-     * Number of entries above which a hash table is created.
-     */
-    private static final int HASH_THRESHOLD = 4;
-
-    /**
-     * Number of entries above which a hash table is created when equality can be checked with
-     * object identity.
-     */
-    private static final int HASH_THRESHOLD_IDENTITY_COMPARE = 8;
-
-    /**
-     * Maximum number of entries allowed in the map.
-     */
-    private static final int MAX_ELEMENT_COUNT = Integer.MAX_VALUE >> 1;
-
-    /**
-     * Number of entries above which more than 1 byte is necessary for the hash index.
-     */
-    private static final int LARGE_HASH_THRESHOLD = ((1 << Byte.SIZE) << 1);
-
-    /**
-     * Number of entries above which more than 2 bytes are are necessary for the hash index.
-     */
-    private static final int VERY_LARGE_HASH_THRESHOLD = (LARGE_HASH_THRESHOLD << Byte.SIZE);
-
-    /**
-     * Total number of entries (actual entries plus deleted entries).
-     */
-    private int totalEntries;
-
-    /**
-     * Number of deleted entries.
-     */
-    private int deletedEntries;
-
-    /**
-     * Entries array with even indices storing keys and odd indices storing values.
-     */
-    private Object[] entries;
-
-    /**
-     * Hash array that is interpreted either as byte or short or int array depending on number of
-     * map entries.
-     */
-    private byte[] hashArray;
-
-    /**
-     * The strategy used for comparing keys or {@code null} for denoting special strategy
-     * {@link Equivalence#IDENTITY}.
-     */
-    private final Equivalence strategy;
-
-    /**
-     * Intercept method for debugging purposes.
-     */
-    private static <K, V> EconomicMapImpl<K, V> intercept(EconomicMapImpl<K, V> map) {
-        return map;
-    }
-
-    public static <K, V> EconomicMapImpl<K, V> create(Equivalence strategy) {
-        return intercept(new EconomicMapImpl<>(strategy));
-    }
-
-    public static <K, V> EconomicMapImpl<K, V> create(Equivalence strategy, int initialCapacity) {
-        return intercept(new EconomicMapImpl<>(strategy, initialCapacity));
-    }
-
-    public static <K, V> EconomicMapImpl<K, V> create(Equivalence strategy, UnmodifiableEconomicMap<K, V> other) {
-        return intercept(new EconomicMapImpl<>(strategy, other));
-    }
-
-    public static <K, V> EconomicMapImpl<K, V> create(Equivalence strategy, UnmodifiableEconomicSet<K> other) {
-        return intercept(new EconomicMapImpl<>(strategy, other));
-    }
-
-    private EconomicMapImpl(Equivalence strategy) {
-        if (strategy == Equivalence.IDENTITY) {
-            this.strategy = null;
-        } else {
-            this.strategy = strategy;
-        }
-    }
-
-    private EconomicMapImpl(Equivalence strategy, int initialCapacity) {
-        this(strategy);
-        init(initialCapacity);
-    }
-
-    private EconomicMapImpl(Equivalence strategy, UnmodifiableEconomicMap<K, V> other) {
-        this(strategy);
-        if (!initFrom(other)) {
-            init(other.size());
-            putAll(other);
-        }
-    }
-
-    private EconomicMapImpl(Equivalence strategy, UnmodifiableEconomicSet<K> other) {
-        this(strategy);
-        if (!initFrom(other)) {
-            init(other.size());
-            addAll(other);
-        }
-    }
-
-    @SuppressWarnings("unchecked")
-    private boolean initFrom(Object o) {
-        if (o instanceof EconomicMapImpl) {
-            EconomicMapImpl<K, V> otherMap = (EconomicMapImpl<K, V>) o;
-            // We are only allowed to directly copy if the strategies of the two maps are the same.
-            if (strategy == otherMap.strategy) {
-                totalEntries = otherMap.totalEntries;
-                deletedEntries = otherMap.deletedEntries;
-                if (otherMap.entries != null) {
-                    entries = otherMap.entries.clone();
-                }
-                if (otherMap.hashArray != null) {
-                    hashArray = otherMap.hashArray.clone();
-                }
-                return true;
-            }
-        }
-        return false;
-    }
-
-    private void init(int size) {
-        if (size > INITIAL_CAPACITY) {
-            entries = new Object[size << 1];
-        }
-    }
-
-    /**
-     * Links the collisions. Needs to be immutable class for allowing efficient shallow copy from
-     * other map on construction.
-     */
-    private static final class CollisionLink {
-
-        CollisionLink(Object value, int next) {
-            this.value = value;
-            this.next = next;
-        }
-
-        final Object value;
-
-        /**
-         * Index plus one of the next entry in the collision link chain.
-         */
-        final int next;
-    }
-
-    @SuppressWarnings("unchecked")
-    @Override
-    public V get(K key) {
-        Objects.requireNonNull(key);
-
-        int index = find(key);
-        if (index != -1) {
-            return (V) getValue(index);
-        }
-        return null;
-    }
-
-    private int find(K key) {
-        if (hasHashArray()) {
-            return findHash(key);
-        } else {
-            return findLinear(key);
-        }
-    }
-
-    private int findLinear(K key) {
-        for (int i = 0; i < totalEntries; i++) {
-            Object entryKey = entries[i << 1];
-            if (entryKey != null && compareKeys(key, entryKey)) {
-                return i;
-            }
-        }
-        return -1;
-    }
-
-    private boolean compareKeys(Object key, Object entryKey) {
-        if (key == entryKey) {
-            return true;
-        }
-        if (strategy != null && strategy != Equivalence.IDENTITY_WITH_SYSTEM_HASHCODE) {
-            if (strategy == Equivalence.DEFAULT) {
-                return key.equals(entryKey);
-            } else {
-                return strategy.equals(key, entryKey);
-            }
-        }
-        return false;
-    }
-
-    private int findHash(K key) {
-        int index = getHashArray(getHashIndex(key)) - 1;
-        if (index != -1) {
-            Object entryKey = getKey(index);
-            if (compareKeys(key, entryKey)) {
-                return index;
-            } else {
-                Object entryValue = getRawValue(index);
-                if (entryValue instanceof CollisionLink) {
-                    return findWithCollision(key, (CollisionLink) entryValue);
-                }
-            }
-        }
-
-        return -1;
-    }
-
-    private int findWithCollision(K key, CollisionLink initialEntryValue) {
-        int index;
-        Object entryKey;
-        CollisionLink entryValue = initialEntryValue;
-        while (true) {
-            CollisionLink collisionLink = entryValue;
-            index = collisionLink.next;
-            entryKey = getKey(index);
-            if (compareKeys(key, entryKey)) {
-                return index;
-            } else {
-                Object value = getRawValue(index);
-                if (value instanceof CollisionLink) {
-                    entryValue = (CollisionLink) getRawValue(index);
-                } else {
-                    return -1;
-                }
-            }
-        }
-    }
-
-    private int getHashArray(int index) {
-        if (entries.length < LARGE_HASH_THRESHOLD) {
-            return (hashArray[index] & 0xFF);
-        } else if (entries.length < VERY_LARGE_HASH_THRESHOLD) {
-            int adjustedIndex = index << 1;
-            return (hashArray[adjustedIndex] & 0xFF) | ((hashArray[adjustedIndex + 1] & 0xFF) << 8);
-        } else {
-            int adjustedIndex = index << 2;
-            return (hashArray[adjustedIndex] & 0xFF) | ((hashArray[adjustedIndex + 1] & 0xFF) << 8) | ((hashArray[adjustedIndex + 2] & 0xFF) << 16) | ((hashArray[adjustedIndex + 3] & 0xFF) << 24);
-        }
-    }
-
-    private void setHashArray(int index, int value) {
-        if (entries.length < LARGE_HASH_THRESHOLD) {
-            hashArray[index] = (byte) value;
-        } else if (entries.length < VERY_LARGE_HASH_THRESHOLD) {
-            int adjustedIndex = index << 1;
-            hashArray[adjustedIndex] = (byte) value;
-            hashArray[adjustedIndex + 1] = (byte) (value >> 8);
-        } else {
-            int adjustedIndex = index << 2;
-            hashArray[adjustedIndex] = (byte) value;
-            hashArray[adjustedIndex + 1] = (byte) (value >> 8);
-            hashArray[adjustedIndex + 2] = (byte) (value >> 16);
-            hashArray[adjustedIndex + 3] = (byte) (value >> 24);
-        }
-    }
-
-    private int findAndRemoveHash(Object key) {
-        int hashIndex = getHashIndex(key);
-        int index = getHashArray(hashIndex) - 1;
-        if (index != -1) {
-            Object entryKey = getKey(index);
-            if (compareKeys(key, entryKey)) {
-                Object value = getRawValue(index);
-                int nextIndex = -1;
-                if (value instanceof CollisionLink) {
-                    CollisionLink collisionLink = (CollisionLink) value;
-                    nextIndex = collisionLink.next;
-                }
-                setHashArray(hashIndex, nextIndex + 1);
-                return index;
-            } else {
-                Object entryValue = getRawValue(index);
-                if (entryValue instanceof CollisionLink) {
-                    return findAndRemoveWithCollision(key, (CollisionLink) entryValue, index);
-                }
-            }
-        }
-
-        return -1;
-    }
-
-    private int findAndRemoveWithCollision(Object key, CollisionLink initialEntryValue, int initialIndexValue) {
-        int index;
-        Object entryKey;
-        CollisionLink entryValue = initialEntryValue;
-        int lastIndex = initialIndexValue;
-        while (true) {
-            CollisionLink collisionLink = entryValue;
-            index = collisionLink.next;
-            entryKey = getKey(index);
-            if (compareKeys(key, entryKey)) {
-                Object value = getRawValue(index);
-                if (value instanceof CollisionLink) {
-                    CollisionLink thisCollisionLink = (CollisionLink) value;
-                    setRawValue(lastIndex, new CollisionLink(collisionLink.value, thisCollisionLink.next));
-                } else {
-                    setRawValue(lastIndex, collisionLink.value);
-                }
-                return index;
-            } else {
-                Object value = getRawValue(index);
-                if (value instanceof CollisionLink) {
-                    entryValue = (CollisionLink) getRawValue(index);
-                    lastIndex = index;
-                } else {
-                    return -1;
-                }
-            }
-        }
-    }
-
-    private int getHashIndex(Object key) {
-        int hash;
-        if (strategy != null && strategy != Equivalence.DEFAULT) {
-            if (strategy == Equivalence.IDENTITY_WITH_SYSTEM_HASHCODE) {
-                hash = System.identityHashCode(key);
-            } else {
-                hash = strategy.hashCode(key);
-            }
-        } else {
-            hash = key.hashCode();
-        }
-        hash = hash ^ (hash >>> 16);
-        return hash & (getHashTableSize() - 1);
-    }
-
-    @SuppressWarnings("unchecked")
-    @Override
-    public V put(K key, V value) {
-        if (key == null) {
-            throw new UnsupportedOperationException("null not supported as key!");
-        }
-        int index = find(key);
-        if (index != -1) {
-            Object oldValue = getValue(index);
-            setValue(index, value);
-            return (V) oldValue;
-        }
-
-        int nextEntryIndex = totalEntries;
-        if (entries == null) {
-            entries = new Object[INITIAL_CAPACITY << 1];
-        } else if (entries.length == nextEntryIndex << 1) {
-            grow();
-
-            assert entries.length > totalEntries << 1;
-            // Can change if grow is actually compressing.
-            nextEntryIndex = totalEntries;
-        }
-
-        setKey(nextEntryIndex, key);
-        setValue(nextEntryIndex, value);
-        totalEntries++;
-
-        if (hasHashArray()) {
-            // Rehash on collision if hash table is more than three quarters full.
-            boolean rehashOnCollision = (getHashTableSize() < (size() + (size() >> 1)));
-            putHashEntry(key, nextEntryIndex, rehashOnCollision);
-        } else if (totalEntries > getHashThreshold()) {
-            createHash();
-        }
-
-        return null;
-    }
-
-    /**
-     * Number of entries above which a hash table should be constructed.
-     */
-    private int getHashThreshold() {
-        if (strategy == null || strategy == Equivalence.IDENTITY_WITH_SYSTEM_HASHCODE) {
-            return HASH_THRESHOLD_IDENTITY_COMPARE;
-        } else {
-            return HASH_THRESHOLD;
-        }
-    }
-
-    private void grow() {
-        int entriesLength = entries.length;
-        int newSize = (entriesLength >> 1) + Math.max(MIN_CAPACITY_INCREASE, entriesLength >> 2);
-        if (newSize > MAX_ELEMENT_COUNT) {
-            throw new UnsupportedOperationException("map grown too large!");
-        }
-        Object[] newEntries = new Object[newSize << 1];
-        System.arraycopy(entries, 0, newEntries, 0, entriesLength);
-        entries = newEntries;
-        if ((entriesLength < LARGE_HASH_THRESHOLD && newEntries.length >= LARGE_HASH_THRESHOLD) ||
-                        (entriesLength < VERY_LARGE_HASH_THRESHOLD && newEntries.length > VERY_LARGE_HASH_THRESHOLD)) {
-            // Rehash in order to change number of bits reserved for hash indices.
-            createHash();
-        }
-    }
-
-    /**
-     * Compresses the graph if there is a large number of deleted entries and returns the translated
-     * new next index.
-     */
-    private int maybeCompress(int nextIndex) {
-        if (entries.length != INITIAL_CAPACITY << 1 && deletedEntries >= (totalEntries >> 1) + (totalEntries >> 2)) {
-            return compressLarge(nextIndex);
-        }
-        return nextIndex;
-    }
-
-    /**
-     * Compresses the graph and returns the translated new next index.
-     */
-    private int compressLarge(int nextIndex) {
-        int size = INITIAL_CAPACITY;
-        int remaining = totalEntries - deletedEntries;
-
-        while (size <= remaining) {
-            size += Math.max(MIN_CAPACITY_INCREASE, size >> 1);
-        }
-
-        Object[] newEntries = new Object[size << 1];
-        int z = 0;
-        int newNextIndex = remaining;
-        for (int i = 0; i < totalEntries; ++i) {
-            Object key = getKey(i);
-            if (i == nextIndex) {
-                newNextIndex = z;
-            }
-            if (key != null) {
-                newEntries[z << 1] = key;
-                newEntries[(z << 1) + 1] = getValue(i);
-                z++;
-            }
-        }
-
-        this.entries = newEntries;
-        totalEntries = z;
-        deletedEntries = 0;
-        if (z <= getHashThreshold()) {
-            this.hashArray = null;
-        } else {
-            createHash();
-        }
-        return newNextIndex;
-    }
-
-    private int getHashTableSize() {
-        if (entries.length < LARGE_HASH_THRESHOLD) {
-            return hashArray.length;
-        } else if (entries.length < VERY_LARGE_HASH_THRESHOLD) {
-            return hashArray.length >> 1;
-        } else {
-            return hashArray.length >> 2;
-        }
-    }
-
-    private void createHash() {
-        int entryCount = size();
-
-        // Calculate smallest 2^n that is greater number of entries.
-        int size = getHashThreshold();
-        while (size <= entryCount) {
-            size <<= 1;
-        }
-
-        // Give extra size to avoid collisions.
-        size <<= 1;
-
-        if (this.entries.length >= VERY_LARGE_HASH_THRESHOLD) {
-            // Every entry has 4 bytes.
-            size <<= 2;
-        } else if (this.entries.length >= LARGE_HASH_THRESHOLD) {
-            // Every entry has 2 bytes.
-            size <<= 1;
-        } else {
-            // Entries are very small => give extra size to further reduce collisions.
-            size <<= 1;
-        }
-
-        hashArray = new byte[size];
-        for (int i = 0; i < totalEntries; i++) {
-            Object entryKey = getKey(i);
-            if (entryKey != null) {
-                putHashEntry(entryKey, i, false);
-            }
-        }
-    }
-
-    private void putHashEntry(Object key, int entryIndex, boolean rehashOnCollision) {
-        int hashIndex = getHashIndex(key);
-        int oldIndex = getHashArray(hashIndex) - 1;
-        if (oldIndex != -1 && rehashOnCollision) {
-            this.createHash();
-            return;
-        }
-        setHashArray(hashIndex, entryIndex + 1);
-        Object value = getRawValue(entryIndex);
-        if (oldIndex != -1) {
-            assert entryIndex != oldIndex : "this cannot happend and would create an endless collision link cycle";
-            if (value instanceof CollisionLink) {
-                CollisionLink collisionLink = (CollisionLink) value;
-                setRawValue(entryIndex, new CollisionLink(collisionLink.value, oldIndex));
-            } else {
-                setRawValue(entryIndex, new CollisionLink(getRawValue(entryIndex), oldIndex));
-            }
-        } else {
-            if (value instanceof CollisionLink) {
-                CollisionLink collisionLink = (CollisionLink) value;
-                setRawValue(entryIndex, collisionLink.value);
-            }
-        }
-    }
-
-    @Override
-    public int size() {
-        return totalEntries - deletedEntries;
-    }
-
-    @Override
-    public boolean containsKey(K key) {
-        return find(key) != -1;
-    }
-
-    @Override
-    public void clear() {
-        entries = null;
-        hashArray = null;
-        totalEntries = deletedEntries = 0;
-    }
-
-    private boolean hasHashArray() {
-        return hashArray != null;
-    }
-
-    @SuppressWarnings("unchecked")
-    @Override
-    public V removeKey(K key) {
-        if (key == null) {
-            throw new UnsupportedOperationException("null not supported as key!");
-        }
-        int index;
-        if (hasHashArray()) {
-            index = this.findAndRemoveHash(key);
-        } else {
-            index = this.findLinear(key);
-        }
-
-        if (index != -1) {
-            Object value = getValue(index);
-            remove(index);
-            return (V) value;
-        }
-        return null;
-    }
-
-    /**
-     * Removes the element at the specific index and returns the index of the next element. This can
-     * be a different value if graph compression was triggered.
-     */
-    private int remove(int indexToRemove) {
-        int index = indexToRemove;
-        int entriesAfterIndex = totalEntries - index - 1;
-        int result = index + 1;
-
-        // Without hash array, compress immediately.
-        if (entriesAfterIndex <= COMPRESS_IMMEDIATE_CAPACITY && !hasHashArray()) {
-            while (index < totalEntries - 1) {
-                setKey(index, getKey(index + 1));
-                setRawValue(index, getRawValue(index + 1));
-                index++;
-            }
-            result--;
-        }
-
-        setKey(index, null);
-        setRawValue(index, null);
-        if (index == totalEntries - 1) {
-            // Make sure last element is always non-null.
-            totalEntries--;
-            while (index > 0 && getKey(index - 1) == null) {
-                totalEntries--;
-                deletedEntries--;
-                index--;
-            }
-        } else {
-            deletedEntries++;
-            result = maybeCompress(result);
-        }
-
-        return result;
-    }
-
-    private abstract class SparseMapIterator<E> implements Iterator<E> {
-
-        protected int current;
-
-        @Override
-        public boolean hasNext() {
-            return current < totalEntries;
-        }
-
-        @Override
-        public void remove() {
-            if (hasHashArray()) {
-                EconomicMapImpl.this.findAndRemoveHash(getKey(current - 1));
-            }
-            current = EconomicMapImpl.this.remove(current - 1);
-        }
-    }
-
-    @Override
-    public Iterable<V> getValues() {
-        return new Iterable<V>() {
-            @Override
-            public Iterator<V> iterator() {
-                return new SparseMapIterator<V>() {
-                    @SuppressWarnings("unchecked")
-                    @Override
-                    public V next() {
-                        Object result;
-                        while (true) {
-                            result = getValue(current);
-                            if (result == null && getKey(current) == null) {
-                                // values can be null, double-check if key is also null
-                                current++;
-                            } else {
-                                current++;
-                                break;
-                            }
-                        }
-                        return (V) result;
-                    }
-                };
-            }
-        };
-    }
-
-    @Override
-    public Iterable<K> getKeys() {
-        return this;
-    }
-
-    @Override
-    public boolean isEmpty() {
-        return this.size() == 0;
-    }
-
-    @Override
-    public MapCursor<K, V> getEntries() {
-        return new MapCursor<K, V>() {
-            int current = -1;
-
-            @Override
-            public boolean advance() {
-                current++;
-                if (current >= totalEntries) {
-                    return false;
-                } else {
-                    while (EconomicMapImpl.this.getKey(current) == null) {
-                        // Skip over null entries
-                        current++;
-                    }
-                    return true;
-                }
-            }
-
-            @SuppressWarnings("unchecked")
-            @Override
-            public K getKey() {
-                return (K) EconomicMapImpl.this.getKey(current);
-            }
-
-            @SuppressWarnings("unchecked")
-            @Override
-            public V getValue() {
-                return (V) EconomicMapImpl.this.getValue(current);
-            }
-
-            @Override
-            public void remove() {
-                if (hasHashArray()) {
-                    EconomicMapImpl.this.findAndRemoveHash(EconomicMapImpl.this.getKey(current));
-                }
-                current = EconomicMapImpl.this.remove(current) - 1;
-            }
-        };
-    }
-
-    @SuppressWarnings("unchecked")
-    @Override
-    public void replaceAll(BiFunction<? super K, ? super V, ? extends V> function) {
-        for (int i = 0; i < totalEntries; i++) {
-            Object entryKey = getKey(i);
-            if (entryKey != null) {
-                Object newValue = function.apply((K) entryKey, (V) getValue(i));
-                setValue(i, newValue);
-            }
-        }
-    }
-
-    private Object getKey(int index) {
-        return entries[index << 1];
-    }
-
-    private void setKey(int index, Object newValue) {
-        entries[index << 1] = newValue;
-    }
-
-    private void setValue(int index, Object newValue) {
-        Object oldValue = getRawValue(index);
-        if (oldValue instanceof CollisionLink) {
-            CollisionLink collisionLink = (CollisionLink) oldValue;
-            setRawValue(index, new CollisionLink(newValue, collisionLink.next));
-        } else {
-            setRawValue(index, newValue);
-        }
-    }
-
-    private void setRawValue(int index, Object newValue) {
-        entries[(index << 1) + 1] = newValue;
-    }
-
-    private Object getRawValue(int index) {
-        return entries[(index << 1) + 1];
-    }
-
-    private Object getValue(int index) {
-        Object object = getRawValue(index);
-        if (object instanceof CollisionLink) {
-            return ((CollisionLink) object).value;
-        }
-        return object;
-    }
-
-    @Override
-    public String toString() {
-        StringBuilder builder = new StringBuilder();
-        builder.append("map(size=").append(size()).append(", {");
-        MapCursor<K, V> cursor = getEntries();
-        while (cursor.advance()) {
-            builder.append("(").append(cursor.getKey()).append(",").append(cursor.getValue()).append("),");
-        }
-        builder.append("})");
-        return builder.toString();
-    }
-
-    @Override
-    public Iterator<K> iterator() {
-        return new SparseMapIterator<K>() {
-            @SuppressWarnings("unchecked")
-            @Override
-            public K next() {
-                Object result;
-                while ((result = getKey(current++)) == null) {
-                    // skip null entries
-                }
-                return (K) result;
-            }
-        };
-    }
-
-    @Override
-    public boolean contains(K element) {
-        return containsKey(element);
-    }
-
-    @SuppressWarnings("unchecked")
-    @Override
-    public boolean add(K element) {
-        return put(element, (V) element) == null;
-    }
-
-    @Override
-    public void remove(K element) {
-        removeKey(element);
-    }
-}
--- a/src/jdk.internal.vm.compiler/share/classes/org.graalvm.word/.checkstyle_checks.xml	Fri Feb 16 12:24:38 2018 -0800
+++ b/src/jdk.internal.vm.compiler/share/classes/org.graalvm.word/.checkstyle_checks.xml	Fri Feb 16 13:49:07 2018 -0800
@@ -40,7 +40,7 @@
       <property name="tokens" value="ARRAY_INIT,BNOT,DEC,DOT,INC,LNOT,UNARY_MINUS,UNARY_PLUS"/>
     </module>
     <module name="NoWhitespaceBefore">
-      <property name="tokens" value="SEMI,DOT,POST_DEC,POST_INC"/>
+      <property name="tokens" value="SEMI,POST_DEC,POST_INC"/>
     </module>
     <module name="ParenPad"/>
     <module name="TypecastParenPad">
--- a/src/jdk.jartool/share/classes/sun/security/tools/jarsigner/Main.java	Fri Feb 16 12:24:38 2018 -0800
+++ b/src/jdk.jartool/share/classes/sun/security/tools/jarsigner/Main.java	Fri Feb 16 13:49:07 2018 -0800
@@ -30,6 +30,7 @@
 import java.security.cert.CertPathValidatorException;
 import java.security.cert.PKIXBuilderParameters;
 import java.util.*;
+import java.util.stream.Collectors;
 import java.util.zip.*;
 import java.util.jar.*;
 import java.net.URI;
@@ -92,6 +93,7 @@
     private static final String P11KEYSTORE = "PKCS11";
 
     private static final long SIX_MONTHS = 180*24*60*60*1000L; //milliseconds
+    private static final long ONE_YEAR = 366*24*60*60*1000L;
 
     private static final DisabledAlgorithmConstraints DISABLED_CHECK =
             new DisabledAlgorithmConstraints(
@@ -102,6 +104,13 @@
     private static final Set<CryptoPrimitive> SIG_PRIMITIVE_SET = Collections
             .unmodifiableSet(EnumSet.of(CryptoPrimitive.SIGNATURE));
 
+    static final String VERSION = "1.0";
+
+    static final int IN_KEYSTORE = 0x01;        // signer is in keystore
+    static final int NOT_ALIAS = 0x04;          // alias list is NOT empty and
+    // signer is not in alias list
+    static final int SIGNED_BY_ALIAS = 0x08;    // signer is in alias list
+
     // Attention:
     // This is the entry that get launched by the security tool jarsigner.
     public static void main(String args[]) throws Exception {
@@ -109,13 +118,6 @@
         js.run(args);
     }
 
-    static final String VERSION = "1.0";
-
-    static final int IN_KEYSTORE = 0x01;        // signer is in keystore
-    static final int NOT_ALIAS = 0x04;          // alias list is NOT empty and
-                                                // signer is not in alias list
-    static final int SIGNED_BY_ALIAS = 0x08;    // signer is in alias list
-
     X509Certificate[] certChain;    // signer's cert chain (when composing)
     PrivateKey privateKey;          // private key
     KeyStore store;                 // the keystore specified by -keystore
@@ -160,8 +162,16 @@
 
     // Informational warnings
     private boolean hasExpiringCert = false;
-    private boolean noTimestamp = false;
-    private Date expireDate = new Date(0L);     // used in noTimestamp warning
+    private boolean hasExpiringTsaCert = false;
+    private boolean noTimestamp = true;
+
+    // Expiration date. The value could be null if signed by a trusted cert.
+    private Date expireDate = null;
+    private Date tsaExpireDate = null;
+
+    // If there is a time stamp block inside the PKCS7 block file
+    boolean hasTimestampBlock = false;
+
 
     // Severe warnings.
 
@@ -174,6 +184,7 @@
 
     private int weakAlg = 0; // 1. digestalg, 2. sigalg, 4. tsadigestalg
     private boolean hasExpiredCert = false;
+    private boolean hasExpiredTsaCert = false;
     private boolean notYetValidCert = false;
     private boolean chainNotValidated = false;
     private boolean tsaChainNotValidated = false;
@@ -191,6 +202,7 @@
     private boolean seeWeak = false;
 
     PKIXBuilderParameters pkixParameters;
+    Set<X509Certificate> trustedCerts = new HashSet<>();
 
     public void run(String args[]) {
         try {
@@ -277,8 +289,8 @@
 
         if (strict) {
             int exitCode = 0;
-            if (weakAlg != 0 || chainNotValidated
-                    || hasExpiredCert || notYetValidCert || signerSelfSigned) {
+            if (weakAlg != 0 || chainNotValidated || hasExpiredCert
+                    || hasExpiredTsaCert || notYetValidCert || signerSelfSigned) {
                 exitCode |= 4;
             }
             if (badKeyUsage || badExtendedKeyUsage || badNetscapeCertType) {
@@ -879,14 +891,12 @@
             }
 
             // If signer is a trusted cert or private entry in user's own
-            // keystore, it can be self-signed.
-            if (!aliasNotInStore) {
+            // keystore, it can be self-signed. Please note aliasNotInStore
+            // is always false when ~/.keystore is used.
+            if (!aliasNotInStore && keystore != null) {
                 signerSelfSigned = false;
             }
 
-            // If there is a time stamp block inside the PKCS7 block file
-            boolean hasTimestampBlock = false;
-
             // Even if the verbose option is not specified, all out strings
             // must be generated so seeWeak can be updated.
             if (!digestMap.isEmpty()
@@ -986,118 +996,7 @@
                     System.out.println(rb.getString("jar.is.unsigned"));
                 }
             } else {
-                boolean warningAppeared = false;
-                boolean errorAppeared = false;
-                if (badKeyUsage || badExtendedKeyUsage || badNetscapeCertType ||
-                        notYetValidCert || chainNotValidated || hasExpiredCert ||
-                        hasUnsignedEntry || signerSelfSigned || (weakAlg != 0) ||
-                        aliasNotInStore || notSignedByAlias || tsaChainNotValidated) {
-
-                    if (strict) {
-                        System.out.println(rb.getString("jar.verified.with.signer.errors."));
-                        System.out.println();
-                        System.out.println(rb.getString("Error."));
-                        errorAppeared = true;
-                    } else {
-                        System.out.println(rb.getString("jar.verified."));
-                        System.out.println();
-                        System.out.println(rb.getString("Warning."));
-                        warningAppeared = true;
-                    }
-
-                    if (weakAlg != 0) {
-                        // In fact, jarsigner verification did not catch this
-                        // since it has not read the JarFile content itself.
-                        // Everything is done with JarFile API. The signing
-                        // history (digestMap etc) will show these info and
-                        // print out proper warnings.
-                    }
-
-                    if (badKeyUsage) {
-                        System.out.println(
-                            rb.getString("This.jar.contains.entries.whose.signer.certificate.s.KeyUsage.extension.doesn.t.allow.code.signing."));
-                    }
-
-                    if (badExtendedKeyUsage) {
-                        System.out.println(
-                            rb.getString("This.jar.contains.entries.whose.signer.certificate.s.ExtendedKeyUsage.extension.doesn.t.allow.code.signing."));
-                    }
-
-                    if (badNetscapeCertType) {
-                        System.out.println(
-                            rb.getString("This.jar.contains.entries.whose.signer.certificate.s.NetscapeCertType.extension.doesn.t.allow.code.signing."));
-                    }
-
-                    if (hasUnsignedEntry) {
-                        System.out.println(rb.getString(
-                            "This.jar.contains.unsigned.entries.which.have.not.been.integrity.checked."));
-                    }
-                    if (hasExpiredCert) {
-                        System.out.println(rb.getString(
-                            "This.jar.contains.entries.whose.signer.certificate.has.expired."));
-                    }
-                    if (notYetValidCert) {
-                        System.out.println(rb.getString(
-                            "This.jar.contains.entries.whose.signer.certificate.is.not.yet.valid."));
-                    }
-
-                    if (chainNotValidated) {
-                        System.out.println(String.format(
-                                rb.getString("This.jar.contains.entries.whose.certificate.chain.is.invalid.reason.1"),
-                                chainNotValidatedReason.getLocalizedMessage()));
-                    }
-
-                    if (tsaChainNotValidated) {
-                        System.out.println(String.format(
-                                rb.getString("This.jar.contains.entries.whose.tsa.certificate.chain.is.invalid.reason.1"),
-                                tsaChainNotValidatedReason.getLocalizedMessage()));
-                    }
-
-                    if (notSignedByAlias) {
-                        System.out.println(
-                                rb.getString("This.jar.contains.signed.entries.which.is.not.signed.by.the.specified.alias.es."));
-                    }
-
-                    if (aliasNotInStore) {
-                        System.out.println(rb.getString("This.jar.contains.signed.entries.that.s.not.signed.by.alias.in.this.keystore."));
-                    }
-
-                    if (signerSelfSigned) {
-                        System.out.println(rb.getString(
-                                "This.jar.contains.entries.whose.signer.certificate.is.self.signed."));
-                    }
-                } else {
-                    System.out.println(rb.getString("jar.verified."));
-                }
-                if (hasExpiringCert || noTimestamp) {
-                    if (!warningAppeared) {
-                        System.out.println();
-                        System.out.println(rb.getString("Warning."));
-                        warningAppeared = true;
-                    }
-                    if (hasExpiringCert) {
-                        System.out.println(rb.getString(
-                                "This.jar.contains.entries.whose.signer.certificate.will.expire.within.six.months."));
-                    }
-                    if (noTimestamp) {
-                        if (hasTimestampBlock) {
-                            // JarSigner API has not seen the timestamp,
-                            // might have ignored it due to weak alg, etc.
-                            System.out.println(
-                                    String.format(rb.getString("bad.timestamp.verifying"), expireDate));
-                        } else {
-                            System.out.println(
-                                    String.format(rb.getString("no.timestamp.verifying"), expireDate));
-                        }
-                    }
-                }
-                if (warningAppeared || errorAppeared) {
-                    if (! (verbose != null && showcerts)) {
-                        System.out.println();
-                        System.out.println(rb.getString(
-                                "Re.run.with.the.verbose.and.certs.options.for.more.details."));
-                    }
-                }
+                displayMessagesAndResult(false);
             }
             return;
         } catch (Exception e) {
@@ -1114,6 +1013,230 @@
         System.exit(1);
     }
 
+    private void displayMessagesAndResult(boolean isSigning) {
+        String result;
+        List<String> errors = new ArrayList<>();
+        List<String> warnings = new ArrayList<>();
+        List<String> info = new ArrayList<>();
+
+        boolean signerNotExpired = expireDate == null
+                || expireDate.after(new Date());
+
+        if (badKeyUsage || badExtendedKeyUsage || badNetscapeCertType ||
+                notYetValidCert || chainNotValidated || hasExpiredCert ||
+                hasUnsignedEntry || signerSelfSigned || (weakAlg != 0) ||
+                aliasNotInStore || notSignedByAlias ||
+                tsaChainNotValidated ||
+                (hasExpiredTsaCert && !signerNotExpired)) {
+
+            if (strict) {
+                result = rb.getString(isSigning
+                        ? "jar.signed.with.signer.errors."
+                        : "jar.verified.with.signer.errors.");
+            } else {
+                result = rb.getString(isSigning
+                        ? "jar.signed."
+                        : "jar.verified.");
+            }
+
+            if (badKeyUsage) {
+                errors.add(rb.getString(isSigning
+                        ? "The.signer.certificate.s.KeyUsage.extension.doesn.t.allow.code.signing."
+                        : "This.jar.contains.entries.whose.signer.certificate.s.KeyUsage.extension.doesn.t.allow.code.signing."));
+            }
+
+            if (badExtendedKeyUsage) {
+                errors.add(rb.getString(isSigning
+                        ? "The.signer.certificate.s.ExtendedKeyUsage.extension.doesn.t.allow.code.signing."
+                        : "This.jar.contains.entries.whose.signer.certificate.s.ExtendedKeyUsage.extension.doesn.t.allow.code.signing."));
+            }
+
+            if (badNetscapeCertType) {
+                errors.add(rb.getString(isSigning
+                        ? "The.signer.certificate.s.NetscapeCertType.extension.doesn.t.allow.code.signing."
+                        : "This.jar.contains.entries.whose.signer.certificate.s.NetscapeCertType.extension.doesn.t.allow.code.signing."));
+            }
+
+            // only in verifying
+            if (hasUnsignedEntry) {
+                errors.add(rb.getString(
+                        "This.jar.contains.unsigned.entries.which.have.not.been.integrity.checked."));
+            }
+            if (hasExpiredCert) {
+                errors.add(rb.getString(isSigning
+                        ? "The.signer.certificate.has.expired."
+                        : "This.jar.contains.entries.whose.signer.certificate.has.expired."));
+            }
+            if (notYetValidCert) {
+                errors.add(rb.getString(isSigning
+                        ? "The.signer.certificate.is.not.yet.valid."
+                        : "This.jar.contains.entries.whose.signer.certificate.is.not.yet.valid."));
+            }
+
+            if (chainNotValidated) {
+                errors.add(String.format(rb.getString(isSigning
+                                ? "The.signer.s.certificate.chain.is.invalid.reason.1"
+                                : "This.jar.contains.entries.whose.certificate.chain.is.invalid.reason.1"),
+                        chainNotValidatedReason.getLocalizedMessage()));
+            }
+
+            if (hasExpiredTsaCert) {
+                errors.add(rb.getString("The.timestamp.has.expired."));
+            }
+            if (tsaChainNotValidated) {
+                errors.add(String.format(rb.getString(isSigning
+                                ? "The.tsa.certificate.chain.is.invalid.reason.1"
+                                : "This.jar.contains.entries.whose.tsa.certificate.chain.is.invalid.reason.1"),
+                        tsaChainNotValidatedReason.getLocalizedMessage()));
+            }
+
+            // only in verifying
+            if (notSignedByAlias) {
+                errors.add(
+                        rb.getString("This.jar.contains.signed.entries.which.is.not.signed.by.the.specified.alias.es."));
+            }
+
+            // only in verifying
+            if (aliasNotInStore) {
+                errors.add(rb.getString("This.jar.contains.signed.entries.that.s.not.signed.by.alias.in.this.keystore."));
+            }
+
+            if (signerSelfSigned) {
+                errors.add(rb.getString(isSigning
+                        ? "The.signer.s.certificate.is.self.signed."
+                        : "This.jar.contains.entries.whose.signer.certificate.is.self.signed."));
+            }
+
+            // weakAlg only detected in signing. The jar file is
+            // now simply treated unsigned in verifying.
+            if ((weakAlg & 1) == 1) {
+                errors.add(String.format(
+                        rb.getString("The.1.algorithm.specified.for.the.2.option.is.considered.a.security.risk."),
+                        digestalg, "-digestalg"));
+            }
+
+            if ((weakAlg & 2) == 2) {
+                errors.add(String.format(
+                        rb.getString("The.1.algorithm.specified.for.the.2.option.is.considered.a.security.risk."),
+                        sigalg, "-sigalg"));
+            }
+            if ((weakAlg & 4) == 4) {
+                errors.add(String.format(
+                        rb.getString("The.1.algorithm.specified.for.the.2.option.is.considered.a.security.risk."),
+                        tSADigestAlg, "-tsadigestalg"));
+            }
+            if ((weakAlg & 8) == 8) {
+                errors.add(String.format(
+                        rb.getString("The.1.signing.key.has.a.keysize.of.2.which.is.considered.a.security.risk."),
+                        privateKey.getAlgorithm(), KeyUtil.getKeySize(privateKey)));
+            }
+        } else {
+            result = rb.getString(isSigning ? "jar.signed." : "jar.verified.");
+        }
+
+        if (hasExpiredTsaCert) {
+            // No need to warn about expiring if already expired
+            hasExpiringTsaCert = false;
+        }
+
+        if (hasExpiringCert ||
+                (hasExpiringTsaCert  && expireDate != null) ||
+                (noTimestamp && expireDate != null) ||
+                (hasExpiredTsaCert && signerNotExpired)) {
+
+            if (hasExpiredTsaCert && signerNotExpired) {
+                if (expireDate != null) {
+                    warnings.add(String.format(
+                            rb.getString("The.timestamp.expired.1.but.usable.2"),
+                            tsaExpireDate,
+                            expireDate));
+                }
+                // Reset the flag so exit code is 0
+                hasExpiredTsaCert = false;
+            }
+            if (hasExpiringCert) {
+                warnings.add(rb.getString(isSigning
+                        ? "The.signer.certificate.will.expire.within.six.months."
+                        : "This.jar.contains.entries.whose.signer.certificate.will.expire.within.six.months."));
+            }
+            if (hasExpiringTsaCert && expireDate != null) {
+                if (expireDate.after(tsaExpireDate)) {
+                    warnings.add(String.format(rb.getString(
+                            "The.timestamp.will.expire.within.one.year.on.1.but.2"), tsaExpireDate, expireDate));
+                } else {
+                    warnings.add(String.format(rb.getString(
+                            "The.timestamp.will.expire.within.one.year.on.1"), tsaExpireDate));
+                }
+            }
+            if (noTimestamp && expireDate != null) {
+                if (hasTimestampBlock) {
+                    warnings.add(String.format(rb.getString(isSigning
+                            ? "invalid.timestamp.signing"
+                            : "bad.timestamp.verifying"), expireDate));
+                } else {
+                    warnings.add(String.format(rb.getString(isSigning
+                            ? "no.timestamp.signing"
+                            : "no.timestamp.verifying"), expireDate));
+                }
+            }
+        }
+
+        System.out.println(result);
+        if (strict) {
+            if (!errors.isEmpty()) {
+                System.out.println();
+                System.out.println(rb.getString("Error."));
+                errors.forEach(System.out::println);
+            }
+            if (!warnings.isEmpty()) {
+                System.out.println();
+                System.out.println(rb.getString("Warning."));
+                warnings.forEach(System.out::println);
+            }
+        } else {
+            if (!errors.isEmpty() || !warnings.isEmpty()) {
+                System.out.println();
+                System.out.println(rb.getString("Warning."));
+                errors.forEach(System.out::println);
+                warnings.forEach(System.out::println);
+            }
+        }
+        if (!isSigning && (!errors.isEmpty() || !warnings.isEmpty())) {
+            if (! (verbose != null && showcerts)) {
+                System.out.println();
+                System.out.println(rb.getString(
+                        "Re.run.with.the.verbose.and.certs.options.for.more.details."));
+            }
+        }
+
+        if (isSigning || verbose != null) {
+            // Always print out expireDate, unless expired or expiring.
+            if (!hasExpiringCert && !hasExpiredCert
+                    && expireDate != null && signerNotExpired) {
+                info.add(String.format(rb.getString(
+                        "The.signer.certificate.will.expire.on.1."), expireDate));
+            }
+            if (!noTimestamp) {
+                if (!hasExpiringTsaCert && !hasExpiredTsaCert && tsaExpireDate != null) {
+                    if (signerNotExpired) {
+                        info.add(String.format(rb.getString(
+                                "The.timestamp.will.expire.on.1."), tsaExpireDate));
+                    } else {
+                        info.add(String.format(rb.getString(
+                                "signer.cert.expired.1.but.timestamp.good.2."),
+                                expireDate,
+                                tsaExpireDate));
+                    }
+                }
+            }
+        }
+
+        if (!info.isEmpty()) {
+            System.out.println();
+            info.forEach(System.out::println);
+        }
+    }
+
     private String withWeak(String alg, Set<CryptoPrimitive> primitiveSet) {
         if (DISABLED_CHECK.permits(primitiveSet, alg, null)) {
             return alg;
@@ -1152,8 +1275,9 @@
      *
      * Note: no newline character at the end.
      *
-     * When isTsCert is true, this method sets global flags like hasExpiredCert,
-     * notYetValidCert, badKeyUsage, badExtendedKeyUsage, badNetscapeCertType.
+     * This method sets global flags like hasExpiringCert, hasExpiredCert,
+     * notYetValidCert, badKeyUsage, badExtendedKeyUsage, badNetscapeCertType,
+     * hasExpiringTsaCert, hasExpiredTsaCert.
      *
      * @param isTsCert true if c is in the TSA cert chain, false otherwise.
      * @param checkUsage true to check code signer keyUsage
@@ -1182,55 +1306,75 @@
         if (x509Cert != null) {
 
             certStr.append("\n").append(tab).append("[");
-            Date notAfter = x509Cert.getNotAfter();
-            try {
-                boolean printValidity = true;
-                if (timestamp == null) {
-                    if (expireDate.getTime() == 0 || expireDate.after(notAfter)) {
-                        expireDate = notAfter;
+
+            if (trustedCerts.contains(x509Cert)) {
+                certStr.append(rb.getString("trusted.certificate"));
+            } else {
+                Date notAfter = x509Cert.getNotAfter();
+                try {
+                    boolean printValidity = true;
+                    if (isTsCert) {
+                        if (tsaExpireDate == null || tsaExpireDate.after(notAfter)) {
+                            tsaExpireDate = notAfter;
+                        }
+                    } else {
+                        if (expireDate == null || expireDate.after(notAfter)) {
+                            expireDate = notAfter;
+                        }
                     }
-                    x509Cert.checkValidity();
-                    // test if cert will expire within six months
-                    if (notAfter.getTime() < System.currentTimeMillis() + SIX_MONTHS) {
-                        if (!isTsCert) hasExpiringCert = true;
-                        if (expiringTimeForm == null) {
-                            expiringTimeForm = new MessageFormat(
-                                rb.getString("certificate.will.expire.on"));
+                    if (timestamp == null) {
+                        x509Cert.checkValidity();
+                        // test if cert will expire within six months (or one year for tsa)
+                        long age = isTsCert ? ONE_YEAR : SIX_MONTHS;
+                        if (notAfter.getTime() < System.currentTimeMillis() + age) {
+                            if (isTsCert) {
+                                hasExpiringTsaCert = true;
+                            } else {
+                                hasExpiringCert = true;
+                            }
+                            if (expiringTimeForm == null) {
+                                expiringTimeForm = new MessageFormat(
+                                        rb.getString("certificate.will.expire.on"));
+                            }
+                            Object[] source = {notAfter};
+                            certStr.append(expiringTimeForm.format(source));
+                            printValidity = false;
+                        }
+                    } else {
+                        x509Cert.checkValidity(timestamp);
+                    }
+                    if (printValidity) {
+                        if (validityTimeForm == null) {
+                            validityTimeForm = new MessageFormat(
+                                    rb.getString("certificate.is.valid.from"));
                         }
-                        Object[] source = { notAfter };
-                        certStr.append(expiringTimeForm.format(source));
-                        printValidity = false;
+                        Object[] source = {x509Cert.getNotBefore(), notAfter};
+                        certStr.append(validityTimeForm.format(source));
+                    }
+                } catch (CertificateExpiredException cee) {
+                    if (isTsCert) {
+                        hasExpiredTsaCert = true;
+                    } else {
+                        hasExpiredCert = true;
                     }
-                } else {
-                    x509Cert.checkValidity(timestamp);
+
+                    if (expiredTimeForm == null) {
+                        expiredTimeForm = new MessageFormat(
+                                rb.getString("certificate.expired.on"));
+                    }
+                    Object[] source = {notAfter};
+                    certStr.append(expiredTimeForm.format(source));
+
+                } catch (CertificateNotYetValidException cnyve) {
+                    if (!isTsCert) notYetValidCert = true;
+
+                    if (notYetTimeForm == null) {
+                        notYetTimeForm = new MessageFormat(
+                                rb.getString("certificate.is.not.valid.until"));
+                    }
+                    Object[] source = {x509Cert.getNotBefore()};
+                    certStr.append(notYetTimeForm.format(source));
                 }
-                if (printValidity) {
-                    if (validityTimeForm == null) {
-                        validityTimeForm = new MessageFormat(
-                            rb.getString("certificate.is.valid.from"));
-                    }
-                    Object[] source = { x509Cert.getNotBefore(), notAfter };
-                    certStr.append(validityTimeForm.format(source));
-                }
-            } catch (CertificateExpiredException cee) {
-                if (!isTsCert) hasExpiredCert = true;
-
-                if (expiredTimeForm == null) {
-                    expiredTimeForm = new MessageFormat(
-                        rb.getString("certificate.expired.on"));
-                }
-                Object[] source = { notAfter };
-                certStr.append(expiredTimeForm.format(source));
-
-            } catch (CertificateNotYetValidException cnyve) {
-                if (!isTsCert) notYetValidCert = true;
-
-                if (notYetTimeForm == null) {
-                    notYetTimeForm = new MessageFormat(
-                        rb.getString("certificate.is.not.valid.until"));
-                }
-                Object[] source = { x509Cert.getNotBefore() };
-                certStr.append(notYetTimeForm.format(source));
             }
             certStr.append("]");
 
@@ -1446,8 +1590,6 @@
             if (tSAPolicyID != null) {
                 builder.setProperty("tsaPolicyId", tSAPolicyID);
             }
-        } else {
-            noTimestamp = true;
         }
 
         if (altSignerClass != null) {
@@ -1519,160 +1661,64 @@
             error(failedMessage, failedCause);
         }
 
+        if (verbose != null) {
+            System.out.println();
+        }
+
         // The JarSigner API always accepts the timestamp received.
         // We need to extract the certs from the signed jar to
         // validate it.
-        if (!noTimestamp) {
-            try (JarFile check = new JarFile(signedJarFile)) {
-                PKCS7 p7 = new PKCS7(check.getInputStream(check.getEntry(
-                        "META-INF/" + sigfile + "." + privateKey.getAlgorithm())));
+        try (JarFile check = new JarFile(signedJarFile)) {
+            PKCS7 p7 = new PKCS7(check.getInputStream(check.getEntry(
+                    "META-INF/" + sigfile + "." + privateKey.getAlgorithm())));
+            Timestamp ts = null;
+            try {
                 SignerInfo si = p7.getSignerInfos()[0];
-                PKCS7 tsToken = si.getTsToken();
-                SignerInfo tsSi = tsToken.getSignerInfos()[0];
-                try {
-                    validateCertChain(Validator.VAR_TSA_SERVER,
-                            tsSi.getCertificateChain(tsToken), null);
-                } catch (Exception e) {
-                    tsaChainNotValidated = true;
-                    tsaChainNotValidatedReason = e;
+                if (si.getTsToken() != null) {
+                    hasTimestampBlock = true;
                 }
+                ts = si.getTimestamp();
             } catch (Exception e) {
-                if (debug) {
-                    e.printStackTrace();
+                tsaChainNotValidated = true;
+                tsaChainNotValidatedReason = e;
+            }
+            // Spaces before the ">>> Signer" and other lines are different
+            String result = certsAndTSInfo("", "    ", Arrays.asList(certChain), ts);
+            if (verbose != null) {
+                System.out.println(result);
+            }
+        } catch (Exception e) {
+            if (debug) {
+                e.printStackTrace();
+            }
+        }
+
+        if (signedjar == null) {
+            // attempt an atomic rename. If that fails,
+            // rename the original jar file, then the signed
+            // one, then delete the original.
+            if (!signedJarFile.renameTo(jarFile)) {
+                File origJar = new File(jarName+".orig");
+
+                if (jarFile.renameTo(origJar)) {
+                    if (signedJarFile.renameTo(jarFile)) {
+                        origJar.delete();
+                    } else {
+                        MessageFormat form = new MessageFormat(rb.getString
+                    ("attempt.to.rename.signedJarFile.to.jarFile.failed"));
+                        Object[] source = {signedJarFile, jarFile};
+                        error(form.format(source));
+                    }
+                } else {
+                    MessageFormat form = new MessageFormat(rb.getString
+                        ("attempt.to.rename.jarFile.to.origJar.failed"));
+                    Object[] source = {jarFile, origJar};
+                    error(form.format(source));
                 }
             }
         }
 
-        // no IOException thrown in the follow try clause, so disable
-        // the try clause.
-        // try {
-            if (signedjar == null) {
-                // attempt an atomic rename. If that fails,
-                // rename the original jar file, then the signed
-                // one, then delete the original.
-                if (!signedJarFile.renameTo(jarFile)) {
-                    File origJar = new File(jarName+".orig");
-
-                    if (jarFile.renameTo(origJar)) {
-                        if (signedJarFile.renameTo(jarFile)) {
-                            origJar.delete();
-                        } else {
-                            MessageFormat form = new MessageFormat(rb.getString
-                        ("attempt.to.rename.signedJarFile.to.jarFile.failed"));
-                            Object[] source = {signedJarFile, jarFile};
-                            error(form.format(source));
-                        }
-                    } else {
-                        MessageFormat form = new MessageFormat(rb.getString
-                            ("attempt.to.rename.jarFile.to.origJar.failed"));
-                        Object[] source = {jarFile, origJar};
-                        error(form.format(source));
-                    }
-                }
-            }
-
-            boolean warningAppeared = false;
-            if (weakAlg != 0 || badKeyUsage || badExtendedKeyUsage
-                    || badNetscapeCertType || notYetValidCert
-                    || chainNotValidated || tsaChainNotValidated
-                    || hasExpiredCert || signerSelfSigned) {
-                if (strict) {
-                    System.out.println(rb.getString("jar.signed.with.signer.errors."));
-                    System.out.println();
-                    System.out.println(rb.getString("Error."));
-                } else {
-                    System.out.println(rb.getString("jar.signed."));
-                    System.out.println();
-                    System.out.println(rb.getString("Warning."));
-                    warningAppeared = true;
-                }
-
-                if (badKeyUsage) {
-                    System.out.println(
-                        rb.getString("The.signer.certificate.s.KeyUsage.extension.doesn.t.allow.code.signing."));
-                }
-
-                if (badExtendedKeyUsage) {
-                    System.out.println(
-                        rb.getString("The.signer.certificate.s.ExtendedKeyUsage.extension.doesn.t.allow.code.signing."));
-                }
-
-                if (badNetscapeCertType) {
-                    System.out.println(
-                        rb.getString("The.signer.certificate.s.NetscapeCertType.extension.doesn.t.allow.code.signing."));
-                }
-
-                if (hasExpiredCert) {
-                    System.out.println(
-                        rb.getString("The.signer.certificate.has.expired."));
-                } else if (notYetValidCert) {
-                    System.out.println(
-                        rb.getString("The.signer.certificate.is.not.yet.valid."));
-                }
-
-                if (chainNotValidated) {
-                    System.out.println(String.format(
-                            rb.getString("The.signer.s.certificate.chain.is.invalid.reason.1"),
-                            chainNotValidatedReason.getLocalizedMessage()));
-                }
-
-                if (tsaChainNotValidated) {
-                    System.out.println(String.format(
-                            rb.getString("The.tsa.certificate.chain.is.invalid.reason.1"),
-                            tsaChainNotValidatedReason.getLocalizedMessage()));
-                }
-
-                if (signerSelfSigned) {
-                    System.out.println(
-                            rb.getString("The.signer.s.certificate.is.self.signed."));
-                }
-
-                if ((weakAlg & 1) == 1) {
-                    System.out.println(String.format(
-                            rb.getString("The.1.algorithm.specified.for.the.2.option.is.considered.a.security.risk."),
-                            digestalg, "-digestalg"));
-                }
-
-                if ((weakAlg & 2) == 2) {
-                    System.out.println(String.format(
-                            rb.getString("The.1.algorithm.specified.for.the.2.option.is.considered.a.security.risk."),
-                            sigalg, "-sigalg"));
-                }
-                if ((weakAlg & 4) == 4) {
-                    System.out.println(String.format(
-                            rb.getString("The.1.algorithm.specified.for.the.2.option.is.considered.a.security.risk."),
-                            tSADigestAlg, "-tsadigestalg"));
-                }
-                if ((weakAlg & 8) == 8) {
-                    System.out.println(String.format(
-                            rb.getString("The.1.signing.key.has.a.keysize.of.2.which.is.considered.a.security.risk."),
-                            privateKey.getAlgorithm(), KeyUtil.getKeySize(privateKey)));
-                }
-            } else {
-                System.out.println(rb.getString("jar.signed."));
-            }
-            if (hasExpiringCert || noTimestamp) {
-                if (!warningAppeared) {
-                    System.out.println();
-                    System.out.println(rb.getString("Warning."));
-                }
-
-                if (hasExpiringCert) {
-                    System.out.println(
-                            rb.getString("The.signer.certificate.will.expire.within.six.months."));
-                }
-
-                if (noTimestamp) {
-                    System.out.println(
-                            String.format(rb.getString("no.timestamp.signing"), expireDate));
-                }
-            }
-
-        // no IOException thrown in the above try clause, so disable
-        // the catch clause.
-        // } catch(IOException ioe) {
-        //     error(rb.getString("unable.to.sign.jar.")+ioe, ioe);
-        // }
+        displayMessagesAndResult(true);
     }
 
     /**
@@ -1691,31 +1737,57 @@
     Map<CodeSigner,String> cacheForSignerInfo = new IdentityHashMap<>();
 
     /**
-     * Returns a string of singer info, with a newline at the end
+     * Returns a string of signer info, with a newline at the end.
+     * Called by verifyJar().
      */
     private String signerInfo(CodeSigner signer, String tab) throws Exception {
         if (cacheForSignerInfo.containsKey(signer)) {
             return cacheForSignerInfo.get(signer);
         }
-        StringBuilder sb = new StringBuilder();
         List<? extends Certificate> certs = signer.getSignerCertPath().getCertificates();
-        // display the signature timestamp, if present
-        Date timestamp;
+        // signing time is only displayed on verification
         Timestamp ts = signer.getTimestamp();
+        String tsLine = "";
         if (ts != null) {
-            sb.append(printTimestamp(tab, ts));
-            sb.append('\n');
+            tsLine = printTimestamp(tab, ts) + "\n";
+        }
+        // Spaces before the ">>> Signer" and other lines are the same.
+
+        String result = certsAndTSInfo(tab, tab, certs, ts);
+        cacheForSignerInfo.put(signer, tsLine + result);
+        return result;
+    }
+
+    /**
+     * Fills info on certs and timestamp into a StringBuilder, sets
+     * warning flags (through printCert) and validates cert chains.
+     *
+     * @param tab1 spaces before the ">>> Signer" line
+     * @param tab2 spaces before the other lines
+     * @param certs the signer cert
+     * @param ts the timestamp, can be null
+     * @return the info as a string
+     */
+    private String certsAndTSInfo(
+            String tab1,
+            String tab2,
+            List<? extends Certificate> certs, Timestamp ts)
+            throws Exception {
+
+        Date timestamp;
+        if (ts != null) {
             timestamp = ts.getTimestamp();
+            noTimestamp = false;
         } else {
             timestamp = null;
-            noTimestamp = true;
         }
         // display the certificate(sb). The first one is end-entity cert and
         // its KeyUsage should be checked.
         boolean first = true;
-        sb.append(tab).append(rb.getString("...Signer")).append('\n');
+        StringBuilder sb = new StringBuilder();
+        sb.append(tab1).append(rb.getString("...Signer")).append('\n');
         for (Certificate c : certs) {
-            sb.append(printCert(false, tab, c, timestamp, first));
+            sb.append(printCert(false, tab2, c, timestamp, first));
             sb.append('\n');
             first = false;
         }
@@ -1724,13 +1796,13 @@
         } catch (Exception e) {
             chainNotValidated = true;
             chainNotValidatedReason = e;
-            sb.append(tab).append(rb.getString(".Invalid.certificate.chain."))
+            sb.append(tab2).append(rb.getString(".Invalid.certificate.chain."))
                     .append(e.getLocalizedMessage()).append("]\n");
         }
         if (ts != null) {
-            sb.append(tab).append(rb.getString("...TSA")).append('\n');
+            sb.append(tab1).append(rb.getString("...TSA")).append('\n');
             for (Certificate c : ts.getSignerCertPath().getCertificates()) {
-                sb.append(printCert(true, tab, c, timestamp, false));
+                sb.append(printCert(true, tab2, c, null, false));
                 sb.append('\n');
             }
             try {
@@ -1739,7 +1811,7 @@
             } catch (Exception e) {
                 tsaChainNotValidated = true;
                 tsaChainNotValidatedReason = e;
-                sb.append(tab).append(rb.getString(".Invalid.TSA.certificate.chain."))
+                sb.append(tab2).append(rb.getString(".Invalid.TSA.certificate.chain."))
                         .append(e.getLocalizedMessage()).append("]\n");
             }
         }
@@ -1747,9 +1819,8 @@
                 && KeyStoreUtil.isSelfSigned((X509Certificate)certs.get(0))) {
             signerSelfSigned = true;
         }
-        String result = sb.toString();
-        cacheForSignerInfo.put(signer, result);
-        return result;
+
+        return sb.toString();
     }
 
     void loadKeyStore(String keyStoreName, boolean prompt) {
@@ -1760,7 +1831,6 @@
         }
 
         try {
-            Set<TrustAnchor> tas = new HashSet<>();
             try {
                 KeyStore caks = KeyStoreUtil.getCacertsKeyStore();
                 if (caks != null) {
@@ -1768,7 +1838,7 @@
                     while (aliases.hasMoreElements()) {
                         String a = aliases.nextElement();
                         try {
-                            tas.add(new TrustAnchor((X509Certificate)caks.getCertificate(a), null));
+                            trustedCerts.add((X509Certificate)caks.getCertificate(a));
                         } catch (Exception e2) {
                             // ignore, when a SecretkeyEntry does not include a cert
                         }
@@ -1827,7 +1897,7 @@
                         // PrivateKeyEntry
                         if (store.isCertificateEntry(a) ||
                                 c.getSubjectDN().equals(c.getIssuerDN())) {
-                            tas.add(new TrustAnchor(c, null));
+                            trustedCerts.add(c);
                         }
                     } catch (Exception e2) {
                         // ignore, when a SecretkeyEntry does not include a cert
@@ -1835,7 +1905,11 @@
                 }
             } finally {
                 try {
-                    pkixParameters = new PKIXBuilderParameters(tas, null);
+                    pkixParameters = new PKIXBuilderParameters(
+                            trustedCerts.stream()
+                                    .map(c -> new TrustAnchor(c, null))
+                                    .collect(Collectors.toSet()),
+                            null);
                     pkixParameters.setRevocationEnabled(false);
                 } catch (InvalidAlgorithmParameterException ex) {
                     // Only if tas is empty
@@ -1951,6 +2025,7 @@
         }
     }
 
+    // Called by signJar().
     void getAliasInfo(String alias) throws Exception {
 
         Key key = null;
@@ -1995,22 +2070,6 @@
                 certChain[i] = (X509Certificate)cs[i];
             }
 
-            // We don't meant to print anything, the next call
-            // checks validity and keyUsage etc
-            printCert(false, "", certChain[0], null, true);
-
-            try {
-                validateCertChain(Validator.VAR_CODE_SIGNING,
-                        Arrays.asList(certChain), null);
-            } catch (Exception e) {
-                chainNotValidated = true;
-                chainNotValidatedReason = e;
-            }
-
-            if (KeyStoreUtil.isSelfSigned(certChain[0])) {
-                signerSelfSigned = true;
-            }
-
             try {
                 if (!token && keypass == null)
                     key = store.getKey(alias, storepass);
@@ -2066,7 +2125,7 @@
      * @param parameter this might be a timestamp
      */
     void validateCertChain(String variant, List<? extends Certificate> certs,
-                           Object parameter)
+                           Timestamp parameter)
             throws Exception {
         try {
             Validator.getInstance(Validator.TYPE_PKIX,
@@ -2080,8 +2139,22 @@
             }
 
             // Exception might be dismissed if another warning flag
-            // is already set by printCert. This is only done for
-            // code signing certs.
+            // is already set by printCert.
+
+            if (variant.equals(Validator.VAR_TSA_SERVER) &&
+                    e instanceof ValidatorException) {
+                // Throw cause if it's CertPathValidatorException,
+                if (e.getCause() != null &&
+                        e.getCause() instanceof CertPathValidatorException) {
+                    e = (Exception) e.getCause();
+                    Throwable t = e.getCause();
+                    if ((t instanceof CertificateExpiredException &&
+                            hasExpiredTsaCert)) {
+                        // we already have hasExpiredTsaCert
+                        return;
+                    }
+                }
+            }
 
             if (variant.equals(Validator.VAR_CODE_SIGNING) &&
                     e instanceof ValidatorException) {
--- a/src/jdk.jartool/share/classes/sun/security/tools/jarsigner/Resources.java	Fri Feb 16 12:24:38 2018 -0800
+++ b/src/jdk.jartool/share/classes/sun/security/tools/jarsigner/Resources.java	Fri Feb 16 13:49:07 2018 -0800
@@ -229,6 +229,7 @@
         {"Error.", "Error: "},
         {"...Signer", ">>> Signer"},
         {"...TSA", ">>> TSA"},
+        {"trusted.certificate", "trusted certificate"},
         {"This.jar.contains.unsigned.entries.which.have.not.been.integrity.checked.",
                 "This jar contains unsigned entries which have not been integrity-checked. "},
         {"This.jar.contains.entries.whose.signer.certificate.has.expired.",
@@ -245,8 +246,16 @@
                 "Re-run with the -verbose and -certs options for more details."},
         {"The.signer.certificate.has.expired.",
                 "The signer certificate has expired."},
+        {"The.timestamp.expired.1.but.usable.2",
+                "The timestamp expired on %1$tY-%1$tm-%1$td. However, the JAR will be valid until the signer certificate expires on %2$tY-%2$tm-%2$td."},
+        {"The.timestamp.has.expired.",
+                "The timestamp has expired."},
         {"The.signer.certificate.will.expire.within.six.months.",
                 "The signer certificate will expire within six months."},
+        {"The.timestamp.will.expire.within.one.year.on.1",
+                "The timestamp will expire within one year on %1$tY-%1$tm-%1$td."},
+        {"The.timestamp.will.expire.within.one.year.on.1.but.2",
+                "The timestamp will expire within one year on %1$tY-%1$tm-%1$td. However, the JAR will be valid until the signer certificate expires on %2$tY-%2$tm-%2$td."},
         {"The.signer.certificate.is.not.yet.valid.",
                 "The signer certificate is not yet valid."},
         {"The.signer.certificate.s.KeyUsage.extension.doesn.t.allow.code.signing.",
@@ -279,10 +288,18 @@
                 "This jar contains entries whose TSA certificate chain is invalid. Reason: %s"},
         {"no.timestamp.signing",
                 "No -tsa or -tsacert is provided and this jar is not timestamped. Without a timestamp, users may not be able to validate this jar after the signer certificate's expiration date (%1$tY-%1$tm-%1$td)."},
+        {"invalid.timestamp.signing",
+                "The timestamp is invalid. Without a valid timestamp, users may not be able to validate this jar after the signer certificate's expiration date (%1$tY-%1$tm-%1$td)."},
         {"no.timestamp.verifying",
                 "This jar contains signatures that do not include a timestamp. Without a timestamp, users may not be able to validate this jar after any of the signer certificates expire (as early as %1$tY-%1$tm-%1$td)."},
         {"bad.timestamp.verifying",
                 "This jar contains signatures that include an invalid timestamp. Without a valid timestamp, users may not be able to validate this jar after any of the signer certificates expire (as early as %1$tY-%1$tm-%1$td).\nRerun jarsigner with -J-Djava.security.debug=jar for more information."},
+        {"The.signer.certificate.will.expire.on.1.",
+                "The signer certificate will expire on %1$tY-%1$tm-%1$td."},
+        {"The.timestamp.will.expire.on.1.",
+                "The timestamp will expire on %1$tY-%1$tm-%1$td."},
+        {"signer.cert.expired.1.but.timestamp.good.2.",
+                "The signer certificate expired on %1$tY-%1$tm-%1$td. However, the JAR will be valid until the timestamp expires on %2$tY-%2$tm-%2$td."},
         {"Unknown.password.type.", "Unknown password type: "},
         {"Cannot.find.environment.variable.",
                 "Cannot find environment variable: "},
--- a/test/hotspot/gtest/gc/shared/test_oopStorage.cpp	Fri Feb 16 12:24:38 2018 -0800
+++ b/test/hotspot/gtest/gc/shared/test_oopStorage.cpp	Fri Feb 16 13:49:07 2018 -0800
@@ -70,6 +70,10 @@
     return storage._allocate_mutex;
   }
 
+  static bool reduce_deferred_updates(OopStorage& storage) {
+    return storage.reduce_deferred_updates();
+  }
+
   static bool block_is_empty(const Block& block) {
     return block.is_empty();
   }
@@ -127,9 +131,31 @@
   return list.chead() == NULL;
 }
 
-static void release_entry(OopStorage& storage, oop* entry) {
+static bool process_deferred_updates(OopStorage& storage) {
+  MutexLockerEx ml(TestAccess::allocate_mutex(storage), Mutex::_no_safepoint_check_flag);
+  bool result = false;
+  while (TestAccess::reduce_deferred_updates(storage)) {
+    result = true;
+  }
+  return result;
+}
+
+static void release_entry(OopStorage& storage, oop* entry, bool process_deferred = true) {
   *entry = NULL;
   storage.release(entry);
+  if (process_deferred) {
+    process_deferred_updates(storage);
+  }
+}
+
+static size_t empty_block_count(const OopStorage& storage) {
+  const TestAccess::BlockList& list = TestAccess::allocate_list(storage);
+  size_t count = 0;
+  for (const OopBlock* block = list.ctail();
+       (block != NULL) && block->is_empty();
+       ++count, block = list.prev(*block))
+  {}
+  return count;
 }
 
 class OopStorageTest : public ::testing::Test {
@@ -188,31 +214,22 @@
 class OopStorageTestWithAllocation::VM_DeleteBlocksAtSafepoint
   : public VM_GTestExecuteAtSafepoint {
 public:
-  VM_DeleteBlocksAtSafepoint(OopStorage* storage, size_t retain) :
-    _storage(storage), _retain(retain)
-  {}
+  VM_DeleteBlocksAtSafepoint(OopStorage* storage) : _storage(storage) {}
 
   void doit() {
-    _storage->delete_empty_blocks_safepoint(_retain);
+    _storage->delete_empty_blocks_safepoint();
   }
 
 private:
   OopStorage* _storage;
-  size_t _retain;
 };
 
 static bool is_allocate_list_sorted(const OopStorage& storage) {
   // The allocate_list isn't strictly sorted.  Rather, all empty
-  // blocks are segregated to the end of the list.  And the number of
-  // empty blocks should match empty_block_count().
-  size_t expected_empty = storage.empty_block_count();
+  // blocks are segregated to the end of the list.
   const TestAccess::BlockList& list = TestAccess::allocate_list(storage);
   const OopBlock* block = list.ctail();
-  for (size_t i = 0; i < expected_empty; ++i, block = list.prev(*block)) {
-    if ((block == NULL) || !block->is_empty()) {
-      return false;
-    }
-  }
+  for ( ; (block != NULL) && block->is_empty(); block = list.prev(*block)) {}
   for ( ; block != NULL; block = list.prev(*block)) {
     if (block->is_empty()) {
       return false;
@@ -243,7 +260,7 @@
   EXPECT_EQ(1u, _storage.block_count());
   EXPECT_EQ(1u, list_length(TestAccess::allocate_list(_storage)));
 
-  EXPECT_EQ(0u, _storage.empty_block_count());
+  EXPECT_EQ(0u, empty_block_count(_storage));
 
   const OopBlock* block = TestAccess::allocate_list(_storage).chead();
   EXPECT_NE(block, (OopBlock*)NULL);
@@ -259,7 +276,7 @@
   EXPECT_EQ(1u, _storage.block_count());
   EXPECT_EQ(1u, list_length(TestAccess::allocate_list(_storage)));
 
-  EXPECT_EQ(1u, _storage.empty_block_count());
+  EXPECT_EQ(1u, empty_block_count(_storage));
 
   const OopBlock* new_block = TestAccess::allocate_list(_storage).chead();
   EXPECT_EQ(block, new_block);
@@ -322,14 +339,14 @@
   TestAccess::BlockList& active_list = TestAccess::active_list(_storage);
   TestAccess::BlockList& allocate_list = TestAccess::allocate_list(_storage);
 
-  EXPECT_EQ(0u, _storage.empty_block_count());
+  EXPECT_EQ(0u, empty_block_count(_storage));
 
   entries[0] = _storage.allocate();
   ASSERT_TRUE(entries[0] != NULL);
   EXPECT_EQ(1u, list_length(active_list));
   EXPECT_EQ(1u, _storage.block_count());
   EXPECT_EQ(1u, list_length(allocate_list));
-  EXPECT_EQ(0u, _storage.empty_block_count());
+  EXPECT_EQ(0u, empty_block_count(_storage));
 
   const OopBlock* block = active_list.chead();
   EXPECT_EQ(1u, TestAccess::block_allocation_count(*block));
@@ -339,7 +356,7 @@
     entries[i] = _storage.allocate();
     EXPECT_EQ(i + 1, _storage.allocation_count());
     ASSERT_TRUE(entries[i] != NULL);
-    EXPECT_EQ(0u, _storage.empty_block_count());
+    EXPECT_EQ(0u, empty_block_count(_storage));
 
     if (block == NULL) {
       ASSERT_FALSE(is_list_empty(allocate_list));
@@ -374,7 +391,7 @@
 
   EXPECT_EQ(list_length(active_list), list_length(allocate_list));
   EXPECT_EQ(list_length(active_list), _storage.block_count());
-  EXPECT_EQ(list_length(active_list), _storage.empty_block_count());
+  EXPECT_EQ(list_length(active_list), empty_block_count(_storage));
   for (const OopBlock* block = allocate_list.chead();
        block != NULL;
        block = allocate_list.next(*block)) {
@@ -386,7 +403,7 @@
   static const size_t step = 11;
   ASSERT_NE(0u, _max_entries % step); // max_entries and step are mutually prime
 
-  EXPECT_EQ(0u, _storage.empty_block_count());
+  EXPECT_EQ(0u, empty_block_count(_storage));
 
   TestAccess::BlockList& active_list = TestAccess::active_list(_storage);
   TestAccess::BlockList& allocate_list = TestAccess::allocate_list(_storage);
@@ -409,7 +426,7 @@
   EXPECT_EQ(list_length(active_list), list_length(allocate_list));
   EXPECT_EQ(list_length(active_list), _storage.block_count());
   EXPECT_EQ(0u, total_allocation_count(active_list));
-  EXPECT_EQ(list_length(allocate_list), _storage.empty_block_count());
+  EXPECT_EQ(list_length(allocate_list), empty_block_count(_storage));
 }
 
 TEST_VM_F(OopStorageTestWithAllocation, random_allocate_release) {
@@ -417,7 +434,7 @@
   static const size_t allocate_step = 5;
   ASSERT_NE(0u, _max_entries % release_step); // max_entries and step are mutually prime
 
-  EXPECT_EQ(0u, _storage.empty_block_count());
+  EXPECT_EQ(0u, empty_block_count(_storage));
 
   TestAccess::BlockList& active_list = TestAccess::active_list(_storage);
   TestAccess::BlockList& allocate_list = TestAccess::allocate_list(_storage);
@@ -449,7 +466,7 @@
   EXPECT_EQ(list_length(active_list), list_length(allocate_list));
   EXPECT_EQ(list_length(active_list), _storage.block_count());
   EXPECT_EQ(0u, total_allocation_count(active_list));
-  EXPECT_EQ(list_length(allocate_list), _storage.empty_block_count());
+  EXPECT_EQ(list_length(allocate_list), empty_block_count(_storage));
 }
 
 template<bool sorted>
@@ -471,11 +488,12 @@
     EXPECT_EQ(_max_entries - nrelease, _storage.allocation_count());
 
     for (size_t i = 0; i < nrelease; ++i) {
-      release_entry(_storage, _entries[2 * i + 1]);
+      release_entry(_storage, _entries[2 * i + 1], false);
       EXPECT_EQ(_max_entries - nrelease - (i + 1), _storage.allocation_count());
     }
+    EXPECT_TRUE(process_deferred_updates(_storage));
 
-    EXPECT_EQ(_storage.block_count(), _storage.empty_block_count());
+    EXPECT_EQ(_storage.block_count(), empty_block_count(_storage));
 
     FREE_C_HEAP_ARRAY(oop*, to_release);
   }
@@ -607,8 +625,9 @@
   }
 
   while (allocated > 0) {
-    release_entry(_storage, entries[--allocated]);
+    release_entry(_storage, entries[--allocated], false);
   }
+  process_deferred_updates(_storage);
 }
 
 class OopStorageTestIteration : public OopStorageTestWithAllocation {
@@ -627,16 +646,17 @@
     memset(_states, 0, sizeof(_states));
 
     size_t initial_release = 0;
-    for ( ; _storage.empty_block_count() < 2; ++initial_release) {
+    for ( ; empty_block_count(_storage) < 2; ++initial_release) {
       ASSERT_GT(_max_entries, initial_release);
       release_entry(_storage, _entries[initial_release]);
       _states[0][initial_release] = mark_released;
     }
 
     for (size_t i = initial_release; i < _max_entries; i += 3) {
-      release_entry(_storage, _entries[i]);
+      release_entry(_storage, _entries[i], false);
       _states[0][i] = mark_released;
     }
+    process_deferred_updates(_storage);
   }
 
   class VerifyState;
@@ -1006,30 +1026,21 @@
   EXPECT_EQ(initial_active_size, _storage.block_count());
   ASSERT_LE(3u, initial_active_size); // Need at least 3 blocks for test
 
-  for (size_t i = 0; _storage.empty_block_count() < 3; ++i) {
+  for (size_t i = 0; empty_block_count(_storage) < 3; ++i) {
     ASSERT_GT(_max_entries, i);
     release_entry(_storage, _entries[i]);
   }
 
   EXPECT_EQ(initial_active_size, list_length(active_list));
   EXPECT_EQ(initial_active_size, _storage.block_count());
-  EXPECT_EQ(3u, _storage.empty_block_count());
+  EXPECT_EQ(3u, empty_block_count(_storage));
 
   {
     ThreadInVMfromNative invm(JavaThread::current());
-    VM_DeleteBlocksAtSafepoint op(&_storage, 2);
+    VM_DeleteBlocksAtSafepoint op(&_storage);
     VMThread::execute(&op);
   }
-  EXPECT_EQ(2u, _storage.empty_block_count());
-  EXPECT_EQ(initial_active_size - 1, list_length(active_list));
-  EXPECT_EQ(initial_active_size - 1, _storage.block_count());
-
-  {
-    ThreadInVMfromNative invm(JavaThread::current());
-    VM_DeleteBlocksAtSafepoint op(&_storage, 0);
-    VMThread::execute(&op);
-  }
-  EXPECT_EQ(0u, _storage.empty_block_count());
+  EXPECT_EQ(0u, empty_block_count(_storage));
   EXPECT_EQ(initial_active_size - 3, list_length(active_list));
   EXPECT_EQ(initial_active_size - 3, _storage.block_count());
 }
@@ -1041,22 +1052,17 @@
   EXPECT_EQ(initial_active_size, _storage.block_count());
   ASSERT_LE(3u, initial_active_size); // Need at least 3 blocks for test
 
-  for (size_t i = 0; _storage.empty_block_count() < 3; ++i) {
+  for (size_t i = 0; empty_block_count(_storage) < 3; ++i) {
     ASSERT_GT(_max_entries, i);
     release_entry(_storage, _entries[i]);
   }
 
   EXPECT_EQ(initial_active_size, list_length(active_list));
   EXPECT_EQ(initial_active_size, _storage.block_count());
-  EXPECT_EQ(3u, _storage.empty_block_count());
+  EXPECT_EQ(3u, empty_block_count(_storage));
 
-  _storage.delete_empty_blocks_concurrent(2);
-  EXPECT_EQ(2u, _storage.empty_block_count());
-  EXPECT_EQ(initial_active_size - 1, list_length(active_list));
-  EXPECT_EQ(initial_active_size - 1, _storage.block_count());
-
-  _storage.delete_empty_blocks_concurrent(0);
-  EXPECT_EQ(0u, _storage.empty_block_count());
+  _storage.delete_empty_blocks_concurrent();
+  EXPECT_EQ(0u, empty_block_count(_storage));
   EXPECT_EQ(initial_active_size - 3, list_length(active_list));
   EXPECT_EQ(initial_active_size - 3, _storage.block_count());
 }
@@ -1075,13 +1081,14 @@
 
   for (size_t i = 0; i < _max_entries; ++i) {
     if ((_entries[i] != retained) && (_entries[i] != released)) {
-      release_entry(_storage, _entries[i]);
+      // Leave deferred release updates to block deletion.
+      release_entry(_storage, _entries[i], false);
     }
   }
 
   {
     ThreadInVMfromNative invm(JavaThread::current());
-    VM_DeleteBlocksAtSafepoint op(&_storage, 0);
+    VM_DeleteBlocksAtSafepoint op(&_storage);
     VMThread::execute(&op);
   }
   EXPECT_EQ(OopStorage::ALLOCATED_ENTRY, _storage.allocation_status(retained));
@@ -1121,12 +1128,14 @@
 TEST_VM_F(OopStorageTestWithAllocation, print_storage) {
   // Release the first 1/2
   for (size_t i = 0; i < (_max_entries / 2); ++i) {
-    release_entry(_storage, _entries[i]);
+    // Deferred updates don't affect print output.
+    release_entry(_storage, _entries[i], false);
     _entries[i] = NULL;
   }
   // Release every other remaining
   for (size_t i = _max_entries / 2; i < _max_entries; i += 2) {
-    release_entry(_storage, _entries[i]);
+    // Deferred updates don't affect print output.
+    release_entry(_storage, _entries[i], false);
     _entries[i] = NULL;
   }
 
@@ -1137,24 +1146,17 @@
   size_t expected_blocks = (_max_entries + entries_per_block - 1) / entries_per_block;
   EXPECT_EQ(expected_blocks, _storage.block_count());
 
-  size_t expected_empties = (_max_entries / 2) / entries_per_block;
-  EXPECT_EQ(expected_empties, _storage.empty_block_count());
-
-  size_t expected_used = expected_blocks - expected_empties;
-
-  double expected_usage = (100.0 * expected_entries) / (expected_used * entries_per_block);
+  double expected_usage = (100.0 * expected_entries) / (expected_blocks * entries_per_block);
 
   {
     ResourceMark rm;
     stringStream expected_st;
     expected_st.print("Test Storage: " SIZE_FORMAT
                       " entries in " SIZE_FORMAT
-                      " blocks (%.F%%), " SIZE_FORMAT
-                      " empties, " SIZE_FORMAT " bytes",
+                      " blocks (%.F%%), " SIZE_FORMAT " bytes",
                       expected_entries,
-                      expected_used,
+                      expected_blocks,
                       expected_usage,
-                      expected_empties,
                       _storage.total_memory_usage());
     stringStream st;
     _storage.print_on(&st);
--- a/test/hotspot/jtreg/compiler/inlining/InlineAccessors.java	Fri Feb 16 12:24:38 2018 -0800
+++ b/test/hotspot/jtreg/compiler/inlining/InlineAccessors.java	Fri Feb 16 13:49:07 2018 -0800
@@ -43,7 +43,7 @@
 
         ProcessBuilder pb = ProcessTools.createJavaProcessBuilder(
                 "-XX:+IgnoreUnrecognizedVMOptions", "-showversion",
-                "-server", "-XX:-TieredCompilation", "-Xbatch", "-Xcomp",
+                "-server", "-XX:-TieredCompilation", "-Xbatch",
                 "-XX:+PrintCompilation", "-XX:+UnlockDiagnosticVMOptions", "-XX:+PrintInlining",
                     Launcher.class.getName());
 
--- a/test/hotspot/jtreg/compiler/uncommontrap/TestUnstableIfTrap.java	Fri Feb 16 12:24:38 2018 -0800
+++ b/test/hotspot/jtreg/compiler/uncommontrap/TestUnstableIfTrap.java	Fri Feb 16 13:49:07 2018 -0800
@@ -24,6 +24,7 @@
 /*
  * @test
  * @bug 8030976 8059226
+ * @requires !vm.graal.enabled
  * @library /test/lib /
  * @modules java.base/jdk.internal.org.objectweb.asm
  *          java.base/jdk.internal.misc
--- a/test/hotspot/jtreg/gc/TestNUMAPageSize.java	Fri Feb 16 12:24:38 2018 -0800
+++ b/test/hotspot/jtreg/gc/TestNUMAPageSize.java	Fri Feb 16 13:49:07 2018 -0800
@@ -23,11 +23,10 @@
 
 /**
  * @test TestNUMAPageSize
+ * @key gc regression
  * @summary Make sure that start up with NUMA support does not cause problems.
  * @bug 8061467
  * @requires (vm.opt.AggressiveOpts == null) | (vm.opt.AggressiveOpts == false)
- * @key gc
- * @key regression
  * @run main/othervm -Xmx8M -XX:+UseNUMA TestNUMAPageSize
  */
 
--- a/test/hotspot/jtreg/gc/arguments/TestAlignmentToUseLargePages.java	Fri Feb 16 12:24:38 2018 -0800
+++ b/test/hotspot/jtreg/gc/arguments/TestAlignmentToUseLargePages.java	Fri Feb 16 13:49:07 2018 -0800
@@ -23,11 +23,10 @@
 
 /**
  * @test TestAlignmentToUseLargePages
+ * @key gc regression
  * @summary All parallel GC variants may use large pages without the requirement that the
  * heap alignment is large page aligned. Other collectors also need to start up with odd sized heaps.
  * @bug 8024396
- * @key gc
- * @key regression
  * @requires vm.gc=="null"
  * @run main/othervm -Xms71M -Xmx91M -XX:+UseParallelGC -XX:-UseParallelOldGC -XX:+UseLargePages TestAlignmentToUseLargePages
  * @run main/othervm -Xms71M -Xmx91M -XX:+UseParallelGC -XX:-UseParallelOldGC -XX:-UseLargePages TestAlignmentToUseLargePages
--- a/test/hotspot/jtreg/gc/cms/GuardShrinkWarning.java	Fri Feb 16 12:24:38 2018 -0800
+++ b/test/hotspot/jtreg/gc/cms/GuardShrinkWarning.java	Fri Feb 16 13:49:07 2018 -0800
@@ -23,10 +23,9 @@
 
 /**
  * @test GuardShrinkWarning
+ * @key gc regression
  * @summary Remove warning about CMS generation shrinking.
  * @bug 8012111
- * @key gc
- * @key regression
  * @library /test/lib
  * @modules java.base/jdk.internal.misc
  *          java.management
--- a/test/hotspot/jtreg/gc/g1/Test2GbHeap.java	Fri Feb 16 12:24:38 2018 -0800
+++ b/test/hotspot/jtreg/gc/g1/Test2GbHeap.java	Fri Feb 16 13:49:07 2018 -0800
@@ -23,13 +23,12 @@
 
 /*
  * @test Test2GbHeap
+ * @key gc regression
  * @bug 8031686
  * @summary Regression test to ensure we can start G1 with 2gb heap.
  * Skip test on 32 bit system: it typically does not support the many and large virtual memory reservations needed.
  * @requires vm.gc.G1
  * @requires vm.bits != "32"
- * @key gc
- * @key regression
  * @library /test/lib
  * @modules java.base/jdk.internal.misc
  *          java.management
--- a/test/hotspot/jtreg/gc/g1/TestHumongousCodeCacheRoots.java	Fri Feb 16 12:24:38 2018 -0800
+++ b/test/hotspot/jtreg/gc/g1/TestHumongousCodeCacheRoots.java	Fri Feb 16 13:49:07 2018 -0800
@@ -23,8 +23,7 @@
 
 /*
  * @test
- * @key regression
- * @key gc
+ * @key regression gc
  * @bug 8027756
  * @requires vm.gc.G1
  * @library /test/lib
--- a/test/hotspot/jtreg/gc/g1/TestParallelAlwaysPreTouch.java	Fri Feb 16 12:24:38 2018 -0800
+++ b/test/hotspot/jtreg/gc/g1/TestParallelAlwaysPreTouch.java	Fri Feb 16 13:49:07 2018 -0800
@@ -23,13 +23,12 @@
 
 /*
  * @test
+ * @key gc regression
  * @bug 8169703
  * @summary Regression test to ensure AlwaysPreTouch with multiple threads works at mutator time.
  * Allocates a few humongous objects that will be allocated by expanding the heap, causing concurrent parallel
  * pre-touch.
  * @requires vm.gc.G1
- * @key gc
- * @key regression
  * @run main/othervm -XX:+UseG1GC -Xms10M -Xmx100m -XX:G1HeapRegionSize=1M -XX:+AlwaysPreTouch -XX:PreTouchParallelChunkSize=512k -Xlog:gc+ergo+heap=debug,gc+heap=debug,gc=debug TestParallelAlwaysPreTouch
  */
 
--- a/test/hotspot/jtreg/gc/logging/TestUnifiedLoggingSwitchStress.java	Fri Feb 16 12:24:38 2018 -0800
+++ b/test/hotspot/jtreg/gc/logging/TestUnifiedLoggingSwitchStress.java	Fri Feb 16 13:49:07 2018 -0800
@@ -39,9 +39,8 @@
 
 /**
  * @test TestUnifiedLoggingSwitchStress
+ * @key gc stress
  * @summary Switches gc log level on fly while stressing memory/gc
- * @key gc
- * @key stress
  * @requires !vm.flightRecorder
  * @library /test/lib /
  * @modules java.management java.base/jdk.internal.misc
--- a/test/hotspot/jtreg/gc/parallel/AdaptiveGCBoundary.java	Fri Feb 16 12:24:38 2018 -0800
+++ b/test/hotspot/jtreg/gc/parallel/AdaptiveGCBoundary.java	Fri Feb 16 13:49:07 2018 -0800
@@ -23,10 +23,9 @@
 
 /**
  * @test AdaptiveGCBoundary
+ * @key gc regression
  * @summary UseAdaptiveGCBoundary is broken
  * @bug 8014546
- * @key gc
- * @key regression
  * @library /test/lib
  * @modules java.base/jdk.internal.misc
  *          java.management
--- a/test/hotspot/jtreg/gc/stress/TestStressG1Humongous.java	Fri Feb 16 12:24:38 2018 -0800
+++ b/test/hotspot/jtreg/gc/stress/TestStressG1Humongous.java	Fri Feb 16 13:49:07 2018 -0800
@@ -23,8 +23,7 @@
 
 /*
  * @test TestStressG1Humongous
- * @key gc
- * @key stress
+ * @key gc stress
  * @summary Stress G1 by humongous allocations in situation near OOM
  * @requires vm.gc.G1
  * @requires !vm.flightRecorder
--- a/test/hotspot/jtreg/gc/stress/gcbasher/TestGCBasherWithAllocateHeapAt.java	Fri Feb 16 12:24:38 2018 -0800
+++ b/test/hotspot/jtreg/gc/stress/gcbasher/TestGCBasherWithAllocateHeapAt.java	Fri Feb 16 13:49:07 2018 -0800
@@ -26,8 +26,7 @@
 
 /*
  * @test TestGCBasherWithAllocateHeapAt
- * @key gc
- * @key stress
+ * @key gc stress
  * @requires vm.gc.G1
  * @requires vm.flavor == "server" & !vm.emulatedClient
  * @summary Stress Java heap allocation with AllocateHeapAt flag using GC basher.
--- a/test/hotspot/jtreg/gc/stress/gcbasher/TestGCBasherWithCMS.java	Fri Feb 16 12:24:38 2018 -0800
+++ b/test/hotspot/jtreg/gc/stress/gcbasher/TestGCBasherWithCMS.java	Fri Feb 16 13:49:07 2018 -0800
@@ -26,8 +26,7 @@
 
 /*
  * @test TestGCBasherWithCMS
- * @key gc
- * @key stress
+ * @key gc stress
  * @requires vm.gc.ConcMarkSweep
  * @requires vm.flavor == "server" & !vm.emulatedClient
  * @summary Stress the CMS GC by trying to make old objects more likely to be garbage than young objects.
--- a/test/hotspot/jtreg/gc/stress/gcbasher/TestGCBasherWithG1.java	Fri Feb 16 12:24:38 2018 -0800
+++ b/test/hotspot/jtreg/gc/stress/gcbasher/TestGCBasherWithG1.java	Fri Feb 16 13:49:07 2018 -0800
@@ -26,8 +26,7 @@
 
 /*
  * @test TestGCBasherWithG1
- * @key gc
- * @key stress
+ * @key gc stress
  * @requires vm.gc.G1
  * @requires vm.flavor == "server" & !vm.emulatedClient
  * @summary Stress the G1 GC by trying to make old objects more likely to be garbage than young objects.
--- a/test/hotspot/jtreg/gc/stress/gcbasher/TestGCBasherWithParallel.java	Fri Feb 16 12:24:38 2018 -0800
+++ b/test/hotspot/jtreg/gc/stress/gcbasher/TestGCBasherWithParallel.java	Fri Feb 16 13:49:07 2018 -0800
@@ -26,8 +26,7 @@
 
 /*
  * @test TestGCBasherWithParallel
- * @key gc
- * @key stress
+ * @key gc stress
  * @requires vm.gc.Parallel
  * @requires vm.flavor == "server" & !vm.emulatedClient
  * @summary Stress the Parallel GC by trying to make old objects more likely to be garbage than young objects.
--- a/test/hotspot/jtreg/gc/stress/gcbasher/TestGCBasherWithSerial.java	Fri Feb 16 12:24:38 2018 -0800
+++ b/test/hotspot/jtreg/gc/stress/gcbasher/TestGCBasherWithSerial.java	Fri Feb 16 13:49:07 2018 -0800
@@ -26,8 +26,7 @@
 
 /*
  * @test TestGCBasherWithSerial
- * @key gc
- * @key stress
+ * @key gc stress
  * @requires vm.gc.Serial
  * @requires vm.flavor == "server" & !vm.emulatedClient
  * @summary Stress the Serial GC by trying to make old objects more likely to be garbage than young objects.
--- a/test/hotspot/jtreg/gc/stress/systemgc/TestSystemGCWithCMS.java	Fri Feb 16 12:24:38 2018 -0800
+++ b/test/hotspot/jtreg/gc/stress/systemgc/TestSystemGCWithCMS.java	Fri Feb 16 13:49:07 2018 -0800
@@ -24,9 +24,8 @@
 
 /*
  * @test TestSystemGCWithCMS
+ * @key gc stress
  * @bug 8190703
- * @key gc
- * @key stress
  * @requires vm.gc.ConcMarkSweep
  * @summary Stress the CMS GC full GC by allocating objects of different lifetimes concurrently with System.gc().
  * @run main/othervm/timeout=300 -Xlog:gc*=info -Xmx512m -XX:+UseConcMarkSweepGC TestSystemGCWithCMS 270
--- a/test/hotspot/jtreg/gc/stress/systemgc/TestSystemGCWithG1.java	Fri Feb 16 12:24:38 2018 -0800
+++ b/test/hotspot/jtreg/gc/stress/systemgc/TestSystemGCWithG1.java	Fri Feb 16 13:49:07 2018 -0800
@@ -24,9 +24,8 @@
 
 /*
  * @test TestSystemGCWithG1
+ * @key gc stress
  * @bug 8190703
- * @key gc
- * @key stress
  * @requires vm.gc.G1
  * @summary Stress the G1 GC full GC by allocating objects of different lifetimes concurrently with System.gc().
  * @run main/othervm/timeout=300 -Xlog:gc*=info -Xmx512m -XX:+UseG1GC TestSystemGCWithG1 270
--- a/test/hotspot/jtreg/gc/stress/systemgc/TestSystemGCWithParallel.java	Fri Feb 16 12:24:38 2018 -0800
+++ b/test/hotspot/jtreg/gc/stress/systemgc/TestSystemGCWithParallel.java	Fri Feb 16 13:49:07 2018 -0800
@@ -24,9 +24,8 @@
 
 /*
  * @test TestSystemGCWithParallel
+ * @key gc stress
  * @bug 8190703
- * @key gc
- * @key stress
  * @requires vm.gc.Parallel
  * @summary Stress the Parallel GC full GC by allocating objects of different lifetimes concurrently with System.gc().
  * @run main/othervm/timeout=300 -Xlog:gc=info -Xmx512m -XX:+UseParallelGC TestSystemGCWithParallel 270
--- a/test/hotspot/jtreg/gc/stress/systemgc/TestSystemGCWithSerial.java	Fri Feb 16 12:24:38 2018 -0800
+++ b/test/hotspot/jtreg/gc/stress/systemgc/TestSystemGCWithSerial.java	Fri Feb 16 13:49:07 2018 -0800
@@ -24,9 +24,8 @@
 
 /*
  * @test TestSystemGCWithSerial
+ * @key gc stress
  * @bug 8190703
- * @key gc
- * @key stress
  * @requires vm.gc.Serial
  * @summary Stress the Serial GC full GC by allocating objects of different lifetimes concurrently with System.gc().
  * @run main/othervm/timeout=300 -Xlog:gc*=info -Xmx512m -XX:+UseSerialGC TestSystemGCWithSerial 270
--- a/test/hotspot/jtreg/runtime/CommandLine/VMDeprecatedOptions.java	Fri Feb 16 12:24:38 2018 -0800
+++ b/test/hotspot/jtreg/runtime/CommandLine/VMDeprecatedOptions.java	Fri Feb 16 13:49:07 2018 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -47,6 +47,8 @@
         {"InitialRAMFraction",        "64"},
         {"AssumeMP",                  "false"},
         {"UseMembar",                 "true"},
+        {"CompilerThreadHintNoPreempt", "true"},
+        {"VMThreadHintNoPreempt",       "false"},
 
         // deprecated alias flags (see also aliased_jvm_flags):
         {"DefaultMaxRAMFraction", "4"},
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/runtime/NMT/JcmdSummaryClass.java	Fri Feb 16 13:49:07 2018 -0800
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+ /*
+ * @test
+ * @bug 8193184
+ * @key nmt
+ * @summary Check class counters in summary report
+ * @library /test/lib
+ * @modules java.base/jdk.internal.misc
+ *          java.management
+ * @run main/othervm -Xbootclasspath/a:. -XX:NativeMemoryTracking=summary JcmdSummaryClass
+ */
+
+import jdk.test.lib.process.ProcessTools;
+import jdk.test.lib.process.OutputAnalyzer;
+import jdk.test.lib.JDKToolFinder;
+
+
+import java.util.regex.*;
+
+public class JcmdSummaryClass {
+
+    public static void main(String args[]) throws Exception {
+        ProcessBuilder pb = new ProcessBuilder();
+        OutputAnalyzer output;
+        // Grab my own PID
+        String pid = Long.toString(ProcessTools.getProcessId());
+
+        // Run 'jcmd <pid> VM.native_memory baseline=true'
+        pb.command(new String[] { JDKToolFinder.getJDKTool("jcmd"), pid, "VM.native_memory"});
+        pb.start().waitFor();
+
+        String classes_line = "classes #\\d+";
+        String instance_array_classes_line = "instance classes #\\d+, array classes #\\d+";
+        output = new OutputAnalyzer(pb.start());
+        output.shouldMatch(classes_line);
+        output.shouldMatch(instance_array_classes_line);
+    }
+}
--- a/test/hotspot/jtreg/runtime/SharedArchiveFile/serviceability/transformRelatedClasses/TransformInterfaceAndImplementor.java	Fri Feb 16 12:24:38 2018 -0800
+++ b/test/hotspot/jtreg/runtime/SharedArchiveFile/serviceability/transformRelatedClasses/TransformInterfaceAndImplementor.java	Fri Feb 16 13:49:07 2018 -0800
@@ -29,6 +29,7 @@
  * @library /test/lib /runtime/SharedArchiveFile /testlibrary/jvmti
  * @requires vm.cds
  * @requires vm.flavor != "minimal"
+ * @requires !vm.graal.enabled
  * @modules java.base/jdk.internal.misc
  *          jdk.jartool/sun.tools.jar
  *          java.management
--- a/test/hotspot/jtreg/runtime/SharedArchiveFile/serviceability/transformRelatedClasses/TransformSuperAndSubClasses.java	Fri Feb 16 12:24:38 2018 -0800
+++ b/test/hotspot/jtreg/runtime/SharedArchiveFile/serviceability/transformRelatedClasses/TransformSuperAndSubClasses.java	Fri Feb 16 13:49:07 2018 -0800
@@ -30,6 +30,7 @@
  * @library /test/lib /runtime/SharedArchiveFile /testlibrary/jvmti
  * @requires vm.cds
  * @requires vm.flavor != "minimal"
+ * @requires !vm.graal.enabled
  * @modules java.base/jdk.internal.misc
  *          jdk.jartool/sun.tools.jar
  *          java.management
--- a/test/hotspot/jtreg/runtime/SharedArchiveFile/serviceability/transformRelatedClasses/TransformSuperSubTwoPckgs.java	Fri Feb 16 12:24:38 2018 -0800
+++ b/test/hotspot/jtreg/runtime/SharedArchiveFile/serviceability/transformRelatedClasses/TransformSuperSubTwoPckgs.java	Fri Feb 16 13:49:07 2018 -0800
@@ -30,6 +30,7 @@
  * @library /test/lib /runtime/SharedArchiveFile /testlibrary/jvmti
  * @requires vm.cds
  * @requires vm.flavor != "minimal"
+ * @requires !vm.graal.enabled
  * @modules java.base/jdk.internal.misc
  *          jdk.jartool/sun.tools.jar
  *          java.management
--- a/test/hotspot/jtreg/runtime/appcds/jvmti/parallelLoad/ParallelLoadAndTransformTest.java	Fri Feb 16 12:24:38 2018 -0800
+++ b/test/hotspot/jtreg/runtime/appcds/jvmti/parallelLoad/ParallelLoadAndTransformTest.java	Fri Feb 16 13:49:07 2018 -0800
@@ -30,6 +30,7 @@
  *     /test/hotspot/jtreg/runtime/appcds/test-classes /test/hotspot/jtreg/runtime/appcds/jvmti
  *     /test/hotspot/jtreg/testlibrary/jvmti
  * @requires vm.cds
+ * @requires !vm.graal.enabled
  * @modules java.base/jdk.internal.misc
  *          java.management
  *          jdk.jartool/sun.tools.jar
--- a/test/hotspot/jtreg/runtime/appcds/jvmti/transformRelatedClasses/TransformInterfaceImplementorAppCDS.java	Fri Feb 16 12:24:38 2018 -0800
+++ b/test/hotspot/jtreg/runtime/appcds/jvmti/transformRelatedClasses/TransformInterfaceImplementorAppCDS.java	Fri Feb 16 13:49:07 2018 -0800
@@ -34,6 +34,7 @@
  *     /test/hotspot/jtreg/runtime/appcds/customLoader/test-classes
  * @requires vm.cds
  * @requires vm.flavor != "minimal"
+ * @requires !vm.graal.enabled
  * @modules java.base/jdk.internal.misc
  *          jdk.jartool/sun.tools.jar
  *          java.management
--- a/test/hotspot/jtreg/runtime/appcds/jvmti/transformRelatedClasses/TransformSuperSubAppCDS.java	Fri Feb 16 12:24:38 2018 -0800
+++ b/test/hotspot/jtreg/runtime/appcds/jvmti/transformRelatedClasses/TransformSuperSubAppCDS.java	Fri Feb 16 13:49:07 2018 -0800
@@ -34,6 +34,7 @@
  *     /test/hotspot/jtreg/runtime/appcds/customLoader/test-classes
  * @requires vm.cds
  * @requires vm.flavor != "minimal"
+ * @requires !vm.graal.enabled
  * @modules java.base/jdk.internal.misc
  *          jdk.jartool/sun.tools.jar
  *          java.management
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/runtime/containers/docker/Dockerfile-BasicTest-ppc64le	Fri Feb 16 13:49:07 2018 -0800
@@ -0,0 +1,10 @@
+# test on x86_64 uses Oracle Linux but we do not have this for ppc64le
+# so use some other Linux where OpenJDK works 
+# FROM oraclelinux:7.2
+FROM ppc64le/ubuntu
+
+COPY /jdk /jdk
+
+ENV JAVA_HOME=/jdk
+
+CMD ["/bin/bash"]
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/serviceability/jvmti/CanGenerateAllClassHook/CanGenerateAllClassHook.java	Fri Feb 16 13:49:07 2018 -0800
@@ -0,0 +1,135 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * @test
+ * @bug 8161605
+ * @summary Tests that jvmtiEnv::GetPotentialCapabilities reports
+ *          can_generate_all_class_hook_events capability with CDS (-Xshare:on)
+ *          at ONLOAD and LIVE phases
+ * @library /test/lib
+ * @compile CanGenerateAllClassHook.java
+ * @run main/othervm/native CanGenerateAllClassHook
+ */
+
+import jdk.test.lib.cds.CDSTestUtils;
+import jdk.test.lib.process.OutputAnalyzer;
+import jdk.test.lib.process.ProcessTools;
+import java.io.File;
+import java.io.IOException;
+
+/*
+ * The simplest way to test is to use system classes.jsa,
+ * but we cannot rely on tested JRE/JDK has it.
+ * So the test runs 2 java processes -
+ * 1st to generate custom shared archive file:
+ *     java -XX:+UnlockDiagnosticVMOptions -XX:SharedArchiveFile=<jsa_file> -Xshare:dump
+ * and 2nd to perform the actual testing using generated shared archive:
+ *     java -XX:+UnlockDiagnosticVMOptions -XX:SharedArchiveFile=<jsa_file> -Xshare:on
+  *         -agentlib:<agent> CanGenerateAllClassHook
+ */
+public class CanGenerateAllClassHook {
+
+    private static final String agentLib = "CanGenerateAllClassHook";
+
+    private static native int getClassHookAvail();
+    private static native int getOnLoadClassHookAvail();
+
+    public static void main(String[] args) throws Exception {
+        if (args.length == 0) {
+            // this is master run
+
+            final File jsaFile = File.createTempFile(agentLib, ".jsa");
+            jsaFile.deleteOnExit();
+            final String jsaPath = jsaFile.getAbsolutePath();
+
+            log("generating CDS archive...");
+            execJava(
+                        "-XX:+UnlockDiagnosticVMOptions",
+                        "-XX:SharedArchiveFile=" + jsaPath,
+                        "-Xshare:dump")
+                    .shouldHaveExitValue(0);
+            log("CDS generation completed.");
+
+            OutputAnalyzer output = execJava(
+                    "-XX:+UnlockDiagnosticVMOptions",
+                    "-XX:SharedArchiveFile=" + jsaPath,
+                    "-Xshare:on",
+                    "-agentlib:" + agentLib,
+                    // copy java.library.path
+                    "-Djava.library.path=" + System.getProperty("java.library.path"),
+                    // specify "-showversion" to ensure the test runs in shared mode
+                    "-showversion",
+                    // class to run
+                    CanGenerateAllClassHook.class.getCanonicalName(),
+                    // and arg
+                    "test");
+            // Xshare:on can cause intermittent failure
+            // checkExec handles this.
+            CDSTestUtils.checkExec(output);
+
+            log("Test PASSED.");
+        } else {
+            // this is test run
+            try {
+                System.loadLibrary(agentLib);
+            } catch (UnsatisfiedLinkError ex) {
+                System.err.println("Failed to load " + agentLib + " lib");
+                System.err.println("java.library.path: " + System.getProperty("java.library.path"));
+                throw ex;
+            }
+
+            final int onLoadValue = getOnLoadClassHookAvail();
+            final int liveValue = getClassHookAvail();
+            // Possible values returned:
+            // 1 - the capability is supported;
+            // 0 - the capability is not supported;
+            // -1 - error occured.
+
+            log("can_generate_all_class_hook_events value capability:");
+            log("ONLOAD phase: " + (onLoadValue < 0 ? "Failed to read" : onLoadValue));
+            log("LIVE phase: " + (liveValue < 0 ? "Failed to read" : liveValue));
+            if (onLoadValue != 1 || liveValue != 1) {
+                throw new RuntimeException("The can_generate_all_class_hook_events capability "
+                        + " is expected to be available in both ONLOAD and LIVE phases");
+            }
+        }
+    }
+
+    private static void log(String msg) {
+        System.out.println(msg);
+        System.out.flush();
+    }
+
+    private static OutputAnalyzer execJava(String... args) throws IOException {
+        ProcessBuilder pb = ProcessTools.createJavaProcessBuilder(args);
+
+        OutputAnalyzer output = new OutputAnalyzer(pb.start());
+
+        log("[STDERR]\n" + output.getStderr());
+        log("[STDOUT]\n" + output.getStdout());
+
+        return output;
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/serviceability/jvmti/CanGenerateAllClassHook/libCanGenerateAllClassHook.c	Fri Feb 16 13:49:07 2018 -0800
@@ -0,0 +1,126 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include "jvmti.h"
+#include "jni.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifndef JNI_ENV_ARG
+
+#ifdef __cplusplus
+#define JNI_ENV_ARG(x, y) y
+#define JNI_ENV_PTR(x) x
+#else
+#define JNI_ENV_ARG(x,y) x, y
+#define JNI_ENV_PTR(x) (*x)
+#endif
+
+#endif
+
+
+static jvmtiEnv *jvmti = NULL;
+
+typedef enum {
+    Yes = 1,
+    No = 0,
+    Error = -1
+} IsAvail;
+
+static IsAvail onLoadIsAvail = Error;
+
+void reportError(const char *msg, int err) {
+    printf("%s, error: %d\n", msg, err);
+}
+
+static IsAvail isClassHookAvail() {
+    IsAvail result = Error;
+    do {
+        jvmtiCapabilities caps;
+        jvmtiPhase phase;
+        jvmtiError err;
+
+        if (jvmti == NULL) {
+            reportError("jvmti is NULL", -1);
+            break;
+        }
+
+        err = (*jvmti)->GetPhase(jvmti, &phase);
+        if (err != JVMTI_ERROR_NONE) {
+            reportError("GetPhase failed", err);
+            break;
+        }
+
+        err = (*jvmti)->GetPotentialCapabilities(jvmti, &caps);
+        if (err != JVMTI_ERROR_NONE) {
+            reportError("GetPotentialCapabilities failed", err);
+            break;
+        }
+
+        result = caps.can_generate_all_class_hook_events ? Yes : No;
+
+        printf("isClassHookAvail: phase=%d, value=%d\n", phase, result);
+    } while (0);
+    return result;
+}
+
+
+JNIEXPORT jint JNICALL
+Agent_OnLoad(JavaVM *jvm, char *options, void *reserved)
+{
+    jint res = JNI_ENV_PTR(jvm)->GetEnv(JNI_ENV_ARG(jvm, (void **) &jvmti), JVMTI_VERSION_9);
+    if (res != JNI_OK || jvmti == NULL) {
+        reportError("GetEnv failed", res);
+        return JNI_ERR;
+    }
+
+    // check and save can_generate_all_class_hook_events for ONLOAD phase
+    onLoadIsAvail = isClassHookAvail();
+
+    return JNI_OK;
+}
+
+JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *jvm, void *reserved) {
+    return JNI_VERSION_9;
+}
+
+
+JNIEXPORT jint JNICALL
+Java_CanGenerateAllClassHook_getClassHookAvail(JNIEnv *env, jclass cls) {
+    return isClassHookAvail();
+}
+
+JNIEXPORT jint JNICALL
+Java_CanGenerateAllClassHook_getOnLoadClassHookAvail(JNIEnv *env, jclass cls) {
+    return onLoadIsAvail;
+}
+
+
+#ifdef __cplusplus
+}
+#endif
+
--- a/test/hotspot/jtreg/serviceability/sa/ClhsdbInspect.java	Fri Feb 16 12:24:38 2018 -0800
+++ b/test/hotspot/jtreg/serviceability/sa/ClhsdbInspect.java	Fri Feb 16 13:49:07 2018 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2017, 2018, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -48,9 +48,9 @@
             LingeredApp.startApp(null, theApp);
             System.out.println("Started LingeredApp with pid " + theApp.getPid());
 
-            // Run the 'jstack -v' command to get the address of a Method*
-            // and the oop address of a java.lang.ref.ReferenceQueue$Lock
-            // object
+            // Run the 'jstack -v' command to get the address of a Method*,
+            // the oop address of a java.lang.ref.ReferenceQueue$Lock
+            // and the oop address of a java.lang.Class object
             List<String> cmds = List.of("jstack -v");
 
             String jstackOutput = test.run(theApp.getPid(), cmds, null, null);
@@ -62,26 +62,37 @@
                 return;
             }
 
-            String addressString = null;
             Map<String, String> tokensMap = new HashMap<>();
-            tokensMap.put("waiting to lock",
+            tokensMap.put("(a java.lang.Class for LingeredAppWithLock)",
                           "instance of Oop for java/lang/Class");
-            tokensMap.put("Method\\*=", "Type is Method");
-            tokensMap.put("waiting to re-lock in wait",
+            tokensMap.put("Method*=", "Type is Method");
+            tokensMap.put("(a java.lang.ref.ReferenceQueue$Lock)",
                           "instance of Oop for java/lang/ref/ReferenceQueue$Lock");
 
+            String[] lines = jstackOutput.split("\\R");
+
             for (String key: tokensMap.keySet()) {
                 cmds = new ArrayList<String>();
                 Map<String, List<String>> expStrMap = new HashMap<>();
 
-                String[] snippets = jstackOutput.split(key);
-                String[] tokens = snippets[1].split(" ");
-                for (String token: tokens) {
-                    if (token.contains("0x")) {
-                        addressString = token.replace("<", "").replace(">", "");
-                        break;
-                    }
-                }
+                String addressString = null;
+                for (String line : lines) {
+                    if (line.contains(key)) {
+                        // Escape the token "Method*=" because the split method uses
+                        // a regex, not just a straight String.
+                        String escapedKey = key.replace("*","\\*");
+                        String[] words = line.split(escapedKey+"|[ ]");
+                        for (String word : words) {
+                            word = word.replace("<","").replace(">","");
+                            if (word.startsWith("0x")) {
+                                addressString = word;
+                                break;
+                            }
+                        }
+                        if (addressString != null)
+                            break;
+                      }
+                  }
 
                 String cmd = "inspect " + addressString;
                 cmds.add(cmd);
--- a/test/hotspot/jtreg/serviceability/sa/ClhsdbWhere.java	Fri Feb 16 12:24:38 2018 -0800
+++ b/test/hotspot/jtreg/serviceability/sa/ClhsdbWhere.java	Fri Feb 16 13:49:07 2018 -0800
@@ -56,9 +56,8 @@
                     "Java Stack Trace for Sweeper thread",
                     "CompilerThread",
                     "Java Stack Trace for Finalizer",
-                    "java.lang.ref.Reference",
-                    "private static void processPendingReferences",
-                    "private static native void waitForReferencePendingList",
+                    "Java Stack Trace for Signal Dispatcher",
+                    "Java Stack Trace for Reference Handler",
                     "Java Stack Trace for main",
                     "public static void main"));
 
--- a/test/hotspot/jtreg/testlibrary/jvmti/TransformerAgent.java	Fri Feb 16 12:24:38 2018 -0800
+++ b/test/hotspot/jtreg/testlibrary/jvmti/TransformerAgent.java	Fri Feb 16 13:49:07 2018 -0800
@@ -57,17 +57,25 @@
 
 
     static class SimpleTransformer implements ClassFileTransformer {
-       public byte[] transform(ClassLoader loader, String name, Class<?> classBeingRedefined,
-                            ProtectionDomain pd, byte[] buffer) throws IllegalClassFormatException {
+        public byte[] transform(ClassLoader loader, String name, Class<?> classBeingRedefined,
+                                ProtectionDomain pd, byte[] buffer) throws IllegalClassFormatException {
+            try {
+                log("SimpleTransformer called for: " + name + "@" + incrCounter(name));
+                if (!shouldTransform(name))
+                    return null;
 
-            log("SimpleTransformer called for: " + name + "@" + incrCounter(name));
-            if (!shouldTransform(name))
-                return null;
-
-            log("transforming: class name = " + name);
-            int nrOfReplacements = TransformUtil.replace(buffer, TransformUtil.BeforePattern,
-                                                         TransformUtil.AfterPattern);
-            log("replaced the string, nrOfReplacements = " + nrOfReplacements);
+                log("transforming: class name = " + name);
+                int nrOfReplacements = TransformUtil.replace(buffer, TransformUtil.BeforePattern,
+                                                           TransformUtil.AfterPattern);
+                log("replaced the string, nrOfReplacements = " + nrOfReplacements);
+            } catch (Throwable t) {
+                // The retransform native code that called this method does not propagate
+                // exceptions. Instead of getting an uninformative generic error, catch
+                // problems here and print it, then exit.
+                log("Transformation failed!");
+                t.printStackTrace();
+                System.exit(1);
+            }
             return buffer;
         }
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/com/sun/jndi/dns/AttributeTests/GetAny.dns	Fri Feb 16 13:49:07 2018 -0800
@@ -0,0 +1,110 @@
+#
+# Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+#
+# This code is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License version 2 only, as
+# published by the Free Software Foundation.
+#
+# This code is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+# FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+# version 2 for more details (a copy is included in the LICENSE file that
+# accompanied this code).
+#
+# You should have received a copy of the GNU General Public License version
+# 2 along with this work; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+#
+# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+# or visit www.oracle.com if you need additional information or have any
+# questions.
+#
+
+################################################################################
+# Capture file for GetAny.java
+#
+# NOTE: This hexadecimal dump of DNS protocol messages was generated by
+#       running the GetAny application program against a real DNS
+#       server along with DNSTracer
+#
+################################################################################
+
+# DNS Request
+
+0000: 32 72 01 00 00 01 00 00   00 00 00 00 05 68 6F 73  2r...........hos
+0010: 74 31 07 64 6F 6D 61 69   6E 31 03 63 6F 6D 00 00  t1.domain1.com..
+0020: FF 00 01                                           ...
+
+
+# DNS Response
+
+0000: 32 72 85 80 00 01 00 06   00 01 00 01 05 68 6F 73  2r...........hos
+0010: 74 31 07 64 6F 6D 61 69   6E 31 03 63 6F 6D 00 00  t1.domain1.com..
+0020: FF 00 01 C0 0C 00 10 00   01 00 00 8C A0 00 15 14  ................
+0030: 41 20 76 65 72 79 20 70   6F 70 75 6C 61 72 20 68  A very popular h
+0040: 6F 73 74 2E C0 0C 00 1D   00 01 00 00 8C A0 00 10  ost.............
+0050: 00 12 16 13 88 97 1A 35   69 68 41 38 00 9B 16 58  .......5ihA8...X
+0060: C0 0C 00 0D 00 01 00 00   8C A0 00 13 0C 54 68 65  .............The
+0070: 20 4F 72 69 67 69 6E 61   6C 05 53 75 6E 6E 79 C0   Original.Sunny.
+0080: 0C 00 0F 00 01 00 00 8C   A0 00 11 00 0A 05 72 65  ..............re
+0090: 6C 61 79 04 6F 68 69 6F   02 75 73 00 C0 0C 00 0F  lay.ohio.us.....
+00A0: 00 01 00 00 8C A0 00 10   00 14 05 72 65 6C 61 79  ...........relay
+00B0: 05 74 65 78 61 73 C0 98   C0 0C 00 01 00 01 00 01  .texas..........
+00C0: 51 80 00 04 01 02 04 01   C0 12 00 02 00 01 00 00  Q...............
+00D0: 8C A0 00 05 02 6E 73 C0   12 C0 D4 00 01 00 01 00  .....ns.........
+00E0: 00 8C A0 00 04 7F 00 00   01                       .........
+
+
+# DNS Request
+
+0000: 41 80 01 00 00 01 00 00   00 00 00 00 05 68 6F 73  A............hos
+0010: 74 31 07 64 6F 6D 61 69   6E 31 03 63 6F 6D 00 00  t1.domain1.com..
+0020: FF 00 FF                                           ...
+
+
+# DNS Response
+
+0000: 41 80 85 80 00 01 00 06   00 01 00 01 05 68 6F 73  A............hos
+0010: 74 31 07 64 6F 6D 61 69   6E 31 03 63 6F 6D 00 00  t1.domain1.com..
+0020: FF 00 FF C0 0C 00 10 00   01 00 00 8C A0 00 15 14  ................
+0030: 41 20 76 65 72 79 20 70   6F 70 75 6C 61 72 20 68  A very popular h
+0040: 6F 73 74 2E C0 0C 00 1D   00 01 00 00 8C A0 00 10  ost.............
+0050: 00 12 16 13 88 97 1A 35   69 68 41 38 00 9B 16 58  .......5ihA8...X
+0060: C0 0C 00 0D 00 01 00 00   8C A0 00 13 0C 54 68 65  .............The
+0070: 20 4F 72 69 67 69 6E 61   6C 05 53 75 6E 6E 79 C0   Original.Sunny.
+0080: 0C 00 0F 00 01 00 00 8C   A0 00 12 00 14 05 72 65  ..............re
+0090: 6C 61 79 05 74 65 78 61   73 02 75 73 00 C0 0C 00  lay.texas.us....
+00A0: 0F 00 01 00 00 8C A0 00   0F 00 0A 05 72 65 6C 61  ............rela
+00B0: 79 04 6F 68 69 6F C0 99   C0 0C 00 01 00 01 00 01  y.ohio..........
+00C0: 51 80 00 04 01 02 04 01   C0 12 00 02 00 01 00 00  Q...............
+00D0: 8C A0 00 05 02 6E 73 C0   12 C0 D4 00 01 00 01 00  .....ns.........
+00E0: 00 8C A0 00 04 7F 00 00   01                       .........
+
+
+# DNS Request
+
+0000: 65 2E 01 00 00 01 00 00   00 00 00 00 05 68 6F 73  e............hos
+0010: 74 31 07 64 6F 6D 61 69   6E 31 03 63 6F 6D 00 00  t1.domain1.com..
+0020: FF 00 01                                           ...
+
+
+# DNS Response
+
+0000: 65 2E 85 80 00 01 00 06   00 01 00 01 05 68 6F 73  e............hos
+0010: 74 31 07 64 6F 6D 61 69   6E 31 03 63 6F 6D 00 00  t1.domain1.com..
+0020: FF 00 01 C0 0C 00 10 00   01 00 00 8C A0 00 15 14  ................
+0030: 41 20 76 65 72 79 20 70   6F 70 75 6C 61 72 20 68  A very popular h
+0040: 6F 73 74 2E C0 0C 00 1D   00 01 00 00 8C A0 00 10  ost.............
+0050: 00 12 16 13 88 97 1A 35   69 68 41 38 00 9B 16 58  .......5ihA8...X
+0060: C0 0C 00 0D 00 01 00 00   8C A0 00 13 0C 54 68 65  .............The
+0070: 20 4F 72 69 67 69 6E 61   6C 05 53 75 6E 6E 79 C0   Original.Sunny.
+0080: 0C 00 0F 00 01 00 00 8C   A0 00 11 00 0A 05 72 65  ..............re
+0090: 6C 61 79 04 6F 68 69 6F   02 75 73 00 C0 0C 00 0F  lay.ohio.us.....
+00A0: 00 01 00 00 8C A0 00 10   00 14 05 72 65 6C 61 79  ...........relay
+00B0: 05 74 65 78 61 73 C0 98   C0 0C 00 01 00 01 00 01  .texas..........
+00C0: 51 80 00 04 01 02 04 01   C0 12 00 02 00 01 00 00  Q...............
+00D0: 8C A0 00 05 02 6E 73 C0   12 C0 D4 00 01 00 01 00  .....ns.........
+00E0: 00 8C A0 00 04 7F 00 00   01                       .........
+
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/com/sun/jndi/dns/AttributeTests/GetAny.java	Fri Feb 16 13:49:07 2018 -0800
@@ -0,0 +1,82 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @bug 8195976
+ * @summary Tests that we can get the attributes of a DNS entry using special
+ *          qualifiers.
+ * @modules java.xml.bind
+ *          java.base/sun.security.util
+ * @library ../lib/
+ * @build DNSTestUtils DNSServer DNSTracer
+ * @run main GetAny
+ */
+
+import javax.naming.directory.Attributes;
+import javax.naming.directory.DirContext;
+import javax.naming.directory.InitialDirContext;
+import java.net.DatagramSocket;
+import java.net.InetAddress;
+import java.util.Hashtable;
+
+public class GetAny {
+    private static final String KEY = "host1";
+
+    private static final String[] MANDATORY = { "A", "MX", "HINFO", "TXT", "29"
+            // "LOC"
+    };
+
+    private static final String[] OPTIONAL = {};
+
+    public static void main(String argv[]) throws Exception {
+        // Create socket on localhost only to avoid possible noise packet
+        DatagramSocket socket = new DatagramSocket(0,
+                InetAddress.getLoopbackAddress());
+
+        // initialize test
+        Hashtable<Object, Object> env;
+
+        env = DNSTestUtils.initEnv(socket, GetAny.class.getName(), argv);
+
+        DirContext ctx = null;
+
+        try {
+            // connect to server
+            ctx = new InitialDirContext(env);
+
+            // Any type from IN class
+            Attributes retAttrs = ctx.getAttributes(KEY, new String[] { "*" });
+            DNSTestUtils.verifySchema(retAttrs, MANDATORY, OPTIONAL);
+
+            retAttrs = ctx.getAttributes(KEY, new String[] { "* *" });
+            DNSTestUtils.verifySchema(retAttrs, MANDATORY, OPTIONAL);
+
+            retAttrs = ctx.getAttributes(KEY, new String[] { "IN *" });
+            DNSTestUtils.verifySchema(retAttrs, MANDATORY, OPTIONAL);
+
+        } finally {
+            DNSTestUtils.cleanup(ctx);
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/com/sun/jndi/dns/lib/DNSServer.java	Fri Feb 16 13:49:07 2018 -0800
@@ -0,0 +1,264 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+import sun.security.util.HexDumpEncoder;
+
+import javax.xml.bind.DatatypeConverter;
+import java.io.IOException;
+import java.net.DatagramPacket;
+import java.net.DatagramSocket;
+import java.nio.ByteBuffer;
+import java.nio.file.Paths;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Scanner;
+import java.util.regex.MatchResult;
+
+/*
+ * A dummy DNS server.
+ *
+ * Loads a sequence of DNS messages from a capture file into its cache.
+ * It listens for DNS UDP requests, finds match request in cache and sends the
+ * corresponding DNS responses.
+ *
+ * The capture file contains an DNS protocol exchange in the hexadecimal
+ * dump format emitted by HexDumpEncoder:
+ *
+ * xxxx: 00 11 22 33 44 55 66 77   88 99 aa bb cc dd ee ff  ................
+ *
+ * Typically, DNS protocol exchange is generated by DNSTracer who captures
+ * communication messages between DNS application program and real DNS server
+ */
+public class DNSServer implements Runnable {
+
+    public class Pair<F, S> {
+        private F first;
+        private S second;
+
+        public Pair(F first, S second) {
+            this.first = first;
+            this.second = second;
+        }
+
+        public void setFirst(F first) {
+            this.first = first;
+        }
+
+        public void setSecond(S second) {
+            this.second = second;
+        }
+
+        public F getFirst() {
+            return first;
+        }
+
+        public S getSecond() {
+            return second;
+        }
+    }
+
+    public static final int DNS_HEADER_SIZE = 12;
+    public static final int DNS_PACKET_SIZE = 512;
+
+    static HexDumpEncoder encoder = new HexDumpEncoder();
+
+    private DatagramSocket socket;
+    private String filename;
+    private boolean loop;
+    private final List<Pair<byte[], byte[]>> cache = new ArrayList<>();
+    private ByteBuffer reqBuffer = ByteBuffer.allocate(DNS_PACKET_SIZE);
+
+    public DNSServer(DatagramSocket socket, String filename) {
+        this(socket, filename, false);
+    }
+
+    public DNSServer(DatagramSocket socket, String filename, boolean loop) {
+        this.socket = socket;
+        this.filename = filename;
+        this.loop = loop;
+    }
+
+    public void run() {
+        try {
+            System.out.println(
+                    "DNSServer: Loading DNS cache data from : " + filename);
+            loadCaptureFile(filename);
+
+            System.out.println(
+                    "DNSServer: listening on port " + socket.getLocalPort());
+
+            System.out.println("DNSServer: loop playback: " + loop);
+
+            int playbackIndex = 0;
+
+            while (playbackIndex < cache.size()) {
+                DatagramPacket reqPacket = new DatagramPacket(reqBuffer.array(),
+                        reqBuffer.array().length);
+                socket.receive(reqPacket);
+
+                System.out.println(
+                        "DNSServer: received query message from " + reqPacket
+                                .getSocketAddress());
+
+                if (!verifyRequestMsg(reqPacket, playbackIndex)) {
+                    throw new RuntimeException(
+                            "DNSServer: Error: Failed to verify DNS request. "
+                                    + "Not identical request message : \n"
+                                    + encoder.encodeBuffer(
+                                    Arrays.copyOf(reqPacket.getData(),
+                                            reqPacket.getLength())));
+                }
+
+                byte[] payload = generateResponsePayload(reqPacket,
+                        playbackIndex);
+                socket.send(new DatagramPacket(payload, payload.length,
+                        reqPacket.getSocketAddress()));
+                System.out.println(
+                        "DNSServer: send response message to " + reqPacket
+                                .getSocketAddress());
+
+                playbackIndex++;
+                if (loop && playbackIndex >= cache.size()) {
+                    playbackIndex = 0;
+                }
+            }
+
+            System.out.println(
+                    "DNSServer: Done for all cached messages playback");
+        } catch (Exception e) {
+            System.err.println("DNSServer: Error: " + e);
+        }
+    }
+
+    /*
+     * Load a capture file containing an DNS protocol exchange in the
+     * hexadecimal dump format emitted by sun.misc.HexDumpEncoder:
+     *
+     * xxxx: 00 11 22 33 44 55 66 77   88 99 aa bb cc dd ee ff  ................
+     */
+    private void loadCaptureFile(String filename) throws IOException {
+        StringBuilder hexString = new StringBuilder();
+        String pattern = "(....): (..) (..) (..) (..) (..) (..) (..) (..)   "
+                + "(..) (..) (..) (..) (..) (..) (..) (..).*";
+
+        try (Scanner fileScanner = new Scanner(Paths.get(filename))) {
+            while (fileScanner.hasNextLine()) {
+
+                try (Scanner lineScanner = new Scanner(
+                        fileScanner.nextLine())) {
+                    if (lineScanner.findInLine(pattern) == null) {
+                        continue;
+                    }
+                    MatchResult result = lineScanner.match();
+                    for (int i = 1; i <= result.groupCount(); i++) {
+                        String digits = result.group(i);
+                        if (digits.length() == 4) {
+                            if (digits.equals("0000")) { // start-of-message
+                                if (hexString.length() > 0) {
+                                    addToCache(hexString.toString());
+                                    hexString.delete(0, hexString.length());
+                                }
+                            }
+                            continue;
+                        } else if (digits.equals("  ")) { // short message
+                            continue;
+                        }
+                        hexString.append(digits);
+                    }
+                }
+            }
+        }
+        addToCache(hexString.toString());
+    }
+
+    /*
+     * Add an DNS encoding to the cache (by request message key).
+     */
+    private void addToCache(String hexString) {
+        byte[] encoding = DatatypeConverter.parseHexBinary(hexString);
+        if (encoding.length < DNS_HEADER_SIZE) {
+            throw new RuntimeException("Invalid DNS message : " + hexString);
+        }
+
+        if (getQR(encoding) == 0) {
+            // a query message, create entry in cache
+            cache.add(new Pair<>(encoding, null));
+            System.out.println(
+                    "    adding DNS query message with ID " + getID(encoding)
+                            + " to the cache");
+        } else {
+            // a response message, attach it to the query entry
+            if (!cache.isEmpty() && (getID(getLatestCacheEntry().getFirst())
+                    == getID(encoding))) {
+                getLatestCacheEntry().setSecond(encoding);
+                System.out.println(
+                        "    adding DNS response message associated to ID "
+                                + getID(encoding) + " in the cache");
+            } else {
+                throw new RuntimeException(
+                        "Invalid DNS message : " + hexString);
+            }
+        }
+    }
+
+    /*
+     * ID: A 16 bit identifier assigned by the program that generates any
+     * kind of query. This identifier is copied the corresponding reply and
+     * can be used by the requester to match up replies to outstanding queries.
+     */
+    private static int getID(byte[] encoding) {
+        return ByteBuffer.wrap(encoding, 0, 2).getShort();
+    }
+
+    /*
+     * QR: A one bit field that specifies whether this message is
+     * a query (0), or a response (1) after ID
+     */
+    private static int getQR(byte[] encoding) {
+        return encoding[2] & (0x01 << 7);
+    }
+
+    private Pair<byte[], byte[]> getLatestCacheEntry() {
+        return cache.get(cache.size() - 1);
+    }
+
+    private boolean verifyRequestMsg(DatagramPacket packet, int playbackIndex) {
+        byte[] cachedRequest = cache.get(playbackIndex).getFirst();
+        return Arrays.equals(Arrays
+                        .copyOfRange(packet.getData(), 2, packet.getLength()),
+                Arrays.copyOfRange(cachedRequest, 2, cachedRequest.length));
+    }
+
+    private byte[] generateResponsePayload(DatagramPacket packet,
+            int playbackIndex) {
+        byte[] resMsg = cache.get(playbackIndex).getSecond();
+        byte[] payload = Arrays.copyOf(resMsg, resMsg.length);
+
+        // replace the ID with same with real request
+        payload[0] = packet.getData()[0];
+        payload[1] = packet.getData()[1];
+
+        return payload;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/com/sun/jndi/dns/lib/DNSTestUtils.java	Fri Feb 16 13:49:07 2018 -0800
@@ -0,0 +1,246 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+import javax.naming.Context;
+import javax.naming.NamingException;
+import javax.naming.directory.Attributes;
+import java.io.PrintStream;
+import java.net.DatagramSocket;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.Hashtable;
+
+public class DNSTestUtils {
+    public static final String TEST_DNS_SERVER_THREAD = "test.dns.server.thread";
+    public static final String TEST_DNS_ROOT_URL = "test.dns.root.url";
+    public static final int HOSTS_LOOKUP_MAX_DEPTH = 3;
+
+    protected static boolean debug = true;
+
+    /*
+     * Check that attrs contains the mandatory attributes and the right
+     * objectclass attribute
+     */
+    public static boolean checkSchema(Attributes attrs, String[] mandatory,
+            String[] optional) {
+        // Check mandatory attributes
+        for (String mandatoryAttr : mandatory) {
+            if (attrs.get(mandatoryAttr) == null) {
+                debug("missing mandatory attribute: " + mandatoryAttr);
+                return false;
+            }
+        }
+
+        // Check optional attributes
+        int optMissing = 0;
+        for (String optionalAttr : optional) {
+            if (attrs.get(optionalAttr) == null) {
+                debug("warning: missing optional attribute: " + optionalAttr);
+                ++optMissing;
+            }
+        }
+
+        if (attrs.size() > (mandatory.length + (optional.length
+                - optMissing))) {
+            debug("too many attributes: " + attrs);
+            return false;
+        }
+
+        return true;
+    }
+
+    /*
+     * Process command line arguments and init env
+     */
+    public static Hashtable<Object, Object> initEnv(DatagramSocket socket,
+            String testname, String[] args) {
+
+        Hashtable<Object, Object> env = new Hashtable<>();
+
+        // set some default parameters if no additional specified
+        env.put("DNS_DOMAIN", "domain1.com.");
+        env.put("FOREIGN_DOMAIN", "Central.Sun.COM.");
+        env.put("FOREIGN_LEAF", "sunweb");
+
+        // set defaults for some JNDI properties
+        env.put(Context.INITIAL_CONTEXT_FACTORY,
+                "com.sun.jndi.dns.DnsContextFactory");
+
+        boolean traceEnable = false;
+        boolean loopPlayback = false;
+        for (int i = 0; i < args.length; i++) {
+            if ((args[i].equals("-D")) && (args.length > i + 1)) {
+                extractProperty(args[++i], env);
+            } else if (args[i].startsWith("-D")) {
+                extractProperty(args[i].substring(2), env);
+            } else if (args[i].equalsIgnoreCase("-trace")) {
+                traceEnable = true;
+            } else if (args[i].equalsIgnoreCase("-loop")) {
+                loopPlayback = true;
+            }
+        }
+
+        debug = Boolean.valueOf(System.getProperty("debug", "true"));
+
+        if (env.get("DNS_SERVER") != null) {
+            String port = (String) env.get("DNS_PORT");
+            String portSuffix = (port == null) ? "" : ":" + port;
+            String url = "dns://" + env.get("DNS_SERVER") + portSuffix;
+            env.put(Context.PROVIDER_URL, url);
+            env.put(Context.PROVIDER_URL, url + "/" + env.get("DNS_DOMAIN"));
+        }
+
+        Runnable inst = null;
+        if (traceEnable) {
+            inst = createDNSTracer(socket, testname, env);
+        } else {
+            if (socket != null) {
+                inst = createDNSServer(socket, testname, loopPlayback);
+            } else {
+                // for tests which run against remote server
+                // or no server required
+                debug("Skip local DNS Server creation "
+                        + "since DatagramSocket is null");
+            }
+        }
+
+        if (inst != null) {
+            env.put(TEST_DNS_SERVER_THREAD, startServer(inst));
+            String url = "dns://localhost:" + socket.getLocalPort();
+
+            env.put(TEST_DNS_ROOT_URL, url);
+            env.put(Context.PROVIDER_URL, url + "/" + env.get("DNS_DOMAIN"));
+        }
+
+        return env;
+    }
+
+    /*
+     * Clean-up the directory context.
+     */
+    public static void cleanup(Context ctx) {
+        if (ctx != null) {
+            try {
+                ctx.close();
+            } catch (NamingException e) {
+                // ignore
+            }
+        }
+    }
+
+    private static void extractProperty(String propString,
+            Hashtable<Object, Object> env) {
+        int index;
+
+        if ((index = propString.indexOf('=')) > 0) {
+            env.put(propString.substring(0, index),
+                    propString.substring(index + 1));
+        } else {
+            throw new RuntimeException(
+                    "Failed to extract test args property from " + propString);
+        }
+    }
+
+    public static DNSTracer createDNSTracer(DatagramSocket socket,
+            String testname, Hashtable<Object, Object> env) {
+        if (socket == null) {
+            throw new RuntimeException("Error: failed to create DNSTracer "
+                    + "since DatagramSocket is null");
+        }
+
+        try {
+            PrintStream outStream = new PrintStream(getCaptureFile(testname));
+            return new DNSTracer(socket, outStream,
+                    (String) env.get("DNS_SERVER"),
+                    Integer.parseInt((String) env.get("DNS_PORT")));
+        } catch (Exception e) {
+            throw new RuntimeException(
+                    "Error: failed to create DNSTracer : " + e.getMessage(), e);
+        }
+    }
+
+    public static DNSServer createDNSServer(DatagramSocket socket,
+            String testname, boolean loop) {
+        if (socket == null) {
+            throw new RuntimeException("Error: failed to create DNSServer "
+                    + "since DatagramSocket is null");
+        }
+
+        String path = getCaptureFile(testname);
+        if (Files.exists(Paths.get(path))) {
+            return new DNSServer(socket, path, loop);
+        } else {
+            throw new RuntimeException(
+                    "Error: failed to create DNSServer, not found dns "
+                            + "cache file " + path);
+        }
+    }
+
+    public static Thread startServer(Runnable runnable) {
+        Thread thread = new Thread(runnable);
+        thread.start();
+        return thread;
+    }
+
+    public static String getCaptureFile(String testname) {
+        return Paths.get(System.getProperty("test.src"))
+                .resolve(testname + ".dns").toString();
+    }
+
+    public static void enableHostsFile(String hostsFile) {
+        System.out.println("Enable jdk.net.hosts.file = " + hostsFile);
+        System.setProperty("jdk.net.hosts.file", hostsFile);
+    }
+
+    public static void enableHostsFile(int depth) {
+        Path path = Paths.get(System.getProperty("test.src", "."))
+                .toAbsolutePath();
+        for (int i = depth; i >= 0; i--) {
+            Path filePath = path.resolve("hosts");
+            if (Files.exists(filePath) && !Files.isDirectory(filePath)) {
+                enableHostsFile(filePath.toString());
+                break;
+            }
+
+            path = path.getParent();
+            if (path == null) {
+                break;
+            }
+        }
+    }
+
+    public static void debug(Object object) {
+        if (debug) {
+            System.out.println(object);
+        }
+    }
+
+    public static void verifySchema(Attributes attrs, String[] mandatory,
+            String[] optional) {
+        debug(attrs);
+        if (!checkSchema(attrs, mandatory, optional)) {
+            throw new RuntimeException("Check schema failed.");
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/com/sun/jndi/dns/lib/DNSTracer.java	Fri Feb 16 13:49:07 2018 -0800
@@ -0,0 +1,130 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+import sun.security.util.HexDumpEncoder;
+
+import java.io.PrintStream;
+import java.net.DatagramPacket;
+import java.net.DatagramSocket;
+import java.net.InetSocketAddress;
+import java.net.SocketAddress;
+import java.net.SocketException;
+import java.nio.ByteBuffer;
+import java.util.Arrays;
+
+/*
+ * A DNS UDP message tracer.
+ *
+ * It listens for DNS UDP requests, forward request to real DNS server, receives
+ * response message and sends back to requester, at same time dump all messages
+ * into capture file
+ *
+ * The capture file contains an DNS protocol exchange in the hexadecimal
+ * dump format emitted by HexDumpEncoder:
+ *
+ * xxxx: 00 11 22 33 44 55 66 77   88 99 aa bb cc dd ee ff  ................
+ *
+ * Typically, the capture file data will be used by DNSServer for playback
+ */
+public class DNSTracer implements Runnable {
+    public static final int DNS_DEFAULT_PORT = 53;
+    public static final int DNS_PACKET_SIZE = 512;
+    static HexDumpEncoder encoder = new HexDumpEncoder();
+
+    private DatagramSocket inSocket;
+    private SocketAddress dnsServerAddress;
+    private ByteBuffer reqBuffer = ByteBuffer.allocate(DNS_PACKET_SIZE);
+    private ByteBuffer resBuffer = ByteBuffer.allocate(DNS_PACKET_SIZE);
+    private PrintStream out = null;
+
+    public DNSTracer(DatagramSocket socket, String dnsHostname) {
+        this(socket, dnsHostname, DNS_DEFAULT_PORT);
+    }
+
+    public DNSTracer(DatagramSocket socket, PrintStream outStream,
+            String dnsHostname) {
+        this(socket, outStream, dnsHostname, DNS_DEFAULT_PORT);
+    }
+
+    public DNSTracer(DatagramSocket socket, String dnsHostname, int dnsPort) {
+        this(socket, System.out, dnsHostname, dnsPort);
+    }
+
+    public DNSTracer(DatagramSocket socket, PrintStream outStream,
+            String dnsHostname, int dnsPort) {
+        inSocket = socket;
+        out = outStream;
+        dnsServerAddress = new InetSocketAddress(dnsHostname, dnsPort);
+    }
+
+    public void run() {
+        System.out.println(
+                "DNSTracer: listening on port " + inSocket.getLocalPort());
+
+        System.out.println("DNSTracer: will forward request to server "
+                + dnsServerAddress);
+
+        try (DatagramSocket outSocket = new DatagramSocket()) {
+            while (true) {
+                DatagramPacket reqPacket = new DatagramPacket(reqBuffer.array(),
+                        reqBuffer.array().length);
+                inSocket.receive(reqPacket);
+
+                out.println("-> " + reqPacket.getSocketAddress());
+                out.println();
+                // dump dns request data
+                out.println(encoder.encodeBuffer(
+                        Arrays.copyOf(reqPacket.getData(),
+                                reqPacket.getLength())));
+                out.println();
+
+                outSocket.send(new DatagramPacket(reqPacket.getData(),
+                        reqPacket.getLength(), dnsServerAddress));
+                DatagramPacket resPacket = new DatagramPacket(resBuffer.array(),
+                        resBuffer.array().length);
+                outSocket.receive(resPacket);
+
+                out.println("<- " + resPacket.getSocketAddress());
+                out.println();
+                // dump dns response data
+                out.println(encoder.encodeBuffer(
+                        Arrays.copyOf(resPacket.getData(),
+                                resPacket.getLength())));
+                out.println();
+
+                inSocket.send(new DatagramPacket(resPacket.getData(),
+                        resPacket.getLength(), reqPacket.getSocketAddress()));
+            }
+        } catch (SocketException se) {
+            if (inSocket.isClosed()) {
+                out.flush();
+                System.out.println("DNSTracer: Exit");
+            } else {
+                se.printStackTrace();
+            }
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/com/sun/jndi/ldap/blits/AddTests/AddNewEntry.java	Fri Feb 16 13:49:07 2018 -0800
@@ -0,0 +1,119 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @bug 8196770
+ * @summary Verify capability to add a new entry to the directory using the
+ *          ADD operation.
+ * @modules java.xml.bind
+ *          java.naming/com.sun.jndi.ldap
+ * @library ../../lib/ /javax/naming/module/src/test/test/
+ * @build LDAPServer LDAPTestUtils
+ * @run main AddNewEntry
+ */
+
+import javax.naming.NamingEnumeration;
+import javax.naming.directory.Attribute;
+import javax.naming.directory.Attributes;
+import javax.naming.directory.BasicAttribute;
+import javax.naming.directory.BasicAttributes;
+import javax.naming.directory.DirContext;
+import javax.naming.directory.InitialDirContext;
+import javax.naming.directory.SearchControls;
+import java.net.ServerSocket;
+import java.util.Hashtable;
+
+public class AddNewEntry {
+
+    public static void main(String[] args) throws Exception {
+        ServerSocket serverSocket = new ServerSocket(0);
+
+        Hashtable<Object, Object> env;
+
+        // initialize test
+        env = LDAPTestUtils
+                .initEnv(serverSocket, AddNewEntry.class.getName(), args, true);
+
+        /* Build attribute set */
+        String[] ids = { "objectClass", "sn", "cn", "telephoneNumber", "mail",
+                "description", "uid" };
+        Attribute objectClass = new BasicAttribute(ids[0]);
+        objectClass.add("top");
+        objectClass.add("person");
+        objectClass.add("organizationalPerson");
+        objectClass.add("inetOrgPerson");
+
+        Attribute sn = new BasicAttribute(ids[1], "Powers");
+        Attribute cn = new BasicAttribute(ids[2],
+                "Austin \\\"Danger\\\" Powers");
+        Attribute telephoneNumber = new BasicAttribute(ids[3], "+44 582 10101");
+        Attribute mail = new BasicAttribute(ids[4], "secret_agent_man@imc.org");
+        Attribute description = new BasicAttribute(ids[5], "Yea Baby!!");
+        description.add("Behave!");
+        Attribute uid = new BasicAttribute(ids[6], "secret_agent_man");
+
+        Attributes attrs = new BasicAttributes();
+        attrs.put(objectClass);
+        attrs.put(sn);
+        attrs.put(cn);
+        attrs.put(telephoneNumber);
+        attrs.put(mail);
+        attrs.put(description);
+        attrs.put(uid);
+
+        DirContext ctx = null;
+        String[] bases = new String[] { (String) env.get("client"),
+                (String) env.get("vendor"), "Add" };
+        String baseDN = LDAPTestUtils.buildDN(bases, (String) env.get("root"));
+        String entryDN = "cn=Austin Powers," + baseDN;
+        String expect = ""; // relative name
+
+        try {
+            // connect to server
+            ctx = new InitialDirContext(env);
+
+            // add entry
+            ctx.createSubcontext(entryDN, attrs);
+
+            // specify base search
+            SearchControls constraints = new SearchControls();
+            constraints.setSearchScope(SearchControls.OBJECT_SCOPE);
+
+            NamingEnumeration results = ctx
+                    .search(entryDN, "(objectclass=*)", constraints);
+
+            int found = LDAPTestUtils.checkResult(results, expect);
+
+            if (found != 1) {
+                throw new RuntimeException(
+                        "Check result failed, expect found 1 but actual is "
+                                + found);
+            }
+
+        } finally {
+            LDAPTestUtils.cleanupSubcontext(ctx, entryDN);
+            LDAPTestUtils.cleanup(ctx);
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/com/sun/jndi/ldap/blits/AddTests/AddNewEntry.ldap	Fri Feb 16 13:49:07 2018 -0800
@@ -0,0 +1,135 @@
+#
+# Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+#
+# This code is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License version 2 only, as
+# published by the Free Software Foundation.
+#
+# This code is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+# FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+# version 2 for more details (a copy is included in the LICENSE file that
+# accompanied this code).
+#
+# You should have received a copy of the GNU General Public License version
+# 2 along with this work; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+#
+# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+# or visit www.oracle.com if you need additional information or have any
+# questions.
+#
+
+################################################################################
+# Capture file for AddNewEntry.java
+#
+# NOTE: This hexadecimal dump of LDAP protocol messages was generated by
+#       running the AddNewEntry application program against a real LDAP
+#       server and setting the JNDI/LDAP environment property:
+#       com.sun.jndi.ldap.trace.ber to activate LDAP message tracing.
+#
+################################################################################
+
+
+# LDAP BindRequest
+
+0000: 30 27 02 01 01 60 22 02   01 03 04 13 63 6E 3D 61  0'...`".....cn=a
+0010: 64 6D 69 6E 2C 6F 3D 49   4D 43 2C 63 3D 55 53 80  dmin,o=IMC,c=US.
+0020: 08 73 65 63 72 65 74 39   39                       .secret99
+
+
+# LDAP BindResponse
+
+0000: 30 0C 02 01 01 61 07 0A   01 00 04 00 04 00        0....a........
+
+
+# LDAP AddRequest
+
+0000: 30 82 01 5F 02 01 02 68   82 01 3B 04 38 63 6E 3D  0.._...h..;.8cn=
+0010: 41 75 73 74 69 6E 20 50   6F 77 65 72 73 2C 6F 75  Austin Powers,ou
+0020: 3D 43 6C 69 65 6E 74 31   2C 6F 75 3D 56 65 6E 64  =Client1,ou=Vend
+0030: 6F 72 31 2C 6F 75 3D 41   64 64 2C 6F 3D 49 4D 43  or1,ou=Add,o=IMC
+0040: 2C 63 3D 55 53 30 81 FE   30 41 04 0B 6F 62 6A 65  ,c=US0..0A..obje
+0050: 63 74 43 6C 61 73 73 31   32 04 03 74 6F 70 04 06  ctClass12..top..
+0060: 70 65 72 73 6F 6E 04 14   6F 72 67 61 6E 69 7A 61  person..organiza
+0070: 74 69 6F 6E 61 6C 50 65   72 73 6F 6E 04 0D 69 6E  tionalPerson..in
+0080: 65 74 4F 72 67 50 65 72   73 6F 6E 30 22 04 04 6D  etOrgPerson0"..m
+0090: 61 69 6C 31 1A 04 18 73   65 63 72 65 74 5F 61 67  ail1...secret_ag
+00A0: 65 6E 74 5F 6D 61 6E 40   69 6D 63 2E 6F 72 67 30  ent_man@imc.org0
+00B0: 19 04 03 75 69 64 31 12   04 10 73 65 63 72 65 74  ...uid1...secret
+00C0: 5F 61 67 65 6E 74 5F 6D   61 6E 30 24 04 0B 64 65  _agent_man0$..de
+00D0: 73 63 72 69 70 74 69 6F   6E 31 15 04 0A 59 65 61  scription1...Yea
+00E0: 20 42 61 62 79 21 21 04   07 42 65 68 61 76 65 21   Baby!!..Behave!
+00F0: 30 0E 04 02 73 6E 31 08   04 06 50 6F 77 65 72 73  0...sn1...Powers
+0100: 30 22 04 0F 74 65 6C 65   70 68 6F 6E 65 4E 75 6D  0"..telephoneNum
+0110: 62 65 72 31 0F 04 0D 2B   34 34 20 35 38 32 20 31  ber1...+44 582 1
+0120: 30 31 30 31 30 20 04 02   63 6E 31 1A 04 18 41 75  01010 ..cn1...Au
+0130: 73 74 69 6E 20 5C 22 44   61 6E 67 65 72 5C 22 20  stin \"Danger\" 
+0140: 50 6F 77 65 72 73 A0 1B   30 19 04 17 32 2E 31 36  Powers..0...2.16
+0150: 2E 38 34 30 2E 31 2E 31   31 33 37 33 30 2E 33 2E  .840.1.113730.3.
+0160: 34 2E 32                                           4.2
+
+
+# LDAP AddResponse
+
+0000: 30 0C 02 01 02 69 07 0A   01 00 04 00 04 00        0....i........
+
+
+# LDAP SearchRequest
+
+0000: 30 7A 02 01 03 63 58 04   38 63 6E 3D 41 75 73 74  0z...cX.8cn=Aust
+0010: 69 6E 20 50 6F 77 65 72   73 2C 6F 75 3D 43 6C 69  in Powers,ou=Cli
+0020: 65 6E 74 31 2C 6F 75 3D   56 65 6E 64 6F 72 31 2C  ent1,ou=Vendor1,
+0030: 6F 75 3D 41 64 64 2C 6F   3D 49 4D 43 2C 63 3D 55  ou=Add,o=IMC,c=U
+0040: 53 0A 01 00 0A 01 03 02   01 00 02 01 00 01 01 00  S...............
+0050: 87 0B 6F 62 6A 65 63 74   63 6C 61 73 73 30 00 A0  ..objectclass0..
+0060: 1B 30 19 04 17 32 2E 31   36 2E 38 34 30 2E 31 2E  .0...2.16.840.1.
+0070: 31 31 33 37 33 30 2E 33   2E 34 2E 32              113730.3.4.2
+
+
+# LDAP SearchResultEntry
+
+0000: 30 82 01 52 02 01 03 64   82 01 4B 04 38 63 6E 3D  0..R...d..K.8cn=
+0010: 41 75 73 74 69 6E 20 50   6F 77 65 72 73 2C 6F 75  Austin Powers,ou
+0020: 3D 43 6C 69 65 6E 74 31   2C 6F 75 3D 56 65 6E 64  =Client1,ou=Vend
+0030: 6F 72 31 2C 6F 75 3D 41   64 64 2C 6F 3D 49 4D 43  or1,ou=Add,o=IMC
+0040: 2C 63 3D 55 53 30 82 01   0D 30 41 04 0B 6F 62 6A  ,c=US0...0A..obj
+0050: 65 63 74 43 6C 61 73 73   31 32 04 03 74 6F 70 04  ectClass12..top.
+0060: 06 70 65 72 73 6F 6E 04   14 6F 72 67 61 6E 69 7A  .person..organiz
+0070: 61 74 69 6F 6E 61 6C 50   65 72 73 6F 6E 04 0D 69  ationalPerson..i
+0080: 6E 65 74 4F 72 67 50 65   72 73 6F 6E 30 22 04 04  netOrgPerson0"..
+0090: 6D 61 69 6C 31 1A 04 18   73 65 63 72 65 74 5F 61  mail1...secret_a
+00A0: 67 65 6E 74 5F 6D 61 6E   40 69 6D 63 2E 6F 72 67  gent_man@imc.org
+00B0: 30 19 04 03 75 69 64 31   12 04 10 73 65 63 72 65  0...uid1...secre
+00C0: 74 5F 61 67 65 6E 74 5F   6D 61 6E 30 24 04 0B 64  t_agent_man0$..d
+00D0: 65 73 63 72 69 70 74 69   6F 6E 31 15 04 0A 59 65  escription1...Ye
+00E0: 61 20 42 61 62 79 21 21   04 07 42 65 68 61 76 65  a Baby!!..Behave
+00F0: 21 30 0E 04 02 73 6E 31   08 04 06 50 6F 77 65 72  !0...sn1...Power
+0100: 73 30 22 04 0F 74 65 6C   65 70 68 6F 6E 65 4E 75  s0"..telephoneNu
+0110: 6D 62 65 72 31 0F 04 0D   2B 34 34 20 35 38 32 20  mber1...+44 582 
+0120: 31 30 31 30 31 30 2F 04   02 63 6E 31 29 04 18 41  101010/..cn1)..A
+0130: 75 73 74 69 6E 20 5C 22   44 61 6E 67 65 72 5C 22  ustin \"Danger\"
+0140: 20 50 6F 77 65 72 73 04   0D 41 75 73 74 69 6E 20   Powers..Austin 
+0150: 50 6F 77 65 72 73                                  Powers
+
+
+# LDAP SearchResultDone
+
+0000: 30 0C 02 01 03 65 07 0A   01 00 04 00 04 00        0....e........
+
+
+# LDAP DeleteRequest
+
+0000: 30 5A 02 01 04 4A 38 63   6E 3D 41 75 73 74 69 6E  0Z...J8cn=Austin
+0010: 20 50 6F 77 65 72 73 2C   6F 75 3D 43 6C 69 65 6E   Powers,ou=Clien
+0020: 74 31 2C 6F 75 3D 56 65   6E 64 6F 72 31 2C 6F 75  t1,ou=Vendor1,ou
+0030: 3D 41 64 64 2C 6F 3D 49   4D 43 2C 63 3D 55 53 A0  =Add,o=IMC,c=US.
+0040: 1B 30 19 04 17 32 2E 31   36 2E 38 34 30 2E 31 2E  .0...2.16.840.1.
+0050: 31 31 33 37 33 30 2E 33   2E 34 2E 32              113730.3.4.2
+
+
+# LDAP DeleteResponse
+
+0000: 30 0C 02 01 04 6B 07 0A   01 00 04 00 04 00        0....k........
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/com/sun/jndi/ldap/lib/LDAPTestUtils.java	Fri Feb 16 13:49:07 2018 -0800
@@ -0,0 +1,358 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+import com.sun.jndi.ldap.LdapURL;
+
+import javax.naming.Context;
+import javax.naming.NamingEnumeration;
+import javax.naming.NamingException;
+import javax.naming.directory.Attribute;
+import javax.naming.directory.Attributes;
+import javax.naming.directory.DirContext;
+import javax.naming.directory.SearchResult;
+import java.io.FileNotFoundException;
+import java.io.PrintStream;
+import java.net.ServerSocket;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.Enumeration;
+import java.util.Hashtable;
+import java.util.Vector;
+
+public class LDAPTestUtils {
+    public static final String TEST_LDAP_SERVER_THREAD = "test.ldap.server.thread";
+    public static final int CERTS_LOOKUP_MAX_DEPTH = 4;
+
+    protected static boolean debug = true;
+
+    /*
+     * Process command line arguments and return properties in a Hashtable.
+     */
+    public static Hashtable<Object, Object> initEnv(String testname,
+            String[] args) {
+        return initEnv(null, testname, args, false);
+    }
+
+    public static Hashtable<Object, Object> initEnv(ServerSocket socket,
+            String testname, String[] args, boolean authInfo) {
+
+        Hashtable<Object, Object> env = new Hashtable<>();
+        String root = "o=IMC,c=US";
+        String vendor = "Vendor1";
+        String client = "Client1";
+        String realm = "";
+        Vector<String> refs = new Vector<>();
+
+        // set defaults for some JNDI properties
+        env.put(Context.INITIAL_CONTEXT_FACTORY,
+                "com.sun.jndi.ldap.LdapCtxFactory");
+
+        if (authInfo) {
+            env.put(Context.SECURITY_AUTHENTICATION, "simple");
+            env.put(Context.SECURITY_PRINCIPAL, "cn=admin,o=IMC,c=US");
+            env.put(Context.SECURITY_CREDENTIALS, "secret99");
+        }
+
+        env.put("root", root);
+        env.put("vendor", vendor);
+        env.put("client", client);
+
+        boolean traceEnable = false;
+        for (int i = 0; i < args.length; i++) {
+            if (args[i].equals("-D") && (args.length > i + 1)) {
+                extractProperty(args[++i], env);
+            } else if (args[i].startsWith("-D")) {
+                extractProperty(args[i].substring(2), env);
+            } else if (args[i].equals("-referral") && (args.length > i + 1)) {
+                refs.addElement(args[++i]);
+            } else if (args[i].equals("-trace")) {
+                traceEnable = true;
+            }
+        }
+
+        env.put("disabled.realm", realm);
+
+        if (refs.size() > 0) {
+            env.put("referrals", refs);
+        }
+
+        if (traceEnable) {
+            enableLDAPTrace(env, testname);
+        } else {
+            if (socket != null) {
+                env.put(TEST_LDAP_SERVER_THREAD,
+                        startLDAPServer(socket, getCaptureFile(testname)));
+                env.put("java.naming.provider.url",
+                        "ldap://localhost:" + socket.getLocalPort());
+            } else {
+                // for tests which run against remote server or no server
+                // required
+                debug("Skip local LDAP Server creation "
+                        + "since ServerSocket is null");
+            }
+        }
+
+        return env;
+    }
+
+    /*
+     * Clean-up the directory context.
+     */
+    public static void cleanup(DirContext ctx) {
+        if (ctx != null) {
+            try {
+                ctx.close();
+            } catch (NamingException e) {
+                // ignore
+            }
+        }
+    }
+
+    /*
+     * Clean-up the sub context.
+     */
+    public static void cleanupSubcontext(DirContext ctx, String name) {
+        if (ctx != null) {
+            try {
+                ctx.destroySubcontext(name);
+            } catch (NamingException ne) {
+                // ignore
+            }
+        }
+    }
+
+    /*
+     * Assemble a distinguished name from the base components and the
+     * namespace root.
+     *
+     * The components are prefixed with 'dc=' if the root is a DC-style name.
+     * Otherwise they are prefixed with 'ou='.
+     */
+    public static String buildDN(String[] bases, String root) {
+
+        StringBuilder dn = new StringBuilder();
+        String prefix;
+
+        if (!root.contains("dc=")) {
+            prefix = "ou=";
+        } else {
+            prefix = "dc=";
+        }
+
+        for (String base : bases) {
+            dn.append(prefix).append(base).append(",");
+        }
+
+        return dn.append(root).toString();
+    }
+
+    /*
+     * Scan the results to confirm that the expected name is present.
+     */
+    public static int checkResult(NamingEnumeration results, String name)
+            throws NamingException {
+
+        return checkResult(results, new String[] { name }, null);
+    }
+
+    /*
+     * Scan the results to confirm that the expected names and attributes
+     * are present.
+     */
+    public static int checkResult(NamingEnumeration results, String[] names,
+            Attributes attrs) throws NamingException {
+
+        int found = 0;
+
+        while (results != null && results.hasMore()) {
+
+            SearchResult entry = (SearchResult) results.next();
+            String entryDN = entry.getName();
+
+            debug(">>> received: " + entryDN);
+
+            if (entry.isRelative()) {
+                entryDN = entryDN.toLowerCase(); // normalize
+            } else {
+                LdapURL url = new LdapURL(entryDN); // extract DN
+                entryDN = url.getDN().toLowerCase(); // normalize
+            }
+
+            for (String name : names) {
+                if ((entryDN.contains(name.toLowerCase())) || (entryDN
+                        .equalsIgnoreCase(name))) {
+
+                    debug(">>> checked results: found '" + name + "'");
+
+                    if (attrs == null || foundAttributes(entry, attrs)) {
+                        found++;
+                        break;
+                    }
+                }
+            }
+        }
+
+        debug(">>> checked results: found " + found
+                + " entries that meet the criteria.");
+
+        return found;
+    }
+
+    /*
+     * Confirm that the attributes are present in the entry.
+     */
+    public static boolean foundAttributes(SearchResult entry, Attributes attrs)
+            throws NamingException {
+
+        Attributes eattrs = entry.getAttributes();
+        int found = 0;
+
+        if ((eattrs == null) || (attrs == null)) {
+            return false;
+        }
+
+        for (NamingEnumeration ne = attrs.getAll(); ne.hasMoreElements(); ) {
+
+            Attribute attr = (Attribute) ne.next();
+
+            if (equalsIgnoreCase(eattrs.get(attr.getID()), attr)) {
+                found++;
+            } else {
+                debug(">>> foundAttributes: no match for " + attr.getID());
+            }
+        }
+        debug(">>> foundAttributes: found " + found + " attributes");
+        return (found == attrs.size());
+    }
+
+    public static Thread startLDAPServer(ServerSocket serverSocket,
+            String fileName) {
+        if (serverSocket == null) {
+            throw new RuntimeException("Error: failed to create LDAPServer "
+                    + "since ServerSocket is null");
+        }
+
+        if (!Files.exists(Paths.get(fileName))) {
+            throw new RuntimeException(
+                    "Error: failed to create LDAPServer, not found ldap "
+                            + "cache file " + fileName);
+        }
+
+        Thread thread = new Thread(() -> {
+            try {
+                new test.LDAPServer(serverSocket, fileName);
+            } catch (Exception e) {
+                System.out.println("Warning: LDAP server running with issue");
+                e.printStackTrace();
+            }
+        });
+
+        thread.start();
+        return thread;
+    }
+
+    private static boolean equalsIgnoreCase(Attribute received,
+            Attribute expected) {
+
+        if (received == null || !received.getID()
+                .equalsIgnoreCase(expected.getID())) {
+            return false;
+        }
+
+        try {
+
+            Enumeration expectedVals = expected.getAll();
+            Object obj;
+            while (expectedVals.hasMoreElements()) {
+                obj = expectedVals.nextElement();
+                if (!received.contains(obj)) {
+                    if (!(obj instanceof String)) {
+                        return false;
+                    }
+                    if (!received.contains(((String) obj).toLowerCase())) {
+                        return false;
+                    }
+                }
+            }
+
+        } catch (NamingException e) {
+            return false;
+        }
+
+        return true;
+    }
+
+    private static void extractProperty(String propString,
+            Hashtable<Object, Object> env) {
+        int index;
+
+        if ((index = propString.indexOf('=')) > 0) {
+            env.put(propString.substring(0, index),
+                    propString.substring(index + 1));
+        } else {
+            throw new RuntimeException(
+                    "Failed to extract test args property from " + propString);
+        }
+    }
+
+    private static void enableLDAPTrace(Hashtable<Object, Object> env,
+            String testname) {
+        try {
+            PrintStream outStream = new PrintStream(getCaptureFile(testname));
+            env.put("com.sun.jndi.ldap.trace.ber", outStream);
+        } catch (FileNotFoundException e) {
+            throw new RuntimeException(
+                    "Error: failed to enable ldap trace: " + e.getMessage(), e);
+        }
+    }
+
+    private static String getCaptureFile(String testname) {
+        return Paths.get(System.getProperty("test.src"))
+                .resolve(testname + ".ldap").toString();
+    }
+
+    public static void debug(Object object) {
+        if (debug) {
+            System.out.println(object);
+        }
+    }
+
+    public static String findCertsHome(int depth) {
+        Path path = Paths.get(System.getProperty("test.src", "."))
+                .toAbsolutePath();
+        for (int i = depth; i >= 0; i--) {
+            Path homePath = path.resolve("certs");
+            if (Files.exists(homePath) && Files.isDirectory(homePath)) {
+                return homePath.toString();
+            }
+
+            path = path.getParent();
+            if (path == null) {
+                break;
+            }
+        }
+
+        return System.getProperty("test.src", ".");
+    }
+}
--- a/test/jdk/java/lang/ClassLoader/forNameLeak/ClassForNameLeak.java	Fri Feb 16 12:24:38 2018 -0800
+++ b/test/jdk/java/lang/ClassLoader/forNameLeak/ClassForNameLeak.java	Fri Feb 16 13:49:07 2018 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -32,13 +32,13 @@
  * @run main/othervm/policy=test.policy -Djava.security.manager ClassForNameLeak
  */
 
+import java.io.IOException;
 import java.lang.ref.PhantomReference;
 import java.lang.ref.Reference;
 import java.lang.ref.ReferenceQueue;
+import java.net.MalformedURLException;
 import java.net.URL;
 import java.net.URLClassLoader;
-import java.nio.file.FileSystems;
-import java.nio.file.Files;
 import java.nio.file.Path;
 import java.nio.file.Paths;
 import java.util.List;
@@ -55,60 +55,61 @@
  */
 public class ClassForNameLeak {
     private static final long TIMEOUT = (long)(5000.0 * Utils.TIMEOUT_FACTOR);
-    private static final String TESTCLASSES = System.getProperty("test.classes", ".");
-    private static final String CLASSFILENAME = "ClassForName.class";
     private static final int THREADS = 10;
+    private static final Path jarFilePath = Paths.get("cfn.jar");
     private static final ReferenceQueue<ClassLoader> rq = new ReferenceQueue<>();
 
-    // Use a new classloader to load the ClassForName class, then run its
-    // Runnable.
-    public static PhantomReference<ClassLoader> loadAndRun(Path jarFilePath)
-            throws Exception {
-        ClassLoader classLoader = new URLClassLoader(
-                new URL[]{jarFilePath.toUri().toURL()}) {
-            @Override public String toString() { return "LeakedClassLoader"; }
-        };
+    static class TestLoader {
+        private final PhantomReference<ClassLoader> ref;
+        TestLoader() {
+            this.ref = loadAndRun();
+        }
 
-        Class<?> loadClass = Class.forName("ClassForName", true, classLoader);
-        ((Runnable) loadClass.newInstance()).run();
+        // Use a new classloader to load the ClassForName class, then run its
+        // Runnable.
+        PhantomReference<ClassLoader> loadAndRun() {
+            try {
+                ClassLoader classLoader =
+                    new URLClassLoader("LeakedClassLoader",
+                        new URL[]{jarFilePath.toUri().toURL()},
+                        ClassLoader.getPlatformClassLoader());
 
-        PhantomReference<ClassLoader> ref = new PhantomReference<>(classLoader, rq);
-        System.out.println("returning phantom ref: " + ref + " to " + classLoader);
-        return ref;
+                Class<?> loadClass = Class.forName("ClassForName", true, classLoader);
+                ((Runnable) loadClass.newInstance()).run();
+
+                return new PhantomReference<>(classLoader, rq);
+            } catch (MalformedURLException|ReflectiveOperationException e) {
+                throw new RuntimeException(e);
+            }
+        }
+
+        PhantomReference<ClassLoader> getRef() {
+            return ref;
+        }
     }
 
-    public static void main(final String[] args) throws Exception {
-        // Create a temporary .jar file containing ClassForName.class
-        Path testClassesDir = Paths.get(TESTCLASSES);
-        Path jarFilePath = Files.createTempFile("cfn", ".jar");
-        JarUtils.createJarFile(jarFilePath, testClassesDir, CLASSFILENAME);
-        jarFilePath.toFile().deleteOnExit();
-
-        // Remove the ClassForName.class file that jtreg built, to make sure
-        // we're loading from the tmp .jar
-        Path classFile = FileSystems.getDefault().getPath(TESTCLASSES,
-                                                          CLASSFILENAME);
-        Files.delete(classFile);
+    public static void main(String... args) throws Exception {
+        // create the JAR file
+        setup();
 
         // Make simultaneous calls to the test method, to stress things a bit
         ExecutorService es = Executors.newFixedThreadPool(THREADS);
 
-        List<Callable<PhantomReference<ClassLoader>>> callables =
+        List<Callable<TestLoader>> callables =
                 Stream.generate(() -> {
-                    Callable<PhantomReference<ClassLoader>> cprcl = () -> {
-                        return loadAndRun(jarFilePath);
-                    };
+                    Callable<TestLoader> cprcl = TestLoader::new;
                     return cprcl;
                 }).limit(THREADS).collect(Collectors.toList());
 
-        List<Future<PhantomReference<ClassLoader>>> refs = es.invokeAll(callables);
+        List<Future<TestLoader>> futures = es.invokeAll(callables);
 
         // Give the GC a chance to enqueue the PhantomReferences
         for (int i = 0; i < 10; i++) {
             System.gc();
         }
+
         // Make sure all PhantomReferences to the leaked classloader are enqueued
-        for (int j = 0; j < THREADS; j++) {
+        for (int j = 0; j < futures.size(); j++) {
             Reference rmRef = rq.remove(TIMEOUT);
             if (rmRef == null) {
                 throw new RuntimeException("ClassLoader was never enqueued!");
@@ -116,6 +117,16 @@
                 System.out.println("Enqueued " + rmRef);
             }
         }
-        System.out.println("All Classloaders successfully enqued");
+        es.shutdown();
+        System.out.println("All ClassLoaders successfully enqueued");
+    }
+
+    private static final String CLASSFILENAME = "ClassForName.class";
+    private static void setup() throws IOException {
+        String testclasses = System.getProperty("test.classes", ".");
+
+        // Create a temporary .jar file containing ClassForName.class
+        Path testClassesDir = Paths.get(testclasses);
+        JarUtils.createJarFile(jarFilePath, testClassesDir, CLASSFILENAME);
     }
 }
--- a/test/jdk/java/lang/ClassLoader/forNameLeak/test.policy	Fri Feb 16 12:24:38 2018 -0800
+++ b/test/jdk/java/lang/ClassLoader/forNameLeak/test.policy	Fri Feb 16 13:49:07 2018 -0800
@@ -2,5 +2,6 @@
   permission java.io.FilePermission "<<ALL FILES>>", "read, write, delete";
   permission java.lang.RuntimePermission "createClassLoader";
   permission java.lang.RuntimePermission "getClassLoader";
+  permission java.lang.RuntimePermission "modifyThread";
   permission java.util.PropertyPermission "*", "read"; /* for Utils */
 };
--- a/test/jdk/java/lang/ClassLoader/nativeLibrary/NativeLibraryTest.java	Fri Feb 16 12:24:38 2018 -0800
+++ b/test/jdk/java/lang/ClassLoader/nativeLibrary/NativeLibraryTest.java	Fri Feb 16 13:49:07 2018 -0800
@@ -24,6 +24,7 @@
 /*
  * @test
  * @bug 8164512 8191360
+ * @requires vm.compMode != "Xcomp"
  * @summary verify if the native library is unloaded when the class loader is GC'ed
  * @build p.Test
  * @run main/othervm/native -Xcheck:jni NativeLibraryTest
--- a/test/jdk/java/lang/invoke/condy/ConstantBootstrapsTest.java	Fri Feb 16 12:24:38 2018 -0800
+++ b/test/jdk/java/lang/invoke/condy/ConstantBootstrapsTest.java	Fri Feb 16 13:49:07 2018 -0800
@@ -25,6 +25,7 @@
  * @test
  * @bug 8186046 8195694
  * @summary Test dynamic constant bootstraps
+ * @requires os.arch != "sparcv9"
  * @library /lib/testlibrary/bytecode /java/lang/invoke/common
  * @build jdk.experimental.bytecode.BasicClassBuilder test.java.lang.invoke.lib.InstructionHelper
  * @run testng ConstantBootstrapsTest
--- a/test/jdk/java/util/regex/RegExTest.java	Fri Feb 16 12:24:38 2018 -0800
+++ b/test/jdk/java/util/regex/RegExTest.java	Fri Feb 16 13:49:07 2018 -0800
@@ -35,7 +35,7 @@
  * 8027645 8035076 8039124 8035975 8074678 6854417 8143854 8147531 7071819
  * 8151481 4867170 7080302 6728861 6995635 6736245 4916384 6328855 6192895
  * 6345469 6988218 6693451 7006761 8140212 8143282 8158482 8176029 8184706
- * 8194667
+ * 8194667 8197462
  *
  * @library /test/lib
  * @build jdk.test.lib.RandomFactory
@@ -168,6 +168,7 @@
         embeddedFlags();
         grapheme();
         expoBacktracking();
+        invalidGroupName();
 
         if (failure) {
             throw new
@@ -4870,4 +4871,41 @@
             }
         }
     }
+
+    private static void invalidGroupName() {
+        // Invalid start of a group name
+        for (String groupName : List.of("", ".", "0", "\u0040", "\u005b",
+                "\u0060", "\u007b", "\u0416")) {
+            for (String pat : List.of("(?<" + groupName + ">)",
+                    "\\k<" + groupName + ">")) {
+                try {
+                    Pattern.compile(pat);
+                    failCount++;
+                } catch (PatternSyntaxException e) {
+                    if (!e.getMessage().startsWith(
+                            "capturing group name does not start with a"
+                            + " Latin letter")) {
+                        failCount++;
+                    }
+                }
+            }
+        }
+        // Invalid char in a group name
+        for (String groupName : List.of("a.", "b\u0040", "c\u005b",
+                "d\u0060", "e\u007b", "f\u0416")) {
+            for (String pat : List.of("(?<" + groupName + ">)",
+                    "\\k<" + groupName + ">")) {
+                try {
+                    Pattern.compile(pat);
+                    failCount++;
+                } catch (PatternSyntaxException e) {
+                    if (!e.getMessage().startsWith(
+                            "named capturing group is missing trailing '>'")) {
+                        failCount++;
+                    }
+                }
+            }
+        }
+        report("Invalid capturing group names");
+    }
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/javax/script/JDK_8196959/BadFactory.java	Fri Feb 16 13:49:07 2018 -0800
@@ -0,0 +1,80 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+import javax.script.*;
+import java.util.*;
+
+// do many bad things to prevent ScriptEngineManager to run correctly
+public class BadFactory implements ScriptEngineFactory {
+    public String getEngineName() {
+        return null;
+    }
+
+    public String getEngineVersion() {
+        return null;
+    }
+
+    public List<String> getExtensions() {
+        return null;
+    }
+
+    public String getLanguageName() {
+        return null;
+    }
+
+    public String getLanguageVersion() {
+        return null;
+    }
+
+    public String getMethodCallSyntax(String obj, String m, String[] args) {
+        return null;
+    }
+
+    public List<String> getMimeTypes() {
+        List<String> list = new ArrayList<String>();
+        list.add("application/bad");
+        list.add(null);
+        list.add("");
+        return list;
+    }
+
+    public List<String> getNames() {
+        throw new IllegalArgumentException();
+    }
+
+    public String getOutputStatement(String str) {
+        return "bad-factory-output";
+    }
+
+    public String getParameter(String key) {
+        return null;
+    }
+
+    public String getProgram(String[] statements) {
+        return null;
+    }
+
+    public ScriptEngine getScriptEngine() {
+        return null;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/javax/script/JDK_8196959/BadFactoryTest.java	Fri Feb 16 13:49:07 2018 -0800
@@ -0,0 +1,30 @@
+/**
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+import javax.script.ScriptEngineManager;
+
+public class BadFactoryTest {
+    public static void main(String[] args) {
+        ScriptEngineManager m = new ScriptEngineManager();
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/javax/script/JDK_8196959/BadFactoryTest.sh	Fri Feb 16 13:49:07 2018 -0800
@@ -0,0 +1,60 @@
+#
+# Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+#
+# This code is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License version 2 only, as
+# published by the Free Software Foundation.
+#
+# This code is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+# FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+# version 2 for more details (a copy is included in the LICENSE file that
+# accompanied this code).
+#
+# You should have received a copy of the GNU General Public License version
+# 2 along with this work; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+#
+# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+# or visit www.oracle.com if you need additional information or have any
+# questions.
+#
+
+# @test
+# @bug 8196959
+# @summary BadFactory that results in NPE being thrown from ScriptEngineManager
+#
+# @build BadFactory BadFactoryTest
+# @run shell BadFactoryTest.sh
+
+if [ "${TESTSRC}" = "" ]
+then
+  echo "TESTSRC not set.  Test cannot execute.  Failed."
+  exit 1
+fi
+
+. ${TESTSRC}/../CommonSetup.sh
+
+echo "Creating JAR file ..."
+
+$JAR ${TESTTOOLVMOPTS} -cf ${TESTCLASSES}/badfactory.jar \
+    -C ${TESTCLASSES} BadFactory.class \
+    -C ${TESTCLASSES} BadFactoryTest.class \
+    -C "${TESTSRC}" META-INF/services/javax.script.ScriptEngineFactory
+
+echo "Running test with security manager ..."
+$JAVA ${TESTVMOPTS} -Djava.security.manager -classpath \
+  "${TESTCLASSES}${PS}${TESTCLASSES}/badfactory.jar" \
+  BadFactoryTest
+
+ret=$?
+if [ $ret -ne 0 ]
+then
+  exit $ret
+fi
+
+echo "Running test without security manager ..."
+$JAVA ${TESTVMOPTS} -classpath \
+  "${TESTCLASSES}${PS}${TESTCLASSES}/badfactoty.jar" \
+  BadFactoryTest
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/javax/script/JDK_8196959/META-INF/services/javax.script.ScriptEngineFactory	Fri Feb 16 13:49:07 2018 -0800
@@ -0,0 +1,2 @@
+# Factory that does many bad things to stress ScriptEngineManager
+BadFactory
--- a/test/jdk/sun/misc/SunMiscSignalTest.java	Fri Feb 16 12:24:38 2018 -0800
+++ b/test/jdk/sun/misc/SunMiscSignalTest.java	Fri Feb 16 13:49:07 2018 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -112,7 +112,6 @@
         Object[][] posixSignals = {
                 {"HUP",  IsSupported.YES, registerXrs, raiseXrs, invokedXrs},
                 {"QUIT", IsSupported.YES, CanRegister.NO, CanRaise.NO, Invoked.NO},
-                {"BUS",  IsSupported.YES, CanRegister.YES, CanRaise.YES, invokedXrs},
                 {"USR1", IsSupported.YES, CanRegister.YES, CanRaise.YES, invokedXrs},
                 {"USR2", IsSupported.YES, CanRegister.YES, CanRaise.YES, invokedXrs},
                 {"PIPE", IsSupported.YES, CanRegister.YES, CanRaise.YES, invokedXrs},
@@ -132,6 +131,14 @@
                 {"SYS",   IsSupported.YES, CanRegister.YES, CanRaise.YES, invokedXrs},
         };
 
+        Object[][] posixNonOSXSignals = {
+                {"BUS",  IsSupported.YES, CanRegister.YES, CanRaise.YES, invokedXrs},
+        };
+
+        Object[][] posixOSXSignals = {
+                {"BUS",  IsSupported.YES, CanRegister.NO, CanRaise.NO, Invoked.NO},
+        };
+
         Object[][] windowsSignals = {
                 {"HUP",  IsSupported.NO, CanRegister.NO, CanRaise.NO, Invoked.NO},
                 {"QUIT", IsSupported.NO, CanRegister.NO, CanRaise.NO, Invoked.NO},
@@ -155,7 +162,9 @@
                 {"SYS",  IsSupported.NO, CanRegister.NO, CanRaise.NO, Invoked.NO},
         };
 
-        return concatArrays(commonSignals, (Platform.isWindows() ? windowsSignals : posixSignals));
+        Object[][] combinedPosixSignals = concatArrays(posixSignals,
+                                                       (Platform.isOSX() ? posixOSXSignals : posixNonOSXSignals));
+        return concatArrays(commonSignals, (Platform.isWindows() ? windowsSignals : combinedPosixSignals));
     }
 
     // Provider of invalid signal names
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/sun/net/www/protocol/jar/CanonicalizationTest.java	Fri Feb 16 13:49:07 2018 -0800
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/**
+ * @test
+ * @bug 8197849
+ * @summary Sanity test the special canonicalization logic for jar resources
+ */
+
+import java.net.URL;
+
+public class CanonicalizationTest {
+    public static void main(String args[]) throws Exception {
+        URL base = new URL("jar:file:/foo!/");
+
+        check(new URL(base, ""), "jar:file:/foo!/");
+        check(new URL(base, "."), "jar:file:/foo!/");
+        check(new URL(base, ".."), "jar:file:/foo!");
+        check(new URL(base, ".x"), "jar:file:/foo!/.x");
+        check(new URL(base, "..x"), "jar:file:/foo!/..x");
+        check(new URL(base, "..."), "jar:file:/foo!/...");
+        check(new URL(base, "foo/."), "jar:file:/foo!/foo/");
+        check(new URL(base, "foo/.."), "jar:file:/foo!/");
+        check(new URL(base, "foo/.x"), "jar:file:/foo!/foo/.x");
+        check(new URL(base, "foo/..x"), "jar:file:/foo!/foo/..x");
+        check(new URL(base, "foo/..."), "jar:file:/foo!/foo/...");
+        check(new URL(base, "foo/./"), "jar:file:/foo!/foo/");
+        check(new URL(base, "foo/../"), "jar:file:/foo!/");
+        check(new URL(base, "foo/.../"), "jar:file:/foo!/foo/.../");
+        check(new URL(base, "foo/../../"), "jar:file:/foo!/");
+        check(new URL(base, "foo/../,,/.."), "jar:file:/foo!/");
+        check(new URL(base, "foo/../."), "jar:file:/foo!/");
+        check(new URL(base, "foo/../.x"), "jar:file:/foo!/.x");
+    }
+
+    private static void check(URL url, String expected) {
+        if (!url.toString().equals(expected)) {
+            throw new AssertionError("Expected " + url + " to equal " + expected);
+        }
+    }
+}
--- a/test/jdk/sun/security/tools/jarsigner/TimestampCheck.java	Fri Feb 16 12:24:38 2018 -0800
+++ b/test/jdk/sun/security/tools/jarsigner/TimestampCheck.java	Fri Feb 16 13:49:07 2018 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2003, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2018, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -79,6 +79,7 @@
  *        jdk.test.lib.JDKToolLauncher
  *        jdk.test.lib.Platform
  *        jdk.test.lib.process.*
+ * @compile -XDignore.symbol.file TimestampCheck.java
  * @run main/timeout=600 TimestampCheck
  */
 public class TimestampCheck {
@@ -126,12 +127,12 @@
         byte[] sign(byte[] input, String path) throws Exception {
 
             DerValue value = new DerValue(input);
-            System.out.println("\nIncoming Request\n===================");
-            System.out.println("Version: " + value.data.getInteger());
+            System.out.println("#\n# Incoming Request\n===================");
+            System.out.println("# Version: " + value.data.getInteger());
             DerValue messageImprint = value.data.getDerValue();
             AlgorithmId aid = AlgorithmId.parse(
                     messageImprint.data.getDerValue());
-            System.out.println("AlgorithmId: " + aid);
+            System.out.println("# AlgorithmId: " + aid);
 
             ObjectIdentifier policyId = new ObjectIdentifier(defaultPolicyId);
             BigInteger nonce = null;
@@ -139,16 +140,16 @@
                 DerValue v = value.data.getDerValue();
                 if (v.tag == DerValue.tag_Integer) {
                     nonce = v.getBigInteger();
-                    System.out.println("nonce: " + nonce);
+                    System.out.println("# nonce: " + nonce);
                 } else if (v.tag == DerValue.tag_Boolean) {
-                    System.out.println("certReq: " + v.getBoolean());
+                    System.out.println("# certReq: " + v.getBoolean());
                 } else if (v.tag == DerValue.tag_ObjectId) {
                     policyId = v.getOID();
-                    System.out.println("PolicyID: " + policyId);
+                    System.out.println("# PolicyID: " + policyId);
                 }
             }
 
-            System.out.println("\nResponse\n===================");
+            System.out.println("#\n# Response\n===================");
             KeyStore ks = KeyStore.getInstance(
                     new File(keystore), "changeit".toCharArray());
 
@@ -232,10 +233,10 @@
                     "1.2.840.113549.1.9.16.1.4"),
                     new DerValue(tstInfo2.toByteArray()));
 
-            System.out.println("Signing...");
-            System.out.println(new X500Name(signer
+            System.out.println("# Signing...");
+            System.out.println("# " + new X500Name(signer
                     .getIssuerX500Principal().getName()));
-            System.out.println(signer.getSerialNumber());
+            System.out.println("# " + signer.getSerialNumber());
 
             SignerInfo signerInfo = new SignerInfo(
                     new X500Name(signer.getIssuerX500Principal().getName()),
@@ -306,8 +307,6 @@
 
     public static void main(String[] args) throws Throwable {
 
-        prepare();
-
         try (Handler tsa = Handler.init(0, "ks");) {
             tsa.start();
             int port = tsa.getPort();
@@ -315,62 +314,99 @@
 
             if (args.length == 0) {         // Run this test
 
+                prepare();
+
                 sign("normal")
                         .shouldNotContain("Warning")
+                        .shouldContain("The signer certificate will expire on")
+                        .shouldContain("The timestamp will expire on")
                         .shouldHaveExitValue(0);
 
                 verify("normal.jar")
                         .shouldNotContain("Warning")
                         .shouldHaveExitValue(0);
 
+                verify("normal.jar", "-verbose")
+                        .shouldNotContain("Warning")
+                        .shouldContain("The signer certificate will expire on")
+                        .shouldContain("The timestamp will expire on")
+                        .shouldHaveExitValue(0);
+
                 // Simulate signing at a previous date:
                 // 1. tsold will create a timestamp of 20 days ago.
                 // 2. oldsigner expired 10 days ago.
-                // jarsigner will show a warning at signing.
                 signVerbose("tsold", "unsigned.jar", "tsold.jar", "oldsigner")
-                        .shouldHaveExitValue(4);
+                        .shouldNotContain("Warning")
+                        .shouldMatch("signer certificate expired on .*. "
+                                + "However, the JAR will be valid")
+                        .shouldHaveExitValue(0);
 
                 // It verifies perfectly.
                 verify("tsold.jar", "-verbose", "-certs")
                         .shouldNotContain("Warning")
+                        .shouldMatch("signer certificate expired on .*. "
+                                + "However, the JAR will be valid")
                         .shouldHaveExitValue(0);
 
+                // No timestamp
                 signVerbose(null, "unsigned.jar", "none.jar", "signer")
                         .shouldContain("is not timestamped")
+                        .shouldContain("The signer certificate will expire on")
                         .shouldHaveExitValue(0);
 
+                verify("none.jar", "-verbose")
+                        .shouldContain("do not include a timestamp")
+                        .shouldContain("The signer certificate will expire on")
+                        .shouldHaveExitValue(0);
+
+                // Error cases
+
                 signVerbose(null, "unsigned.jar", "badku.jar", "badku")
+                        .shouldContain("KeyUsage extension doesn't allow code signing")
                         .shouldHaveExitValue(8);
                 checkBadKU("badku.jar");
 
                 // 8180289: unvalidated TSA cert chain
                 sign("tsnoca")
-                        .shouldContain("TSA certificate chain is invalid")
+                        .shouldContain("The TSA certificate chain is invalid. "
+                                + "Reason: Path does not chain with any of the trust anchors")
                         .shouldHaveExitValue(64);
 
                 verify("tsnoca.jar", "-verbose", "-certs")
                         .shouldHaveExitValue(64)
                         .shouldContain("jar verified")
-                        .shouldContain("Invalid TSA certificate chain")
-                        .shouldContain("TSA certificate chain is invalid");
+                        .shouldContain("Invalid TSA certificate chain: "
+                                + "Path does not chain with any of the trust anchors")
+                        .shouldContain("TSA certificate chain is invalid."
+                                + " Reason: Path does not chain with any of the trust anchors");
 
                 sign("nononce")
+                        .shouldContain("Nonce missing in timestamp token")
                         .shouldHaveExitValue(1);
                 sign("diffnonce")
+                        .shouldContain("Nonce changed in timestamp token")
                         .shouldHaveExitValue(1);
                 sign("baddigest")
+                        .shouldContain("Digest octets changed in timestamp token")
                         .shouldHaveExitValue(1);
                 sign("diffalg")
+                        .shouldContain("Digest algorithm not")
                         .shouldHaveExitValue(1);
+
                 sign("fullchain")
                         .shouldHaveExitValue(0);   // Success, 6543440 solved.
+
                 sign("tsbad1")
+                        .shouldContain("Certificate is not valid for timestamping")
                         .shouldHaveExitValue(1);
                 sign("tsbad2")
+                        .shouldContain("Certificate is not valid for timestamping")
                         .shouldHaveExitValue(1);
                 sign("tsbad3")
+                        .shouldContain("Certificate is not valid for timestamping")
                         .shouldHaveExitValue(1);
                 sign("nocert")
+                        .shouldContain("Certificate not included in timestamp token")
                         .shouldHaveExitValue(1);
 
                 sign("policy", "-tsapolicyid",  "1.2.3")
@@ -378,6 +414,7 @@
                 checkTimestamp("policy.jar", "1.2.3", "SHA-256");
 
                 sign("diffpolicy", "-tsapolicyid", "1.2.3")
+                        .shouldContain("TSAPolicyID changed in timestamp token")
                         .shouldHaveExitValue(1);
 
                 sign("sha1alg", "-tsadigestalg", "SHA")
@@ -387,6 +424,7 @@
                 sign("tsweak", "-digestalg", "MD5",
                                 "-sigalg", "MD5withRSA", "-tsadigestalg", "MD5")
                         .shouldHaveExitValue(68)
+                        .shouldContain("The timestamp is invalid. Without a valid timestamp")
                         .shouldMatch("MD5.*-digestalg.*risk")
                         .shouldMatch("MD5.*-tsadigestalg.*risk")
                         .shouldMatch("MD5withRSA.*-sigalg.*risk");
@@ -394,6 +432,7 @@
 
                 signVerbose("tsweak", "unsigned.jar", "tsweak2.jar", "signer")
                         .shouldHaveExitValue(64)
+                        .shouldContain("The timestamp is invalid. Without a valid timestamp")
                         .shouldContain("TSA certificate chain is invalid");
 
                 // Weak timestamp is an error and jar treated unsigned
@@ -402,19 +441,26 @@
                         .shouldContain("treated as unsigned")
                         .shouldMatch("Timestamp.*512.*weak");
 
+                // Algorithm used in signing is weak
                 signVerbose("normal", "unsigned.jar", "halfWeak.jar", "signer",
                         "-digestalg", "MD5")
+                        .shouldContain("-digestalg option is considered a security risk")
                         .shouldHaveExitValue(4);
                 checkHalfWeak("halfWeak.jar");
 
                 // sign with DSA key
                 signVerbose("normal", "unsigned.jar", "sign1.jar", "dsakey")
                         .shouldHaveExitValue(0);
+
                 // sign with RSAkeysize < 1024
                 signVerbose("normal", "sign1.jar", "sign2.jar", "weakkeysize")
+                        .shouldContain("Algorithm constraints check failed on keysize")
                         .shouldHaveExitValue(4);
                 checkMultiple("sign2.jar");
 
+                // 8191438: jarsigner should print when a timestamp will expire
+                checkExpiration();
+
                 // When .SF or .RSA is missing or invalid
                 checkMissingOrInvalidFiles("normal.jar");
 
@@ -422,12 +468,118 @@
                     checkInvalidTsaCertKeyUsage();
                 }
             } else {                        // Run as a standalone server
-                System.out.println("Press Enter to quit server");
+                System.out.println("TSA started at " + host
+                        + ". Press Enter to quit server");
                 System.in.read();
             }
         }
     }
 
+    private static void checkExpiration() throws Exception {
+
+        // Warning when expired or expiring
+        signVerbose(null, "unsigned.jar", "expired.jar", "expired")
+                .shouldContain("signer certificate has expired")
+                .shouldHaveExitValue(4);
+        verify("expired.jar")
+                .shouldContain("signer certificate has expired")
+                .shouldHaveExitValue(4);
+        signVerbose(null, "unsigned.jar", "expiring.jar", "expiring")
+                .shouldContain("signer certificate will expire within")
+                .shouldHaveExitValue(0);
+        verify("expiring.jar")
+                .shouldContain("signer certificate will expire within")
+                .shouldHaveExitValue(0);
+        // Info for long
+        signVerbose(null, "unsigned.jar", "long.jar", "long")
+                .shouldNotContain("signer certificate has expired")
+                .shouldNotContain("signer certificate will expire within")
+                .shouldContain("signer certificate will expire on")
+                .shouldHaveExitValue(0);
+        verify("long.jar")
+                .shouldNotContain("signer certificate has expired")
+                .shouldNotContain("signer certificate will expire within")
+                .shouldNotContain("The signer certificate will expire")
+                .shouldHaveExitValue(0);
+        verify("long.jar", "-verbose")
+                .shouldContain("The signer certificate will expire")
+                .shouldHaveExitValue(0);
+
+        // Both expired
+        signVerbose("tsexpired", "unsigned.jar",
+                "tsexpired-expired.jar", "expired")
+                .shouldContain("The signer certificate has expired.")
+                .shouldContain("The timestamp has expired.")
+                .shouldHaveExitValue(4);
+        verify("tsexpired-expired.jar")
+                .shouldContain("signer certificate has expired")
+                .shouldContain("timestamp has expired.")
+                .shouldHaveExitValue(4);
+
+        // TS expired but signer still good
+        signVerbose("tsexpired", "unsigned.jar",
+                "tsexpired-long.jar", "long")
+                .shouldContain("The timestamp expired on")
+                .shouldHaveExitValue(0);
+        verify("tsexpired-long.jar")
+                .shouldMatch("timestamp expired on.*However, the JAR will be valid")
+                .shouldNotContain("Error")
+                .shouldHaveExitValue(0);
+
+        signVerbose("tsexpired", "unsigned.jar",
+                "tsexpired-ca.jar", "ca")
+                .shouldContain("The timestamp has expired.")
+                .shouldHaveExitValue(4);
+        verify("tsexpired-ca.jar")
+                .shouldNotContain("timestamp has expired")
+                .shouldNotContain("Error")
+                .shouldHaveExitValue(0);
+
+        // Warning when expiring
+        sign("tsexpiring")
+                .shouldContain("timestamp will expire within")
+                .shouldHaveExitValue(0);
+        verify("tsexpiring.jar")
+                .shouldContain("timestamp will expire within")
+                .shouldNotContain("still valid")
+                .shouldHaveExitValue(0);
+
+        signVerbose("tsexpiring", "unsigned.jar",
+                "tsexpiring-ca.jar", "ca")
+                .shouldContain("self-signed")
+                .stderrShouldNotMatch("The.*expir")
+                .shouldHaveExitValue(4); // self-signed
+        verify("tsexpiring-ca.jar")
+                .stderrShouldNotMatch("The.*expir")
+                .shouldHaveExitValue(0);
+
+        signVerbose("tsexpiringsoon", "unsigned.jar",
+                "tsexpiringsoon-long.jar", "long")
+                .shouldContain("The timestamp will expire")
+                .shouldHaveExitValue(0);
+        verify("tsexpiringsoon-long.jar")
+                .shouldMatch("timestamp will expire.*However, the JAR will be valid until")
+                .shouldHaveExitValue(0);
+
+        // Info for long
+        sign("tslong")
+                .shouldNotContain("timestamp has expired")
+                .shouldNotContain("timestamp will expire within")
+                .shouldContain("timestamp will expire on")
+                .shouldContain("signer certificate will expire on")
+                .shouldHaveExitValue(0);
+        verify("tslong.jar")
+                .shouldNotContain("timestamp has expired")
+                .shouldNotContain("timestamp will expire within")
+                .shouldNotContain("timestamp will expire on")
+                .shouldNotContain("signer certificate will expire on")
+                .shouldHaveExitValue(0);
+        verify("tslong.jar", "-verbose")
+                .shouldContain("timestamp will expire on")
+                .shouldContain("signer certificate will expire on")
+                .shouldHaveExitValue(0);
+    }
+
     private static void checkInvalidTsaCertKeyUsage() throws Exception {
 
         // Hack: Rewrite the TSA cert inside normal.jar into ts2.jar.
@@ -680,6 +832,14 @@
         keytool("-alias tsbad3 -genkeypair -dname CN=tsbad3");
         keytool("-alias tsnoca -genkeypair -dname CN=tsnoca");
 
+        keytool("-alias expired -genkeypair -dname CN=expired");
+        keytool("-alias expiring -genkeypair -dname CN=expiring");
+        keytool("-alias long -genkeypair -dname CN=long");
+        keytool("-alias tsexpired -genkeypair -dname CN=tsexpired");
+        keytool("-alias tsexpiring -genkeypair -dname CN=tsexpiring");
+        keytool("-alias tsexpiringsoon -genkeypair -dname CN=tsexpiringsoon");
+        keytool("-alias tslong -genkeypair -dname CN=tslong");
+
         // tsnoca's issuer will be removed from keystore later
         keytool("-alias ca -genkeypair -ext bc -dname CN=CA");
         gencert("tsnoca", "-ext eku:critical=ts");
@@ -691,7 +851,15 @@
         gencert("dsakey");
         gencert("weakkeysize");
         gencert("badku", "-ext ku:critical=keyAgreement");
-        gencert("ts", "-ext eku:critical=ts");
+        gencert("ts", "-ext eku:critical=ts -validity 500");
+
+        gencert("expired", "-validity 10 -startdate -12d");
+        gencert("expiring", "-validity 178");
+        gencert("long", "-validity 182");
+        gencert("tsexpired", "-ext eku:critical=ts -validity 10 -startdate -12d");
+        gencert("tsexpiring", "-ext eku:critical=ts -validity 364");
+        gencert("tsexpiringsoon", "-ext eku:critical=ts -validity 170"); // earlier than expiring
+        gencert("tslong", "-ext eku:critical=ts -validity 367");
 
 
         for (int i = 0; i < 5; i++) {
@@ -711,7 +879,7 @@
             }
         }
 
-        gencert("tsold", "-ext eku:critical=ts -startdate -40d -validity 45");
+        gencert("tsold", "-ext eku:critical=ts -startdate -40d -validity 500");
 
         gencert("tsweak", "-ext eku:critical=ts");
         gencert("tsbad1");
--- a/test/jdk/sun/security/tools/jarsigner/warnings/AliasNotInStoreTest.java	Fri Feb 16 12:24:38 2018 -0800
+++ b/test/jdk/sun/security/tools/jarsigner/warnings/AliasNotInStoreTest.java	Fri Feb 16 13:49:07 2018 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -51,32 +51,12 @@
         JarUtils.createJar(UNSIGNED_JARFILE, FIRST_FILE);
 
         // create first key pair for signing
-        keytool(
-                "-genkey",
-                "-alias", FIRST_KEY_ALIAS,
-                "-keyalg", KEY_ALG,
-                "-keysize", Integer.toString(KEY_SIZE),
-                "-keystore", BOTH_KEYS_KEYSTORE,
-                "-storepass", PASSWORD,
-                "-keypass", PASSWORD,
-                "-dname", "CN=First",
-                "-validity", Integer.toString(VALIDITY)).shouldHaveExitValue(0);
-
-        // create second key pair for signing
-        keytool(
-                "-genkey",
-                "-alias", SECOND_KEY_ALIAS,
-                "-keyalg", KEY_ALG,
-                "-keysize", Integer.toString(KEY_SIZE),
-                "-keystore", BOTH_KEYS_KEYSTORE,
-                "-storepass", PASSWORD,
-                "-keypass", PASSWORD,
-                "-dname", "CN=Second",
-                "-validity", Integer.toString(VALIDITY)).shouldHaveExitValue(0);
+        createAlias(FIRST_KEY_ALIAS);
+        createAlias(SECOND_KEY_ALIAS);
 
         // sign jar with first key
         OutputAnalyzer analyzer = jarsigner(
-                "-keystore", BOTH_KEYS_KEYSTORE,
+                "-keystore", KEYSTORE,
                 "-storepass", PASSWORD,
                 "-keypass", PASSWORD,
                 "-signedjar", SIGNED_JARFILE,
@@ -93,7 +73,7 @@
 
         // sign jar with second key
         analyzer = jarsigner(
-                "-keystore", BOTH_KEYS_KEYSTORE,
+                "-keystore", KEYSTORE,
                 "-storepass", PASSWORD,
                 "-keypass", PASSWORD,
                 UPDATED_SIGNED_JARFILE,
@@ -104,7 +84,7 @@
         // create keystore that contains only first key
         keytool(
                 "-importkeystore",
-                "-srckeystore", BOTH_KEYS_KEYSTORE,
+                "-srckeystore", KEYSTORE,
                 "-srcalias", FIRST_KEY_ALIAS,
                 "-srcstorepass", PASSWORD,
                 "-srckeypass", PASSWORD,
@@ -113,7 +93,7 @@
                 "-deststorepass", PASSWORD,
                 "-destkeypass", PASSWORD).shouldHaveExitValue(0);
 
-        // verify jar with keystore that contains only first key in strict mode,
+        // verify jar with keystore that contains only first key,
         // so there is signed entry (FirstClass.class) that is not signed
         // by any alias in the keystore
         analyzer = jarsigner(
--- a/test/jdk/sun/security/tools/jarsigner/warnings/BadExtendedKeyUsageTest.java	Fri Feb 16 12:24:38 2018 -0800
+++ b/test/jdk/sun/security/tools/jarsigner/warnings/BadExtendedKeyUsageTest.java	Fri Feb 16 13:49:07 2018 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -52,17 +52,14 @@
 
         // create a certificate whose signer certificate's
         // ExtendedKeyUsage extension doesn't allow code signing
-        keytool(
-                "-genkey",
-                "-alias", KEY_ALIAS,
-                "-keyalg", KEY_ALG,
-                "-keysize", Integer.toString(KEY_SIZE),
-                "-keystore", KEYSTORE,
-                "-storepass", PASSWORD,
-                "-keypass", PASSWORD,
-                "-dname", "CN=Test",
+        // create key pair for jar signing
+        createAlias(CA_KEY_ALIAS);
+        createAlias(KEY_ALIAS);
+
+        issueCert(
+                KEY_ALIAS,
                 "-ext", "ExtendedkeyUsage=serverAuth",
-                "-validity", Integer.toString(VALIDITY)).shouldHaveExitValue(0);
+                "-validity", Integer.toString(VALIDITY));
 
         // sign jar
         OutputAnalyzer analyzer = jarsigner(
--- a/test/jdk/sun/security/tools/jarsigner/warnings/BadKeyUsageTest.java	Fri Feb 16 12:24:38 2018 -0800
+++ b/test/jdk/sun/security/tools/jarsigner/warnings/BadKeyUsageTest.java	Fri Feb 16 13:49:07 2018 -0800
@@ -53,17 +53,13 @@
 
         // create a certificate whose signer certificate's KeyUsage extension
         // doesn't allow code signing
-        keytool(
-                "-genkey",
-                "-alias", KEY_ALIAS,
-                "-keyalg", KEY_ALG,
-                "-keysize", Integer.toString(KEY_SIZE),
-                "-keystore", KEYSTORE,
-                "-storepass", PASSWORD,
-                "-keypass", PASSWORD,
-                "-dname", "CN=Test",
+        createAlias(CA_KEY_ALIAS);
+        createAlias(KEY_ALIAS);
+
+        issueCert(
+                KEY_ALIAS,
                 "-ext", "KeyUsage=keyAgreement",
-                "-validity", Integer.toString(VALIDITY)).shouldHaveExitValue(0);
+                "-validity", Integer.toString(VALIDITY));
 
         // sign jar
         OutputAnalyzer analyzer = jarsigner(
--- a/test/jdk/sun/security/tools/jarsigner/warnings/BadNetscapeCertTypeTest.java	Fri Feb 16 12:24:38 2018 -0800
+++ b/test/jdk/sun/security/tools/jarsigner/warnings/BadNetscapeCertTypeTest.java	Fri Feb 16 13:49:07 2018 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -24,10 +24,6 @@
 import jdk.testlibrary.OutputAnalyzer;
 import jdk.test.lib.util.JarUtils;
 
-import java.nio.file.Files;
-import java.nio.file.Paths;
-import java.util.Base64;
-
 /**
  * @test
  * @bug 8024302 8026037
@@ -38,25 +34,14 @@
  */
 public class BadNetscapeCertTypeTest extends Test {
 
-    private static final String NETSCAPE_KEYSTORE_BASE64 = TEST_SOURCES + FS
-            + "bad_netscape_cert_type.jks.base64";
-
-    private static final String NETSCAPE_KEYSTORE
-            = "bad_netscape_cert_type.jks";
-
     /**
      * The test signs and verifies a jar that contains entries
      * whose signer certificate's NetscapeCertType extension
      * doesn't allow code signing (badNetscapeCertType).
      * Warning message is expected.
-     * Run bad_netscape_cert_type.sh script to create bad_netscape_cert_type.jks
      */
     public static void main(String[] args) throws Throwable {
 
-        Files.write(Paths.get(NETSCAPE_KEYSTORE),
-                Base64.getMimeDecoder().decode(
-                    Files.readAllBytes(Paths.get(NETSCAPE_KEYSTORE_BASE64))));
-
         BadNetscapeCertTypeTest test = new BadNetscapeCertTypeTest();
         test.start();
     }
@@ -66,10 +51,22 @@
         Utils.createFiles(FIRST_FILE);
         JarUtils.createJar(UNSIGNED_JARFILE, FIRST_FILE);
 
+        // create a certificate whose signer certificate's
+        // NetscapeCertType extension doesn't allow code signing
+        // create key pair for jar signing
+        createAlias(CA_KEY_ALIAS);
+        createAlias(KEY_ALIAS);
+
+        issueCert(
+                KEY_ALIAS,
+                // NetscapeCertType [ SSL client ]
+                "-ext", "2.16.840.1.113730.1.1=03020780",
+                "-validity", Integer.toString(VALIDITY));
+
         // sign jar
         OutputAnalyzer analyzer = jarsigner(
                 "-verbose",
-                "-keystore", NETSCAPE_KEYSTORE,
+                "-keystore", KEYSTORE,
                 "-storepass", PASSWORD,
                 "-keypass", PASSWORD,
                 "-signedjar", SIGNED_JARFILE,
@@ -82,7 +79,7 @@
         analyzer = jarsigner(
                 "-verify",
                 "-verbose",
-                "-keystore", NETSCAPE_KEYSTORE,
+                "-keystore", KEYSTORE,
                 "-storepass", PASSWORD,
                 "-keypass", PASSWORD,
                 SIGNED_JARFILE);
@@ -94,7 +91,7 @@
                 "-verify",
                 "-verbose",
                 "-strict",
-                "-keystore", NETSCAPE_KEYSTORE,
+                "-keystore", KEYSTORE,
                 "-storepass", PASSWORD,
                 "-keypass", PASSWORD,
                 SIGNED_JARFILE);
--- a/test/jdk/sun/security/tools/jarsigner/warnings/ChainNotValidatedTest.java	Fri Feb 16 12:24:38 2018 -0800
+++ b/test/jdk/sun/security/tools/jarsigner/warnings/ChainNotValidatedTest.java	Fri Feb 16 13:49:07 2018 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -21,118 +21,52 @@
  * questions.
  */
 
-import java.io.File;
 import jdk.testlibrary.OutputAnalyzer;
-import jdk.testlibrary.ProcessTools;
 import jdk.test.lib.util.JarUtils;
 
+import java.nio.file.Files;
+import java.nio.file.Paths;
+
 /**
  * @test
  * @bug 8024302 8026037
  * @summary Test for chainNotValidated warning
  * @library /lib/testlibrary /test/lib ../
  * @build jdk.test.lib.util.JarUtils
- * @run main ChainNotValidatedTest
+ * @run main ChainNotValidatedTest ca2yes
+ * @run main ChainNotValidatedTest ca2no
  */
 public class ChainNotValidatedTest extends Test {
 
-    private static final String CHAIN = "chain";
-
-    /**
-     * The test signs and verifies a jar that contains entries
-     * whose cert chain can't be correctly validated (chainNotValidated).
-     * Warning message is expected.
-     */
     public static void main(String[] args) throws Throwable {
         ChainNotValidatedTest test = new ChainNotValidatedTest();
-        test.start();
+        test.start(args[0].equals("ca2yes"));
     }
 
-    private void start() throws Throwable {
+    private void start(boolean ca2yes) throws Throwable {
         // create a jar file that contains one class file
         Utils.createFiles(FIRST_FILE);
         JarUtils.createJar(UNSIGNED_JARFILE, FIRST_FILE);
 
-        // create self-signed certificate whose BasicConstraints extension
-        // is set to false, so the certificate may not be used
-        // as a parent certificate (certpath validation should fail)
-        keytool(
-                "-genkeypair",
-                "-alias", CA_KEY_ALIAS,
-                "-keyalg", KEY_ALG,
-                "-keysize", Integer.toString(KEY_SIZE),
-                "-keystore", KEYSTORE,
-                "-storepass", PASSWORD,
-                "-keypass", PASSWORD,
-                "-dname", "CN=CA",
-                "-ext", "BasicConstraints:critical=ca:false",
-                "-validity", Integer.toString(VALIDITY)).shouldHaveExitValue(0);
-
-        // create a certificate that is signed by self-signed certificate
-        // despite of it may not be used as a parent certificate
-        // (certpath validation should fail)
-        keytool(
-                "-genkeypair",
-                "-alias", KEY_ALIAS,
-                "-keyalg", KEY_ALG,
-                "-keysize", Integer.toString(KEY_SIZE),
-                "-keystore", KEYSTORE,
-                "-storepass", PASSWORD,
-                "-keypass", PASSWORD,
-                "-dname", "CN=Test",
-                "-ext", "BasicConstraints:critical=ca:false",
-                "-validity", Integer.toString(VALIDITY)).shouldHaveExitValue(0);
-
-        keytool(
-                "-certreq",
-                "-alias", KEY_ALIAS,
-                "-keystore", KEYSTORE,
-                "-storepass", PASSWORD,
-                "-keypass", PASSWORD,
-                "-file", CERT_REQUEST_FILENAME).shouldHaveExitValue(0);
+        // We have 2 @run. Need cleanup.
+        Files.deleteIfExists(Paths.get(KEYSTORE));
 
-        keytool(
-                "-gencert",
-                "-alias", CA_KEY_ALIAS,
-                "-keystore", KEYSTORE,
-                "-storepass", PASSWORD,
-                "-keypass", PASSWORD,
-                "-infile", CERT_REQUEST_FILENAME,
-                "-validity", Integer.toString(VALIDITY),
-                "-outfile", CERT_FILENAME).shouldHaveExitValue(0);
-
-        keytool(
-                "-importcert",
-                "-alias", KEY_ALIAS,
-                "-keystore", KEYSTORE,
-                "-storepass", PASSWORD,
-                "-keypass", PASSWORD,
-                "-file", CERT_FILENAME).shouldHaveExitValue(0);
+        // Root CA is not checked at all. If the intermediate CA has
+        // BasicConstraints extension set to true, it will be valid.
+        // Otherwise, chain validation will fail.
+        createAlias(CA_KEY_ALIAS);
+        createAlias(CA2_KEY_ALIAS);
+        issueCert(CA2_KEY_ALIAS,
+                "-ext",
+                "bc=ca:" + ca2yes);
 
-        ProcessBuilder pb = new ProcessBuilder(KEYTOOL,
-                "-export",
-                "-rfc",
-                "-alias", KEY_ALIAS,
-                "-keystore", KEYSTORE,
-                "-storepass", PASSWORD,
-                "-keypass", PASSWORD);
-        pb.redirectOutput(ProcessBuilder.Redirect.appendTo(new File(CHAIN)));
-        ProcessTools.executeCommand(pb).shouldHaveExitValue(0);
+        createAlias(KEY_ALIAS);
+        issueCert(KEY_ALIAS, "-alias", CA2_KEY_ALIAS);
 
-        pb = new ProcessBuilder(KEYTOOL,
-                "-export",
-                "-rfc",
-                "-alias", CA_KEY_ALIAS,
-                "-keystore", KEYSTORE,
-                "-storepass", PASSWORD,
-                "-keypass", PASSWORD);
-        pb.redirectOutput(ProcessBuilder.Redirect.appendTo(new File(CHAIN)));
-        ProcessTools.executeCommand(pb).shouldHaveExitValue(0);
-
-        // remove CA certificate
+        // remove CA2 certificate so it's not trusted
         keytool(
                 "-delete",
-                "-alias", CA_KEY_ALIAS,
+                "-alias", CA2_KEY_ALIAS,
                 "-keystore", KEYSTORE,
                 "-storepass", PASSWORD,
                 "-keypass", PASSWORD).shouldHaveExitValue(0);
@@ -142,12 +76,15 @@
                 "-keystore", KEYSTORE,
                 "-storepass", PASSWORD,
                 "-keypass", PASSWORD,
-                "-certchain", CHAIN,
                 "-signedjar", SIGNED_JARFILE,
                 UNSIGNED_JARFILE,
                 KEY_ALIAS);
 
-        checkSigning(analyzer, CHAIN_NOT_VALIDATED_SIGNING_WARNING);
+        if (ca2yes) {
+            checkSigning(analyzer, "!" + CHAIN_NOT_VALIDATED_SIGNING_WARNING);
+        } else {
+            checkSigning(analyzer, CHAIN_NOT_VALIDATED_SIGNING_WARNING);
+        }
 
         // verify signed jar
         analyzer = jarsigner(
@@ -156,10 +93,13 @@
                 "-keystore", KEYSTORE,
                 "-storepass", PASSWORD,
                 "-keypass", PASSWORD,
-                "-certchain", CHAIN,
                 SIGNED_JARFILE);
 
-        checkVerifying(analyzer, 0, CHAIN_NOT_VALIDATED_VERIFYING_WARNING);
+        if (ca2yes) {
+            checkVerifying(analyzer, 0, "!" + CHAIN_NOT_VALIDATED_VERIFYING_WARNING);
+        } else {
+            checkVerifying(analyzer, 0, CHAIN_NOT_VALIDATED_VERIFYING_WARNING);
+        }
 
         // verify signed jar in strict mode
         analyzer = jarsigner(
@@ -169,11 +109,15 @@
                 "-keystore", KEYSTORE,
                 "-storepass", PASSWORD,
                 "-keypass", PASSWORD,
-                "-certchain", CHAIN,
                 SIGNED_JARFILE);
 
-        checkVerifying(analyzer, CHAIN_NOT_VALIDATED_EXIT_CODE,
-                CHAIN_NOT_VALIDATED_VERIFYING_WARNING);
+        if (ca2yes) {
+            checkVerifying(analyzer, 0,
+                    "!" + CHAIN_NOT_VALIDATED_VERIFYING_WARNING);
+        } else {
+            checkVerifying(analyzer, CHAIN_NOT_VALIDATED_EXIT_CODE,
+                    CHAIN_NOT_VALIDATED_VERIFYING_WARNING);
+        }
 
         System.out.println("Test passed");
     }
--- a/test/jdk/sun/security/tools/jarsigner/warnings/HasExpiredCertTest.java	Fri Feb 16 12:24:38 2018 -0800
+++ b/test/jdk/sun/security/tools/jarsigner/warnings/HasExpiredCertTest.java	Fri Feb 16 13:49:07 2018 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -52,18 +52,13 @@
         JarUtils.createJar(UNSIGNED_JARFILE, FIRST_FILE);
 
         // create key pair for jar signing
-        keytool(
-                "-genkey",
-                "-alias", KEY_ALIAS,
-                "-keyalg", KEY_ALG,
-                "-keysize", Integer.toString(KEY_SIZE),
-                "-keystore", KEYSTORE,
-                "-storepass", PASSWORD,
-                "-keypass", PASSWORD,
-                "-dname", "CN=Test",
+        createAlias(CA_KEY_ALIAS);
+        createAlias(KEY_ALIAS);
+
+        issueCert(
+                KEY_ALIAS,
                 "-startdate", "-" + SHORT_VALIDITY * 2 + "d",
-                "-validity", Integer.toString(SHORT_VALIDITY))
-                .shouldHaveExitValue(0);
+                "-validity", Integer.toString(SHORT_VALIDITY));
 
         // sign jar
         OutputAnalyzer analyzer = jarsigner(
--- a/test/jdk/sun/security/tools/jarsigner/warnings/HasExpiringCertTest.java	Fri Feb 16 12:24:38 2018 -0800
+++ b/test/jdk/sun/security/tools/jarsigner/warnings/HasExpiringCertTest.java	Fri Feb 16 13:49:07 2018 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -52,17 +52,12 @@
         JarUtils.createJar(UNSIGNED_JARFILE, FIRST_FILE);
 
         // create key pair for jar signing
-        keytool(
-                "-genkey",
-                "-alias", KEY_ALIAS,
-                "-keyalg", KEY_ALG,
-                "-keysize", Integer.toString(KEY_SIZE),
-                "-keystore", KEYSTORE,
-                "-storepass", PASSWORD,
-                "-keypass", PASSWORD,
-                "-dname", "CN=Test",
-                "-validity", Integer.toString(SHORT_VALIDITY))
-                .shouldHaveExitValue(0);
+        createAlias(CA_KEY_ALIAS);
+        createAlias(KEY_ALIAS);
+
+        issueCert(
+                KEY_ALIAS,
+                "-validity", Integer.toString(SHORT_VALIDITY));
 
         // sign jar
         OutputAnalyzer analyzer = jarsigner(
--- a/test/jdk/sun/security/tools/jarsigner/warnings/HasUnsignedEntryTest.java	Fri Feb 16 12:24:38 2018 -0800
+++ b/test/jdk/sun/security/tools/jarsigner/warnings/HasUnsignedEntryTest.java	Fri Feb 16 13:49:07 2018 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -51,16 +51,11 @@
         JarUtils.createJar(UNSIGNED_JARFILE, FIRST_FILE);
 
         // create key pair for signing
-        keytool(
-                "-genkey",
-                "-alias", KEY_ALIAS,
-                "-keyalg", KEY_ALG,
-                "-keysize", Integer.toString(KEY_SIZE),
-                "-keystore", KEYSTORE,
-                "-storepass", PASSWORD,
-                "-keypass", PASSWORD,
-                "-dname", "CN=Test",
-                "-validity", Integer.toString(VALIDITY)).shouldHaveExitValue(0);
+        createAlias(CA_KEY_ALIAS);
+        createAlias(KEY_ALIAS);
+        issueCert(
+                KEY_ALIAS,
+                "-validity", Integer.toString(VALIDITY));
 
         // sign jar
         OutputAnalyzer analyzer = jarsigner(
--- a/test/jdk/sun/security/tools/jarsigner/warnings/MultipleWarningsTest.java	Fri Feb 16 12:24:38 2018 -0800
+++ b/test/jdk/sun/security/tools/jarsigner/warnings/MultipleWarningsTest.java	Fri Feb 16 13:49:07 2018 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -54,35 +54,25 @@
         // create a jar file that contains one class file
         JarUtils.createJar(UNSIGNED_JARFILE, FIRST_FILE);
 
+        createAlias(CA_KEY_ALIAS);
+
         // create first expired certificate
         // whose ExtendedKeyUsage extension does not allow code signing
-        keytool(
-                "-genkey",
-                "-alias", FIRST_KEY_ALIAS,
-                "-keyalg", KEY_ALG,
-                "-keysize", Integer.toString(KEY_SIZE),
-                "-keystore", KEYSTORE,
-                "-storepass", PASSWORD,
-                "-keypass", PASSWORD,
-                "-dname", "CN=First",
+        createAlias(FIRST_KEY_ALIAS);
+        issueCert(
+                FIRST_KEY_ALIAS,
                 "-ext", "ExtendedkeyUsage=serverAuth",
                 "-startdate", "-" + VALIDITY * 2 + "d",
-                "-validity", Integer.toString(VALIDITY)).shouldHaveExitValue(0);
+                "-validity", Integer.toString(VALIDITY));
 
         // create second expired certificate
         // whose KeyUsage extension does not allow code signing
-        keytool(
-                "-genkey",
-                "-alias", SECOND_KEY_ALIAS,
-                "-keyalg", KEY_ALG,
-                "-keysize", Integer.toString(KEY_SIZE),
-                "-keystore", KEYSTORE,
-                "-storepass", PASSWORD,
-                "-keypass", PASSWORD,
-                "-dname", "CN=Second",
+        createAlias(SECOND_KEY_ALIAS);
+        issueCert(
+                SECOND_KEY_ALIAS,
                 "-ext", "ExtendedkeyUsage=serverAuth",
                 "-startdate", "-" + VALIDITY * 2 + "d",
-                "-validity", Integer.toString(VALIDITY)).shouldHaveExitValue(0);
+                "-validity", Integer.toString(VALIDITY));
 
         // sign jar with first key
         OutputAnalyzer analyzer = jarsigner(
--- a/test/jdk/sun/security/tools/jarsigner/warnings/NoTimestampTest.java	Fri Feb 16 12:24:38 2018 -0800
+++ b/test/jdk/sun/security/tools/jarsigner/warnings/NoTimestampTest.java	Fri Feb 16 13:49:07 2018 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -57,15 +57,9 @@
                 * 24 * 60 * 60 * 1000L);
 
         // create key pair
-        keytool(
-                "-genkey",
-                "-alias", KEY_ALIAS,
-                "-keyalg", KEY_ALG,
-                "-keysize", Integer.toString(KEY_SIZE),
-                "-keystore", KEYSTORE,
-                "-storepass", PASSWORD,
-                "-keypass", PASSWORD,
-                "-dname", "CN=Test",
+        createAlias(CA_KEY_ALIAS);
+        createAlias(KEY_ALIAS);
+        issueCert(KEY_ALIAS,
                 "-validity", Integer.toString(VALIDITY));
 
         // sign jar file
--- a/test/jdk/sun/security/tools/jarsigner/warnings/NotSignedByAliasTest.java	Fri Feb 16 12:24:38 2018 -0800
+++ b/test/jdk/sun/security/tools/jarsigner/warnings/NotSignedByAliasTest.java	Fri Feb 16 13:49:07 2018 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -49,29 +49,19 @@
         Utils.createFiles(FIRST_FILE);
         JarUtils.createJar(UNSIGNED_JARFILE, FIRST_FILE);
 
-        // create first key pair for signing
-        keytool(
-                "-genkey",
-                "-alias", FIRST_KEY_ALIAS,
-                "-keyalg", KEY_ALG,
-                "-keysize", Integer.toString(KEY_SIZE),
-                "-keystore", KEYSTORE,
-                "-storepass", PASSWORD,
-                "-keypass", PASSWORD,
-                "-dname", "CN=First",
-                "-validity", Integer.toString(VALIDITY)).shouldHaveExitValue(0);
+        createAlias(CA_KEY_ALIAS);
 
         // create first key pair for signing
-        keytool(
-                "-genkey",
-                "-alias", SECOND_KEY_ALIAS,
-                "-keyalg", KEY_ALG,
-                "-keysize", Integer.toString(KEY_SIZE),
-                "-keystore", KEYSTORE,
-                "-storepass", PASSWORD,
-                "-keypass", PASSWORD,
-                "-dname", "CN=Second",
-                "-validity", Integer.toString(VALIDITY)).shouldHaveExitValue(0);
+        createAlias(FIRST_KEY_ALIAS);
+        issueCert(
+                FIRST_KEY_ALIAS,
+                "-validity", Integer.toString(VALIDITY));
+
+        // create first key pair for signing
+        createAlias(SECOND_KEY_ALIAS);
+        issueCert(
+                SECOND_KEY_ALIAS,
+                "-validity", Integer.toString(VALIDITY));
 
         // sign jar with first key
         OutputAnalyzer analyzer = jarsigner(
--- a/test/jdk/sun/security/tools/jarsigner/warnings/NotYetValidCertTest.java	Fri Feb 16 12:24:38 2018 -0800
+++ b/test/jdk/sun/security/tools/jarsigner/warnings/NotYetValidCertTest.java	Fri Feb 16 13:49:07 2018 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -50,15 +50,11 @@
         JarUtils.createJar(UNSIGNED_JARFILE, FIRST_FILE);
 
         // create certificate that will be valid only tomorrow
-        keytool(
-                "-genkey",
-                "-alias", KEY_ALIAS,
-                "-keyalg", KEY_ALG,
-                "-keysize", Integer.toString(KEY_SIZE),
-                "-keystore", KEYSTORE,
-                "-storepass", PASSWORD,
-                "-keypass", PASSWORD,
-                "-dname", "CN=Test",
+        createAlias(CA_KEY_ALIAS);
+        createAlias(KEY_ALIAS);
+
+        issueCert(
+                KEY_ALIAS,
                 "-startdate", "+1d",
                 "-validity", Integer.toString(VALIDITY));
 
--- a/test/jdk/sun/security/tools/jarsigner/warnings/Test.java	Fri Feb 16 12:24:38 2018 -0800
+++ b/test/jdk/sun/security/tools/jarsigner/warnings/Test.java	Fri Feb 16 13:49:07 2018 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2013, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -45,7 +45,6 @@
     static final String FIRST_FILE = "first.txt";
     static final String SECOND_FILE = "second.txt";
     static final String PASSWORD = "password";
-    static final String BOTH_KEYS_KEYSTORE = "both_keys.jks";
     static final String FIRST_KEY_KEYSTORE = "first_key.jks";
     static final String KEYSTORE = "keystore.jks";
     static final String FIRST_KEY_ALIAS = "first";
@@ -55,11 +54,13 @@
     static final String CERT_REQUEST_FILENAME = "test.req";
     static final String CERT_FILENAME = "test.crt";
     static final String CA_KEY_ALIAS = "ca";
+    static final String CA2_KEY_ALIAS = "ca2";
     static final int KEY_SIZE = 2048;
     static final int TIMEOUT = 6 * 60 * 1000;   // in millis
     static final int VALIDITY = 365;
 
     static final String WARNING = "Warning:";
+    static final String WARNING_OR_ERROR = "(Warning|Error):";
 
     static final String CHAIN_NOT_VALIDATED_VERIFYING_WARNING
             = "This jar contains entries "
@@ -154,14 +155,72 @@
     static final int ALIAS_NOT_IN_STORE_EXIT_CODE = 32;
     static final int NOT_SIGNED_BY_ALIAS_EXIT_CODE = 32;
 
+    protected void createAlias(String alias, String ... options)
+            throws Throwable {
+        List<String> cmd = new ArrayList<>();
+        cmd.addAll(List.of(
+                "-genkeypair",
+                "-alias", alias,
+                "-keyalg", KEY_ALG,
+                "-keysize", Integer.toString(KEY_SIZE),
+                "-keystore", KEYSTORE,
+                "-storepass", PASSWORD,
+                "-keypass", PASSWORD,
+                "-dname", "CN=" + alias));
+        cmd.addAll(Arrays.asList(options));
+
+        keytool(cmd.toArray(new String[cmd.size()]))
+                .shouldHaveExitValue(0);
+    }
+
+    protected void issueCert(String alias, String ... options)
+            throws Throwable {
+        keytool("-certreq",
+                "-alias", alias,
+                "-keystore", KEYSTORE,
+                "-storepass", PASSWORD,
+                "-keypass", PASSWORD,
+                "-file", alias + ".req")
+                    .shouldHaveExitValue(0);
+
+        List<String> cmd = new ArrayList<>();
+        cmd.addAll(List.of(
+                "-gencert",
+                "-alias", CA_KEY_ALIAS,
+                "-infile", alias + ".req",
+                "-outfile", alias + ".cert",
+                "-keystore", KEYSTORE,
+                "-storepass", PASSWORD,
+                "-keypass", PASSWORD,
+                "-file", alias + ".req"));
+        cmd.addAll(Arrays.asList(options));
+
+        keytool(cmd.toArray(new String[cmd.size()]))
+                .shouldHaveExitValue(0);
+
+        keytool("-importcert",
+                "-alias", alias,
+                "-keystore", KEYSTORE,
+                "-storepass", PASSWORD,
+                "-keypass", PASSWORD,
+                "-file", alias + ".cert")
+                    .shouldHaveExitValue(0);
+    }
+
     protected void checkVerifying(OutputAnalyzer analyzer, int expectedExitCode,
             String... warnings) {
         analyzer.shouldHaveExitValue(expectedExitCode);
+        int count = 0;
         for (String warning : warnings) {
-            analyzer.shouldContain(warning);
+            if (warning.startsWith("!")) {
+                analyzer.shouldNotContain(warning.substring(1));
+            } else {
+                count++;
+                analyzer.shouldContain(warning);
+            }
         }
-        if (warnings.length > 0) {
-            analyzer.shouldContain(WARNING);
+        if (count > 0) {
+            analyzer.shouldMatch(WARNING_OR_ERROR);
         }
         if (expectedExitCode == 0) {
             analyzer.shouldContain(JAR_VERIFIED);
@@ -172,11 +231,17 @@
 
     protected void checkSigning(OutputAnalyzer analyzer, String... warnings) {
         analyzer.shouldHaveExitValue(0);
+        int count = 0;
         for (String warning : warnings) {
-            analyzer.shouldContain(warning);
+            if (warning.startsWith("!")) {
+                analyzer.shouldNotContain(warning.substring(1));
+            } else {
+                count++;
+                analyzer.shouldContain(warning);
+            }
         }
-        if (warnings.length > 0) {
-            analyzer.shouldContain(WARNING);
+        if (count > 0) {
+            analyzer.shouldMatch(WARNING_OR_ERROR);
         }
         analyzer.shouldContain(JAR_SIGNED);
     }
--- a/test/jdk/sun/security/tools/jarsigner/warnings/bad_netscape_cert_type.jks.base64	Fri Feb 16 12:24:38 2018 -0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,26 +0,0 @@
-/u3+7QAAAAIAAAABAAAAAQAFYWxpYXMAAAFBpkwW0gAAAr0wggK5MA4GCisGAQQB
-KgIRAQEFAASCAqWkGJ3PPjYmWNKrV23Y1u413RMAkrRZ+1OLWYRcQt4jtxtIyEH5
-Ho5b9dy9XN9FBKlTOD4c2Pc1T43BLKXeuLu3uLLeIxgXFt0z9CLyGwdYZZ751kXr
-DQ99qY6aNQUO6SeE4Wdty0KPAqid6ZJ8bF7T6wsTZSvNhaBRzyFydEfG7bbUYjOl
-mWC44nlsu6VEU3o9RQpcm1gIMwradOaIVT/HoB2bKmAv8gHqI6kreiEZwTdZkSAI
-IRi2vt1RPllXt5hgjDxUfZe8XOYYweR4Vt2/jVuKLJ80DNTu/9SeUD88zQAz53k4
-r3nRhv6TRcPm6tV/Fh92XLHiskL+TAzTfm+bUAudPCCVxN+yRtxvAgA+UhdV/SuM
-Zn5F6nrmP+YJG1hmprgCJIJJaCEXa9RXYC+vIVpO0WVNRuGlGm+/1afnOuQC8Wss
-ShXwjkaqTwAhqBFq7eYmmP8BK3gflYrt2zDLXvhl4ndVvMhMthFJ3ZvLh2LWpqLI
-/n8EMCf8US3lIEFk9DTHBZjffiHkqK2e7+FXEpG3xrgE6ZYLMdbd5Pb3YjZfhQx+
-ZTtiEFzYSaEGhacek/m7dRq1qmwgFsytng2OdWZe2ln8LJY0odr1dGUfJHfgafvi
-tlfbkg/rgjONtwliChDggbkUwnerrj/D/zrdEufUvfyltSshhHXRNDD3fH6spmEk
-hHKgxEc4yvxqJxzdMGtuib355aSfNegyl+GsnsKzXQCVEK2h3BLTQObzaD+8NZ12
-LQHvbrCiaS34vxJ3rEC+a+SW7itZp0aCdXMWdMJNkRKqyLBD3vG3zN05sN3XrhEM
-8BRT020TWY00tbVFbbBFheYLQRgTjrQtr0Yt6UHWBZc4N20crDLcSH5gqcCOVpla
-1Y2uqFEn8yqrGRwn/kgfNgAAAAEABVguNTA5AAABtTCCAbEwggEaoAMCAQICCQDH
-cEuVvzCuqzANBgkqhkiG9w0BAQUFADAPMQ0wCwYDVQQDDARUZXN0MB4XDTEzMTAx
-MTA2NTUwNloXDTIzMTAwOTA2NTUwNlowDzENMAsGA1UEAwwEVGVzdDCBnzANBgkq
-hkiG9w0BAQEFAAOBjQAwgYkCgYEA8hOfp2Dcnvt//ZZQAja9TRiwKqXVS+TiYE3S
-gngCBjIi+YYdo0DsUeO5MBfE6uvCWOr5lwAR/u1iaJOhIoGJDiGoPasZlt+yIgtR
-LzA7j2q+1q6kcwiVxfikI3aUgHV/QsybTriT4Bf7TQNKtJG23MQa4sD7+PjtCWD7
-p3cHTfkCAwEAAaMVMBMwEQYJYIZIAYb4QgEBBAQDAgeAMA0GCSqGSIb3DQEBBQUA
-A4GBAKoDlTJ8wLRA7G8XdGm4gv733n1cSQzlkcsjfOO6/mA5Jvu8tyFNq9HTf9AT
-VXbrbGcUYJjhzSSY3w5apXK1kXyqTB1LUNEJ45WnmciqSSecVTpJz9TuegyoX0Zf
-HScSgqfDmjqoiiFiNCgn3ZEJ85ykGvoFYGH+php+BVi3S0bj5E/jRpyV3vNnii/S
-wJDSAXF6bYU=
--- a/test/jdk/sun/security/tools/jarsigner/warnings/bad_netscape_cert_type.sh	Fri Feb 16 12:24:38 2018 -0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,48 +0,0 @@
-#
-# Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
-# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
-#
-# This code is free software; you can redistribute it and/or modify it
-# under the terms of the GNU General Public License version 2 only, as
-# published by the Free Software Foundation.
-#
-# This code is distributed in the hope that it will be useful, but WITHOUT
-# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
-# FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
-# version 2 for more details (a copy is included in the LICENSE file that
-# accompanied this code).
-#
-# You should have received a copy of the GNU General Public License version
-# 2 along with this work; if not, write to the Free Software Foundation,
-# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
-#
-# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
-# or visit www.oracle.com if you need additional information or have any
-# questions.
-#
-
-#!/bin/sh
-
-# This script creates JKS keystore with a certificate
-# that contains Netscape Certificate Type extension
-# that does not allow code signing
-# The keystore is used by BadNetscapeCertTypeTest.java test
-
-rm -rf keystore.jks
-echo "nsCertType = client" > ext.cfg
-
-openssl req -new -out cert.req -keyout key.pem -days 3650 \
-    -passin pass:password -passout pass:password -subj "/CN=Test"
-openssl x509 -in cert.req -out cert.pem -req -signkey key.pem -days 3650 \
-    -passin pass:password -extfile ext.cfg
-openssl pkcs12 -export -in cert.pem -inkey key.pem -out keystore.p12 \
-    -passin pass:password -passout pass:password -name alias
-
-${JAVA_HOME}/bin/keytool -importkeystore \
-    -srckeystore keystore.p12 -srcstoretype pkcs12 \
-    -srcstorepass password -alias alias \
-    -destkeystore bad_netscape_cert_type.jks -deststoretype jks \
-    -deststorepass password -destalias alias \
-
-openssl base64 < bad_netscape_cert_type.jks > bad_netscape_cert_type.jks.base64
-rm -rf cert.req key.pem cert.pem keystore.p12 ext.cfg bad_netscape_cert_type.jks
--- a/test/jtreg-ext/requires/VMProps.java	Fri Feb 16 12:24:38 2018 -0800
+++ b/test/jtreg-ext/requires/VMProps.java	Fri Feb 16 13:49:07 2018 -0800
@@ -352,9 +352,11 @@
      * @return true if docker is supported in a given environment
      */
     protected String dockerSupport() {
-        // currently docker testing is only supported for Linux-x64
-        if (! ( Platform.isLinux() && Platform.isX64() ) )
+        // currently docker testing is only supported for Linux-x64 and Linux-ppc64le
+        String arch = System.getProperty("os.arch");
+        if (! (Platform.isLinux() && (Platform.isX64() || arch.equals("ppc64le")))) {
             return "false";
+        }
 
         boolean isSupported;
         try {
--- a/test/lib/jdk/test/lib/containers/docker/DockerTestUtils.java	Fri Feb 16 12:24:38 2018 -0800
+++ b/test/lib/jdk/test/lib/containers/docker/DockerTestUtils.java	Fri Feb 16 13:49:07 2018 -0800
@@ -34,6 +34,7 @@
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.List;
+import jdk.test.lib.Platform;
 import jdk.test.lib.Utils;
 import jdk.test.lib.process.OutputAnalyzer;
 import jdk.test.lib.process.ProcessTools;
@@ -109,7 +110,9 @@
      * The jdk will be placed under the "/jdk/" folder inside the docker file system.
      *
      * @param imageName     name of the image to be created, including version tag
-     * @param dockerfile    name of the dockerfile residing in the test source
+     * @param dockerfile    name of the dockerfile residing in the test source;
+     *                      we check for a platform specific dockerfile as well
+     *                      and use this one in case it exists
      * @param buildDirName  name of the docker build/staging directory, which will
      *                      be created in the jtreg's scratch folder
      * @throws Exception
@@ -122,6 +125,11 @@
         if (Files.exists(buildDir)) {
             throw new RuntimeException("The docker build directory already exists: " + buildDir);
         }
+        // check for the existance of a platform specific docker file as well
+        String platformSpecificDockerfile = dockerfile + "-" + Platform.getOsArch();
+        if (Files.exists(Paths.get(Utils.TEST_SRC, platformSpecificDockerfile))) {
+          dockerfile = platformSpecificDockerfile;
+        }
 
         Path jdkSrcDir = Paths.get(Utils.TEST_JDK);
         Path jdkDstDir = buildDir.resolve("jdk");