changeset 50549:a2a0c61f8b09

Merge
author prr
date Fri, 04 May 2018 08:50:01 -0700
parents 37aa8b00c604 29b840b16a96
children 09cbe16c0662
files make/Images.gmk src/hotspot/share/services/metaspaceDCmd.cpp test/jdk/ProblemList.txt
diffstat 848 files changed, 47153 insertions(+), 3313 deletions(-) [+]
line wrap: on
line diff
--- a/.hgtags	Wed May 02 22:11:35 2018 -0700
+++ b/.hgtags	Fri May 04 08:50:01 2018 -0700
@@ -483,3 +483,4 @@
 6fa770f9f8ab296e1ce255ec17ccf6d4e1051886 jdk-10+46
 69d7398038c54774d9395b6810e0cca335edc02c jdk-11+10
 e1e60f75cd39312a7f59d2a4f91d624e5aecc95e jdk-11+11
+3ab6ba9f94a9045a526d645af26c933235371d6f jdk-11+12
--- a/make/Bundles.gmk	Wed May 02 22:11:35 2018 -0700
+++ b/make/Bundles.gmk	Fri May 04 08:50:01 2018 -0700
@@ -156,9 +156,6 @@
   JRE_IMAGE_HOMEDIR := $(JRE_IMAGE_DIR)
   JDK_BUNDLE_SUBDIR := jdk-$(VERSION_NUMBER)
   JRE_BUNDLE_SUBDIR := jre-$(VERSION_NUMBER)
-  JRE_COMPACT1_BUNDLE_SUBDIR := jre-$(VERSION_NUMBER)-compact1
-  JRE_COMPACT2_BUNDLE_SUBDIR := jre-$(VERSION_NUMBER)-compact2
-  JRE_COMPACT3_BUNDLE_SUBDIR := jre-$(VERSION_NUMBER)-compact3
   ifneq ($(DEBUG_LEVEL), release)
     JDK_BUNDLE_SUBDIR := $(JDK_BUNDLE_SUBDIR)/$(DEBUG_LEVEL)
     JRE_BUNDLE_SUBDIR := $(JRE_BUNDLE_SUBDIR)/$(DEBUG_LEVEL)
@@ -281,35 +278,6 @@
 
 ################################################################################
 
-ifneq ($(filter profiles-bundles, $(MAKECMDGOALS)), )
-  ifeq ($(OPENJDK_TARGET_OS), macosx)
-    $(error Creating compact profiles bundles on macosx is unsupported)
-  endif
-
-  define GenerateCompactProfilesBundles
-    ALL_JRE_COMPACT$1_FILES := $$(call CacheFind, $$(JRE_COMPACT$1_IMAGE_DIR))
-
-    JRE_COMPACT$1_BUNDLE_FILES := $$(filter-out \
-        $$(SYMBOLS_EXCLUDE_PATTERN), \
-        $$(ALL_JRE_COMPACT$1_FILES))
-
-    $$(eval $$(call SetupBundleFile, BUILD_JRE_COMPACT$1_BUNDLE, \
-        BUNDLE_NAME := $$(JRE_COMPACT$1_BUNDLE_NAME), \
-        FILES := $$(JRE_COMPACT$1_BUNDLE_FILES), \
-        BASE_DIRS := $$(JRE_COMPACT$1_IMAGE_DIR), \
-        SUBDIR := $$(JRE_COMPACT$1_BUNDLE_SUBDIR), \
-    ))
-
-    PROFILES_TARGETS += $$(BUILD_JRE_COMPACT$1_BUNDLE)
-  endef
-
-  $(eval $(call GenerateCompactProfilesBundles,1))
-  $(eval $(call GenerateCompactProfilesBundles,2))
-  $(eval $(call GenerateCompactProfilesBundles,3))
-endif
-
-################################################################################
-
 ifneq ($(filter test-bundles, $(MAKECMDGOALS)), )
   TEST_BUNDLE_FILES := $(call CacheFind, $(TEST_IMAGE_DIR))
 
@@ -345,8 +313,7 @@
 ################################################################################
 
 product-bundles: $(PRODUCT_TARGETS)
-profiles-bundles: $(PROFILES_TARGETS)
 test-bundles: $(TEST_TARGETS)
 docs-bundles: $(DOCS_TARGETS)
 
-.PHONY: all default product-bundles profiles-bundles test-bundles docs-bundles
+.PHONY: all default product-bundles test-bundles docs-bundles
--- a/make/Help.gmk	Wed May 02 22:11:35 2018 -0700
+++ b/make/Help.gmk	Fri May 04 08:50:01 2018 -0700
@@ -43,7 +43,7 @@
 	$(info $(_) make images            # Create complete jdk and jre images)
 	$(info $(_)                        # (alias for product-images))
 	$(info $(_) make <name>-image      # Build just the image for any of: )
-	$(info $(_)                        # jdk, jre, test, docs, symbols, profiles)
+	$(info $(_)                        # jdk, jre, test, docs, symbols)
 	$(info $(_) make <phase>           # Build the specified phase and everything it depends on)
 	$(info $(_)                        # (gensrc, java, copy, libs, launchers, gendata, rmic))
 	$(info $(_) make *-only            # Applies to most targets and disables building the)
@@ -51,7 +51,6 @@
 	$(info $(_)                        # result in incorrect build results!)
 	$(info $(_) make docs              # Create all docs)
 	$(info $(_) make docs-jdk-api      # Create just JDK javadocs)
-	$(info $(_) make profiles          # Create complete jre compact profile images)
 	$(info $(_) make bootcycle-images  # Build images twice, second time with newly built JDK)
 	$(info $(_) make install           # Install the generated images locally)
 	$(info $(_) make reconfigure       # Rerun configure with the same arguments as last time)
--- a/make/Images.gmk	Wed May 02 22:11:35 2018 -0700
+++ b/make/Images.gmk	Fri May 04 08:50:01 2018 -0700
@@ -47,50 +47,8 @@
     $(PLATFORM_MODULES) $(JRE_TOOL_MODULES))
 JDK_MODULES += $(ALL_MODULES)
 
-# Modules list for compact builds
-JRE_COMPACT1_MODULES := \
-    java.logging \
-    java.scripting \
-    jdk.localedata \
-    jdk.crypto.cryptoki \
-    jdk.crypto.ec \
-    jdk.unsupported \
-    #
-
-JRE_COMPACT2_MODULES := \
-    $(JRE_COMPACT1_MODULES) \
-    java.rmi \
-    java.sql \
-    java.xml \
-    jdk.xml.dom \
-    jdk.httpserver \
-    #
-
-JRE_COMPACT3_MODULES := \
-    $(JRE_COMPACT2_MODULES) \
-    java.smartcardio \
-    java.compiler \
-    java.instrument \
-    java.management \
-    java.management.rmi \
-    java.naming \
-    java.prefs \
-    java.security.jgss \
-    java.security.sasl \
-    java.sql.rowset \
-    java.xml.crypto \
-    jdk.management \
-    jdk.naming.dns \
-    jdk.naming.rmi \
-    jdk.sctp \
-    jdk.security.auth \
-    #
-
 JRE_MODULES_LIST := $(call CommaList, $(JRE_MODULES))
 JDK_MODULES_LIST := $(call CommaList, $(JDK_MODULES))
-JRE_COMPACT1_MODULES_LIST := $(call CommaList, $(JRE_COMPACT1_MODULES))
-JRE_COMPACT2_MODULES_LIST := $(call CommaList, $(JRE_COMPACT2_MODULES))
-JRE_COMPACT3_MODULES_LIST := $(call CommaList, $(JRE_COMPACT3_MODULES))
 
 ################################################################################
 
@@ -152,45 +110,8 @@
 	)
 	$(TOUCH) $@
 
-
-$(JRE_COMPACT1_IMAGE_DIR)/$(JIMAGE_TARGET_FILE): $(JMODS) \
-    $(call DependOnVariable, JRE_COMPACT1_MODULES_LIST) $(BASE_RELEASE_FILE)
-	$(ECHO) Creating jre compact1 jimage
-	$(RM) -r $(JRE_COMPACT1_IMAGE_DIR)
-	$(call ExecuteWithLog, $(SUPPORT_OUTPUTDIR)/images/jre_compact1, \
-	    $(JLINK_TOOL) --add-modules $(JRE_COMPACT1_MODULES_LIST) \
-	        $(JLINK_JRE_EXTRA_OPTS) \
-	        --output $(JRE_COMPACT1_IMAGE_DIR) \
-	)
-	$(TOUCH) $@
-
-$(JRE_COMPACT2_IMAGE_DIR)/$(JIMAGE_TARGET_FILE): $(JMODS) \
-    $(call DependOnVariable, JRE_COMPACT2_MODULES_LIST) $(BASE_RELEASE_FILE)
-	$(ECHO) Creating jre compact2 jimage
-	$(RM) -r $(JRE_COMPACT2_IMAGE_DIR)
-	$(call ExecuteWithLog, $(SUPPORT_OUTPUTDIR)/images/jre_compact2, \
-	    $(JLINK_TOOL) --add-modules $(JRE_COMPACT2_MODULES_LIST) \
-	        $(JLINK_JRE_EXTRA_OPTS) \
-	        --output $(JRE_COMPACT2_IMAGE_DIR) \
-	)
-	$(TOUCH) $@
-
-$(JRE_COMPACT3_IMAGE_DIR)/$(JIMAGE_TARGET_FILE): $(JMODS) \
-    $(call DependOnVariable, JRE_COMPACT3_MODULES_LIST) $(BASE_RELEASE_FILE)
-	$(ECHO) Creating jre compact3 jimage
-	$(RM) -r $(JRE_COMPACT3_IMAGE_DIR)
-	$(call ExecuteWithLog, $(SUPPORT_OUTPUTDIR)/images/jre_compact3, \
-	    $(JLINK_TOOL) --add-modules $(JRE_COMPACT3_MODULES_LIST) \
-	        $(JLINK_JRE_EXTRA_OPTS) \
-	        --output $(JRE_COMPACT3_IMAGE_DIR) \
-	)
-	$(TOUCH) $@
-
 TOOL_JRE_TARGETS := $(JRE_IMAGE_DIR)/$(JIMAGE_TARGET_FILE)
 TOOL_JDK_TARGETS := $(JDK_IMAGE_DIR)/$(JIMAGE_TARGET_FILE)
-TOOL_JRE_COMPACT1_TARGETS := $(JRE_COMPACT1_IMAGE_DIR)/$(JIMAGE_TARGET_FILE)
-TOOL_JRE_COMPACT2_TARGETS := $(JRE_COMPACT2_IMAGE_DIR)/$(JIMAGE_TARGET_FILE)
-TOOL_JRE_COMPACT3_TARGETS := $(JRE_COMPACT3_IMAGE_DIR)/$(JIMAGE_TARGET_FILE)
 
 ################################################################################
 # /man dir
@@ -441,15 +362,4 @@
 
 all: jdk jre symbols
 
-$(JRE_COMPACT1_TARGETS): $(TOOL_JRE_COMPACT1_TARGETS)
-$(JRE_COMPACT2_TARGETS): $(TOOL_JRE_COMPACT2_TARGETS)
-$(JRE_COMPACT3_TARGETS): $(TOOL_JRE_COMPACT3_TARGETS)
-
-profiles: $(TOOL_JRE_COMPACT1_TARGETS) \
-    $(TOOL_JRE_COMPACT2_TARGETS) \
-    $(TOOL_JRE_COMPACT3_TARGETS) \
-    $(JRE_COMPACT1_TARGETS) \
-    $(JRE_COMPACT2_TARGETS) \
-    $(JRE_COMPACT3_TARGETS)
-
-.PHONY: default all jdk jre symbols profiles
+.PHONY: default all jdk jre symbols
--- a/make/Main.gmk	Wed May 02 22:11:35 2018 -0700
+++ b/make/Main.gmk	Fri May 04 08:50:01 2018 -0700
@@ -344,9 +344,6 @@
 symbols-image:
 	+($(CD) $(TOPDIR)/make && $(MAKE) $(MAKE_ARGS) -f Images.gmk symbols)
 
-profiles-image:
-	+($(CD) $(TOPDIR)/make && $(MAKE) $(MAKE_ARGS) -f Images.gmk profiles)
-
 mac-bundles-jdk:
 	+($(CD) $(TOPDIR)/make && $(MAKE) $(MAKE_ARGS) -f MacBundles.gmk)
 
@@ -358,7 +355,7 @@
 
 ALL_TARGETS += store-source-revision create-source-revision-tracker bootcycle-images zip-security \
     zip-source jrtfs-jar jdk-image jre-image \
-    symbols-image profiles-image mac-bundles-jdk \
+    symbols-image mac-bundles-jdk \
     release-file exploded-image-optimize
 
 ################################################################################
@@ -569,16 +566,13 @@
 product-bundles:
 	+($(CD) $(TOPDIR)/make && $(MAKE) $(MAKE_ARGS) -f Bundles.gmk product-bundles)
 
-profiles-bundles:
-	+($(CD) $(TOPDIR)/make && $(MAKE) $(MAKE_ARGS) -f Bundles.gmk profiles-bundles)
-
 test-bundles:
 	+($(CD) $(TOPDIR)/make && $(MAKE) $(MAKE_ARGS) -f Bundles.gmk test-bundles)
 
 docs-bundles:
 	+($(CD) $(TOPDIR)/make && $(MAKE) $(MAKE_ARGS) -f Bundles.gmk docs-bundles)
 
-ALL_TARGETS += product-bundles profiles-bundles test-bundles docs-bundles
+ALL_TARGETS += product-bundles test-bundles docs-bundles
 
 ################################################################################
 # Install targets
@@ -804,8 +798,6 @@
   jre-image: jmods release-file
   symbols-image: $(LIBS_TARGETS) $(LAUNCHER_TARGETS)
 
-  profiles-image: jmods release-file
-
   mac-bundles-jdk: jdk-image jre-image
 
   # The optimize target can run as soon as the modules dir has been completely
@@ -886,8 +878,6 @@
 
   product-bundles: product-images
 
-  profiles-bundles: profiles-images
-
   test-bundles: test-image
 
   docs-bundles: docs-image
@@ -992,9 +982,6 @@
 # an image until this can be cleaned up properly.
 product-images: zip-security
 
-# Declare these for backwards compatiblity and convenience.
-profiles profiles-images: profiles-image
-
 # The module summary cannot be run when:
 # * Cross compiling and building a partial BUILDJDK for the build host
 # * An external buildjdk has been supplied since it may not match the
@@ -1034,7 +1021,6 @@
     exploded-image-base exploded-image \
     create-buildjdk docs-jdk-api docs-javase-api docs-reference-api docs-jdk \
     docs-javase docs-reference docs-javadoc mac-bundles product-images \
-    profiles profiles-images \
     docs-image test-image all-images \
     all-bundles
 
--- a/make/autoconf/hotspot.m4	Wed May 02 22:11:35 2018 -0700
+++ b/make/autoconf/hotspot.m4	Fri May 04 08:50:01 2018 -0700
@@ -25,7 +25,7 @@
 
 # All valid JVM features, regardless of platform
 VALID_JVM_FEATURES="compiler1 compiler2 zero minimal dtrace jvmti jvmci \
-    graal vm-structs jni-check services management all-gcs nmt cds \
+    graal vm-structs jni-check services management cmsgc g1gc parallelgc serialgc nmt cds \
     static-build link-time-opt aot"
 
 # All valid JVM variants
@@ -305,12 +305,8 @@
     AC_MSG_ERROR([Specified JVM feature 'jvmci' requires feature 'compiler2' or 'compiler1'])
   fi
 
-  if HOTSPOT_CHECK_JVM_FEATURE(compiler2) && ! HOTSPOT_CHECK_JVM_FEATURE(all-gcs); then
-    AC_MSG_ERROR([Specified JVM feature 'compiler2' requires feature 'all-gcs'])
-  fi
-
-  if HOTSPOT_CHECK_JVM_FEATURE(vm-structs) && ! HOTSPOT_CHECK_JVM_FEATURE(all-gcs); then
-    AC_MSG_ERROR([Specified JVM feature 'vm-structs' requires feature 'all-gcs'])
+  if HOTSPOT_CHECK_JVM_FEATURE(cmsgc) && ! HOTSPOT_CHECK_JVM_FEATURE(serialgc); then
+    AC_MSG_ERROR([Specified JVM feature 'cmsgc' requires feature 'serialgc'])
   fi
 
   # Turn on additional features based on other parts of configure
@@ -395,7 +391,7 @@
   fi
 
   # All variants but minimal (and custom) get these features
-  NON_MINIMAL_FEATURES="$NON_MINIMAL_FEATURES jvmti vm-structs jni-check services management all-gcs nmt"
+  NON_MINIMAL_FEATURES="$NON_MINIMAL_FEATURES cmsgc g1gc parallelgc serialgc jni-check jvmti management nmt services vm-structs"
   if test "x$ENABLE_CDS" = "xtrue"; then
     NON_MINIMAL_FEATURES="$NON_MINIMAL_FEATURES cds"
   fi
@@ -404,7 +400,7 @@
   JVM_FEATURES_server="compiler1 compiler2 $NON_MINIMAL_FEATURES $JVM_FEATURES $JVM_FEATURES_jvmci $JVM_FEATURES_aot $JVM_FEATURES_graal"
   JVM_FEATURES_client="compiler1 $NON_MINIMAL_FEATURES $JVM_FEATURES $JVM_FEATURES_jvmci"
   JVM_FEATURES_core="$NON_MINIMAL_FEATURES $JVM_FEATURES"
-  JVM_FEATURES_minimal="compiler1 minimal $JVM_FEATURES $JVM_FEATURES_link_time_opt"
+  JVM_FEATURES_minimal="compiler1 minimal serialgc $JVM_FEATURES $JVM_FEATURES_link_time_opt"
   JVM_FEATURES_zero="zero $NON_MINIMAL_FEATURES $JVM_FEATURES"
   JVM_FEATURES_custom="$JVM_FEATURES"
 
@@ -442,6 +438,12 @@
     eval $features_var_name='"'$JVM_FEATURES_FOR_VARIANT'"'
     AC_MSG_RESULT(["$JVM_FEATURES_FOR_VARIANT"])
 
+    # Verify that we have at least one gc selected
+    GC_FEATURES=`$ECHO $JVM_FEATURES_FOR_VARIANT | $GREP gc`
+    if test "x$GC_FEATURES" = x; then
+      AC_MSG_WARN([Invalid JVM features: No gc selected for variant $variant.])
+    fi
+
     # Validate features (for configure script errors, not user errors)
     BASIC_GET_NON_MATCHING_VALUES(INVALID_FEATURES, $JVM_FEATURES_FOR_VARIANT, $VALID_JVM_FEATURES)
     if test "x$INVALID_FEATURES" != x; then
--- a/make/autoconf/spec.gmk.in	Wed May 02 22:11:35 2018 -0700
+++ b/make/autoconf/spec.gmk.in	Fri May 04 08:50:01 2018 -0700
@@ -817,18 +817,11 @@
 # Images directory definitions
 JDK_IMAGE_SUBDIR:=jdk
 JRE_IMAGE_SUBDIR:=jre
-JRE_COMPACT1_IMAGE_SUBDIR := jre-compact1
-JRE_COMPACT2_IMAGE_SUBDIR := jre-compact2
-JRE_COMPACT3_IMAGE_SUBDIR := jre-compact3
 
 # Colon left out to be able to override output dir for bootcycle-images
 JDK_IMAGE_DIR=$(IMAGES_OUTPUTDIR)/$(JDK_IMAGE_SUBDIR)
 JRE_IMAGE_DIR=$(IMAGES_OUTPUTDIR)/$(JRE_IMAGE_SUBDIR)
 
-JRE_COMPACT1_IMAGE_DIR := $(IMAGES_OUTPUTDIR)/$(JRE_COMPACT1_IMAGE_SUBDIR)
-JRE_COMPACT2_IMAGE_DIR := $(IMAGES_OUTPUTDIR)/$(JRE_COMPACT2_IMAGE_SUBDIR)
-JRE_COMPACT3_IMAGE_DIR := $(IMAGES_OUTPUTDIR)/$(JRE_COMPACT3_IMAGE_SUBDIR)
-
 # Test image, as above
 TEST_IMAGE_SUBDIR:=test
 TEST_IMAGE_DIR=$(IMAGES_OUTPUTDIR)/$(TEST_IMAGE_SUBDIR)
@@ -866,12 +859,6 @@
 endif
 JDK_BUNDLE_NAME := jdk-$(BASE_NAME)_bin$(DEBUG_PART).tar.gz
 JRE_BUNDLE_NAME := jre-$(BASE_NAME)_bin$(DEBUG_PART).tar.gz
-JRE_COMPACT1_BUNDLE_NAME := \
-    jre-$(VERSION_SHORT)+$(VERSION_BUILD)-compact1_$(OPENJDK_TARGET_BUNDLE_PLATFORM)_bin$(DEBUG_PART).tar.gz
-JRE_COMPACT2_BUNDLE_NAME := \
-    jre-$(VERSION_SHORT)+$(VERSION_BUILD)-compact2_$(OPENJDK_TARGET_BUNDLE_PLATFORM)_bin$(DEBUG_PART).tar.gz
-JRE_COMPACT3_BUNDLE_NAME := \
-    jre-$(VERSION_SHORT)+$(VERSION_BUILD)-compact3_$(OPENJDK_TARGET_BUNDLE_PLATFORM)_bin$(DEBUG_PART).tar.gz
 JDK_SYMBOLS_BUNDLE_NAME := jdk-$(BASE_NAME)_bin$(DEBUG_PART)-symbols.tar.gz
 JRE_SYMBOLS_BUNDLE_NAME := jre-$(BASE_NAME)_bin$(DEBUG_PART)-symbols.tar.gz
 TEST_DEMOS_BUNDLE_NAME := jdk-$(BASE_NAME)_bin-tests-demos$(DEBUG_PART).tar.gz
--- a/make/autoconf/version-numbers	Wed May 02 22:11:35 2018 -0700
+++ b/make/autoconf/version-numbers	Fri May 04 08:50:01 2018 -0700
@@ -32,7 +32,7 @@
 DEFAULT_VERSION_DATE=2018-09-25
 DEFAULT_VERSION_CLASSFILE_MAJOR=55  # "`$EXPR $DEFAULT_VERSION_FEATURE + 44`"
 DEFAULT_VERSION_CLASSFILE_MINOR=0
-DEFAULT_ACCEPTABLE_BOOT_VERSIONS="9 10 11"
+DEFAULT_ACCEPTABLE_BOOT_VERSIONS="10 11"
 
 LAUNCHER_NAME=openjdk
 PRODUCT_NAME=OpenJDK
--- a/make/conf/jib-profiles.js	Wed May 02 22:11:35 2018 -0700
+++ b/make/conf/jib-profiles.js	Fri May 04 08:50:01 2018 -0700
@@ -390,7 +390,7 @@
         };
     };
 
-    common.boot_jdk_version = "9";
+    common.boot_jdk_version = "10";
     common.boot_jdk_home = input.get("boot_jdk", "home_path") + "/jdk-"
         + common.boot_jdk_version
         + (input.build_os == "macosx" ? ".jdk/Contents/Home" : "");
@@ -848,7 +848,7 @@
             server: "jpg",
             product: "jdk",
             version: common.boot_jdk_version,
-            build_number: "181",
+            build_number: "46",
             file: "bundles/" + boot_jdk_platform + "/jdk-" + common.boot_jdk_version + "_"
                 + boot_jdk_platform + "_bin.tar.gz",
             configure_args: "--with-boot-jdk=" + common.boot_jdk_home,
--- a/make/hotspot/lib/JvmDtraceObjects.gmk	Wed May 02 22:11:35 2018 -0700
+++ b/make/hotspot/lib/JvmDtraceObjects.gmk	Fri May 04 08:50:01 2018 -0700
@@ -77,9 +77,14 @@
         vmGCOperations.o \
     )
 
-    ifeq ($(call check-jvm-feature, all-gcs), true)
+    ifeq ($(call check-jvm-feature, cmsgc), true)
       DTRACE_INSTRUMENTED_OBJS += $(addprefix $(JVM_OUTPUTDIR)/objs/, \
           vmCMSOperations.o \
+      )
+    endif
+
+    ifeq ($(call check-jvm-feature, parallelgc), true)
+      DTRACE_INSTRUMENTED_OBJS += $(addprefix $(JVM_OUTPUTDIR)/objs/, \
           vmPSOperations.o \
       )
     endif
--- a/make/hotspot/lib/JvmFeatures.gmk	Wed May 02 22:11:35 2018 -0700
+++ b/make/hotspot/lib/JvmFeatures.gmk	Fri May 04 08:50:01 2018 -0700
@@ -118,19 +118,6 @@
       #
 endif
 
-ifneq ($(call check-jvm-feature, all-gcs), true)
-  JVM_CFLAGS_FEATURES += -DINCLUDE_ALL_GCS=0
-  JVM_EXCLUDE_PATTERNS += \
-      cms/ g1/ parallel/
-  JVM_EXCLUDE_FILES += \
-      concurrentGCThread.cpp \
-      suspendibleThreadSet.cpp \
-      plab.cpp
-  JVM_EXCLUDE_FILES += \
-      g1MemoryPool.cpp \
-      psMemoryPool.cpp
-endif
-
 ifneq ($(call check-jvm-feature, nmt), true)
   JVM_CFLAGS_FEATURES += -DINCLUDE_NMT=0
   JVM_EXCLUDE_FILES += \
@@ -138,13 +125,34 @@
       memTracker.cpp nmtDCmd.cpp mallocSiteTable.cpp
 endif
 
-ifeq ($(call check-jvm-feature, aot), true)
-  JVM_CFLAGS_FEATURES += -DINCLUDE_AOT
-else
+ifneq ($(call check-jvm-feature, aot), true)
+  JVM_CFLAGS_FEATURES += -DINCLUDE_AOT=0
   JVM_EXCLUDE_FILES += \
       compiledIC_aot_x86_64.cpp compilerRuntime.cpp \
       aotCodeHeap.cpp aotCompiledMethod.cpp aotLoader.cpp compiledIC_aot.cpp
 endif
+
+ifneq ($(call check-jvm-feature, cmsgc), true)
+  JVM_CFLAGS_FEATURES += -DINCLUDE_CMSGC=0
+  JVM_EXCLUDE_PATTERNS += gc/cms
+endif
+
+ifneq ($(call check-jvm-feature, g1gc), true)
+  JVM_CFLAGS_FEATURES += -DINCLUDE_G1GC=0
+  JVM_EXCLUDE_PATTERNS += gc/g1
+endif
+
+ifneq ($(call check-jvm-feature, parallelgc), true)
+  JVM_CFLAGS_FEATURES += -DINCLUDE_PARALLELGC=0
+  JVM_EXCLUDE_PATTERNS += gc/parallel
+endif
+
+ifneq ($(call check-jvm-feature, serialgc), true)
+  JVM_CFLAGS_FEATURES += -DINCLUDE_SERIALGC=0
+  JVM_EXCLUDE_PATTERNS += gc/serial
+  # If serial is disabled, we cannot use serial as OldGC in parallel
+  JVM_EXCLUDE_FILES += psMarkSweep.cpp psMarkSweepDecorator.cpp
+endif
 ################################################################################
 
 ifeq ($(call check-jvm-feature, link-time-opt), true)
--- a/make/test/JtregNativeHotspot.gmk	Wed May 02 22:11:35 2018 -0700
+++ b/make/test/JtregNativeHotspot.gmk	Fri May 04 08:50:01 2018 -0700
@@ -59,8 +59,18 @@
     -I$(VM_TESTBASE_DIR)/nsk/share/native \
     -I$(VM_TESTBASE_DIR)/nsk/share/jni
 
+NSK_MONITORING_INCLUDES := \
+    -I$(VM_TESTBASE_DIR)/nsk/share/native \
+    -I$(VM_TESTBASE_DIR)/nsk/share/jni
+
 BUILD_HOTSPOT_JTREG_LIBRARIES_CFLAGS_libProcessUtils := $(VM_SHARE_INCLUDES)
 
+BUILD_HOTSPOT_JTREG_LIBRARIES_CFLAGS_libThreadController := $(NSK_MONITORING_INCLUDES)
+BUILD_HOTSPOT_JTREG_LIBRARIES_CFLAGS_libDeadlock := $(NSK_MONITORING_INCLUDES)
+BUILD_HOTSPOT_JTREG_LIBRARIES_CFLAGS_libRecursiveMonitoringThread := $(NSK_MONITORING_INCLUDES)
+BUILD_HOTSPOT_JTREG_LIBRARIES_CFLAGS_libLockingThreads := $(NSK_MONITORING_INCLUDES)
+BUILD_HOTSPOT_JTREG_LIBRARIES_CFLAGS_libStackTraceController := $(NSK_MONITORING_INCLUDES)
+
 ################################################################################
 
 # Platform specific setup
--- a/src/hotspot/cpu/aarch64/macroAssembler_aarch64.cpp	Wed May 02 22:11:35 2018 -0700
+++ b/src/hotspot/cpu/aarch64/macroAssembler_aarch64.cpp	Fri May 04 08:50:01 2018 -0700
@@ -49,11 +49,6 @@
 #include "runtime/jniHandles.inline.hpp"
 #include "runtime/sharedRuntime.hpp"
 #include "runtime/thread.hpp"
-#if INCLUDE_ALL_GCS
-#include "gc/g1/g1BarrierSet.hpp"
-#include "gc/g1/g1CardTable.hpp"
-#include "gc/g1/heapRegion.hpp"
-#endif
 
 #ifdef PRODUCT
 #define BLOCK_COMMENT(str) /* nothing */
@@ -1951,6 +1946,11 @@
 void MacroAssembler::decrementw(Address dst, int value)
 {
   assert(!dst.uses(rscratch1), "invalid dst for address decrement");
+  if (dst.getMode() == Address::literal) {
+    assert(abs(value) < (1 << 12), "invalid value and address mode combination");
+    lea(rscratch2, dst);
+    dst = Address(rscratch2);
+  }
   ldrw(rscratch1, dst);
   decrementw(rscratch1, value);
   strw(rscratch1, dst);
@@ -1959,6 +1959,11 @@
 void MacroAssembler::decrement(Address dst, int value)
 {
   assert(!dst.uses(rscratch1), "invalid address for decrement");
+  if (dst.getMode() == Address::literal) {
+    assert(abs(value) < (1 << 12), "invalid value and address mode combination");
+    lea(rscratch2, dst);
+    dst = Address(rscratch2);
+  }
   ldr(rscratch1, dst);
   decrement(rscratch1, value);
   str(rscratch1, dst);
@@ -1991,6 +1996,11 @@
 void MacroAssembler::incrementw(Address dst, int value)
 {
   assert(!dst.uses(rscratch1), "invalid dst for address increment");
+  if (dst.getMode() == Address::literal) {
+    assert(abs(value) < (1 << 12), "invalid value and address mode combination");
+    lea(rscratch2, dst);
+    dst = Address(rscratch2);
+  }
   ldrw(rscratch1, dst);
   incrementw(rscratch1, value);
   strw(rscratch1, dst);
@@ -1999,6 +2009,11 @@
 void MacroAssembler::increment(Address dst, int value)
 {
   assert(!dst.uses(rscratch1), "invalid dst for address increment");
+  if (dst.getMode() == Address::literal) {
+    assert(abs(value) < (1 << 12), "invalid value and address mode combination");
+    lea(rscratch2, dst);
+    dst = Address(rscratch2);
+  }
   ldr(rscratch1, dst);
   increment(rscratch1, value);
   str(rscratch1, dst);
--- a/src/hotspot/cpu/aarch64/macroAssembler_aarch64.hpp	Wed May 02 22:11:35 2018 -0700
+++ b/src/hotspot/cpu/aarch64/macroAssembler_aarch64.hpp	Fri May 04 08:50:01 2018 -0700
@@ -781,23 +781,6 @@
 
   void resolve_jobject(Register value, Register thread, Register tmp);
 
-#if INCLUDE_ALL_GCS
-
-  void g1_write_barrier_pre(Register obj,
-                            Register pre_val,
-                            Register thread,
-                            Register tmp,
-                            bool tosca_live,
-                            bool expand_call);
-
-  void g1_write_barrier_post(Register store_addr,
-                             Register new_val,
-                             Register thread,
-                             Register tmp,
-                             Register tmp2);
-
-#endif // INCLUDE_ALL_GCS
-
   // oop manipulations
   void load_klass(Register dst, Register src);
   void store_klass(Register dst, Register src);
--- a/src/hotspot/cpu/aarch64/sharedRuntime_aarch64.cpp	Wed May 02 22:11:35 2018 -0700
+++ b/src/hotspot/cpu/aarch64/sharedRuntime_aarch64.cpp	Fri May 04 08:50:01 2018 -0700
@@ -2339,7 +2339,7 @@
   __ b(cont);
 
   int reexecute_offset = __ pc() - start;
-#if defined(INCLUDE_JVMCI) && !defined(COMPILER1)
+#if INCLUDE_JVMCI && !defined(COMPILER1)
   if (EnableJVMCI && UseJVMCICompiler) {
     // JVMCI does not use this kind of deoptimization
     __ should_not_reach_here();
--- a/src/hotspot/cpu/arm/assembler_arm.cpp	Wed May 02 22:11:35 2018 -0700
+++ b/src/hotspot/cpu/arm/assembler_arm.cpp	Fri May 04 08:50:01 2018 -0700
@@ -42,10 +42,6 @@
 #include "runtime/stubRoutines.hpp"
 #include "utilities/hashtable.hpp"
 #include "utilities/macros.hpp"
-#if INCLUDE_ALL_GCS
-#include "gc/g1/g1BarrierSet.hpp"
-#include "gc/g1/heapRegion.hpp"
-#endif // INCLUDE_ALL_GCS
 
 int AbstractAssembler::code_fill_byte() {
   return 0xff; // illegal instruction 0xffffffff
--- a/src/hotspot/cpu/arm/assembler_arm_32.cpp	Wed May 02 22:11:35 2018 -0700
+++ b/src/hotspot/cpu/arm/assembler_arm_32.cpp	Fri May 04 08:50:01 2018 -0700
@@ -42,10 +42,6 @@
 #include "runtime/stubRoutines.hpp"
 #include "utilities/hashtable.hpp"
 #include "utilities/macros.hpp"
-#if INCLUDE_ALL_GCS
-#include "gc/g1/g1BarrierSet.hpp"
-#include "gc/g1/heapRegion.hpp"
-#endif // INCLUDE_ALL_GCS
 
 #ifdef COMPILER2
 // Convert the raw encoding form into the form expected by the
--- a/src/hotspot/cpu/arm/assembler_arm_64.cpp	Wed May 02 22:11:35 2018 -0700
+++ b/src/hotspot/cpu/arm/assembler_arm_64.cpp	Fri May 04 08:50:01 2018 -0700
@@ -42,10 +42,6 @@
 #include "runtime/stubRoutines.hpp"
 #include "utilities/hashtable.hpp"
 #include "utilities/macros.hpp"
-#if INCLUDE_ALL_GCS
-#include "gc/g1/g1BarrierSet.hpp"
-#include "gc/g1/heapRegion.hpp"
-#endif // INCLUDE_ALL_GCS
 
 // Returns whether given imm has equal bit fields <0:size-1> and <size:2*size-1>.
 inline bool Assembler::LogicalImmediate::has_equal_subpatterns(uintx imm, int size) {
--- a/src/hotspot/cpu/arm/c1_LIRGenerator_arm.cpp	Wed May 02 22:11:35 2018 -0700
+++ b/src/hotspot/cpu/arm/c1_LIRGenerator_arm.cpp	Fri May 04 08:50:01 2018 -0700
@@ -486,6 +486,9 @@
 void LIRGenerator::CardTableBarrierSet_post_barrier_helper(LIR_OprDesc* addr, LIR_Const* card_table_base) {
   assert(addr->is_register(), "must be a register at this point");
 
+  CardTableBarrierSet* ctbs = barrier_set_cast<CardTableBarrierSet>(BarrierSet::barrier_set());
+  CardTable* ct = ctbs->card_table();
+
   LIR_Opr tmp = FrameMap::LR_ptr_opr;
 
   // TODO-AARCH64: check performance
@@ -507,7 +510,7 @@
   LIR_Address* card_addr = new LIR_Address(tmp, addr, (LIR_Address::Scale) -CardTable::card_shift, 0, T_BOOLEAN);
 #endif
   if (UseCondCardMark) {
-    if (UseConcMarkSweepGC) {
+    if (ct->scanned_concurrently()) {
       __ membar_storeload();
     }
     LIR_Opr cur_value = new_register(T_INT);
@@ -519,11 +522,9 @@
     set_card(tmp, card_addr);
     __ branch_destination(L_already_dirty->label());
   } else {
-#if INCLUDE_ALL_GCS
-    if (UseConcMarkSweepGC && CMSPrecleaningEnabled) {
+    if (ct->scanned_concurrently()) {
       __ membar_storestore();
     }
-#endif
     set_card(tmp, card_addr);
   }
 }
--- a/src/hotspot/cpu/arm/gc/g1/g1BarrierSetAssembler_arm.cpp	Wed May 02 22:11:35 2018 -0700
+++ b/src/hotspot/cpu/arm/gc/g1/g1BarrierSetAssembler_arm.cpp	Fri May 04 08:50:01 2018 -0700
@@ -28,6 +28,7 @@
 #include "gc/g1/g1BarrierSetAssembler.hpp"
 #include "gc/g1/g1ThreadLocalData.hpp"
 #include "gc/g1/g1CardTable.hpp"
+#include "gc/g1/g1ThreadLocalData.hpp"
 #include "gc/g1/heapRegion.hpp"
 #include "interpreter/interp_masm.hpp"
 #include "runtime/sharedRuntime.hpp"
@@ -127,6 +128,239 @@
 #endif // !AARCH64
 }
 
+// G1 pre-barrier.
+// Blows all volatile registers (R0-R3 on 32-bit ARM, R0-R18 on AArch64, Rtemp, LR).
+// If store_addr != noreg, then previous value is loaded from [store_addr];
+// in such case store_addr and new_val registers are preserved;
+// otherwise pre_val register is preserved.
+void G1BarrierSetAssembler::g1_write_barrier_pre(MacroAssembler* masm,
+                                          Register store_addr,
+                                          Register new_val,
+                                          Register pre_val,
+                                          Register tmp1,
+                                          Register tmp2) {
+  Label done;
+  Label runtime;
+
+  if (store_addr != noreg) {
+    assert_different_registers(store_addr, new_val, pre_val, tmp1, tmp2, noreg);
+  } else {
+    assert (new_val == noreg, "should be");
+    assert_different_registers(pre_val, tmp1, tmp2, noreg);
+  }
+
+  Address in_progress(Rthread, in_bytes(G1ThreadLocalData::satb_mark_queue_active_offset()));
+  Address index(Rthread, in_bytes(G1ThreadLocalData::satb_mark_queue_index_offset()));
+  Address buffer(Rthread, in_bytes(G1ThreadLocalData::satb_mark_queue_buffer_offset()));
+
+  // Is marking active?
+  assert(in_bytes(SATBMarkQueue::byte_width_of_active()) == 1, "adjust this code");
+  __ ldrb(tmp1, in_progress);
+  __ cbz(tmp1, done);
+
+  // Do we need to load the previous value?
+  if (store_addr != noreg) {
+    __ load_heap_oop(pre_val, Address(store_addr, 0));
+  }
+
+  // Is the previous value null?
+  __ cbz(pre_val, done);
+
+  // Can we store original value in the thread's buffer?
+  // Is index == 0?
+  // (The index field is typed as size_t.)
+
+  __ ldr(tmp1, index);           // tmp1 := *index_adr
+  __ ldr(tmp2, buffer);
+
+  __ subs(tmp1, tmp1, wordSize); // tmp1 := tmp1 - wordSize
+  __ b(runtime, lt);             // If negative, goto runtime
+
+  __ str(tmp1, index);           // *index_adr := tmp1
+
+  // Record the previous value
+  __ str(pre_val, Address(tmp2, tmp1));
+  __ b(done);
+
+  __ bind(runtime);
+
+  // save the live input values
+#ifdef AARCH64
+  if (store_addr != noreg) {
+    __ raw_push(store_addr, new_val);
+  } else {
+    __ raw_push(pre_val, ZR);
+  }
+#else
+  if (store_addr != noreg) {
+    // avoid raw_push to support any ordering of store_addr and new_val
+    __ push(RegisterSet(store_addr) | RegisterSet(new_val));
+  } else {
+    __ push(pre_val);
+  }
+#endif // AARCH64
+
+  if (pre_val != R0) {
+    __ mov(R0, pre_val);
+  }
+  __ mov(R1, Rthread);
+
+  __ call_VM_leaf(CAST_FROM_FN_PTR(address, SharedRuntime::g1_wb_pre), R0, R1);
+
+#ifdef AARCH64
+  if (store_addr != noreg) {
+    __ raw_pop(store_addr, new_val);
+  } else {
+    __ raw_pop(pre_val, ZR);
+  }
+#else
+  if (store_addr != noreg) {
+    __ pop(RegisterSet(store_addr) | RegisterSet(new_val));
+  } else {
+    __ pop(pre_val);
+  }
+#endif // AARCH64
+
+  __ bind(done);
+}
+
+// G1 post-barrier.
+// Blows all volatile registers (R0-R3 on 32-bit ARM, R0-R18 on AArch64, Rtemp, LR).
+void G1BarrierSetAssembler::g1_write_barrier_post(MacroAssembler* masm,
+                                           Register store_addr,
+                                           Register new_val,
+                                           Register tmp1,
+                                           Register tmp2,
+                                           Register tmp3) {
+
+  Address queue_index(Rthread, in_bytes(G1ThreadLocalData::dirty_card_queue_index_offset()));
+  Address buffer(Rthread, in_bytes(G1ThreadLocalData::dirty_card_queue_buffer_offset()));
+
+  BarrierSet* bs = BarrierSet::barrier_set();
+  CardTableBarrierSet* ctbs = barrier_set_cast<CardTableBarrierSet>(bs);
+  CardTable* ct = ctbs->card_table();
+  Label done;
+  Label runtime;
+
+  // Does store cross heap regions?
+
+  __ eor(tmp1, store_addr, new_val);
+#ifdef AARCH64
+  __ logical_shift_right(tmp1, tmp1, HeapRegion::LogOfHRGrainBytes);
+  __ cbz(tmp1, done);
+#else
+  __ movs(tmp1, AsmOperand(tmp1, lsr, HeapRegion::LogOfHRGrainBytes));
+  __ b(done, eq);
+#endif
+
+  // crosses regions, storing NULL?
+
+  __ cbz(new_val, done);
+
+  // storing region crossing non-NULL, is card already dirty?
+  const Register card_addr = tmp1;
+  assert(sizeof(*ct->byte_map_base()) == sizeof(jbyte), "adjust this code");
+
+  __ mov_address(tmp2, (address)ct->byte_map_base(), symbolic_Relocation::card_table_reference);
+  __ add(card_addr, tmp2, AsmOperand(store_addr, lsr, CardTable::card_shift));
+
+  __ ldrb(tmp2, Address(card_addr));
+  __ cmp(tmp2, (int)G1CardTable::g1_young_card_val());
+  __ b(done, eq);
+
+  __ membar(MacroAssembler::Membar_mask_bits(MacroAssembler::StoreLoad), tmp2);
+
+  assert(CardTable::dirty_card_val() == 0, "adjust this code");
+  __ ldrb(tmp2, Address(card_addr));
+  __ cbz(tmp2, done);
+
+  // storing a region crossing, non-NULL oop, card is clean.
+  // dirty card and log.
+
+  __ strb(__ zero_register(tmp2), Address(card_addr));
+
+  __ ldr(tmp2, queue_index);
+  __ ldr(tmp3, buffer);
+
+  __ subs(tmp2, tmp2, wordSize);
+  __ b(runtime, lt); // go to runtime if now negative
+
+  __ str(tmp2, queue_index);
+
+  __ str(card_addr, Address(tmp3, tmp2));
+  __ b(done);
+
+  __ bind(runtime);
+
+  if (card_addr != R0) {
+    __ mov(R0, card_addr);
+  }
+  __ mov(R1, Rthread);
+  __ call_VM_leaf(CAST_FROM_FN_PTR(address, SharedRuntime::g1_wb_post), R0, R1);
+
+  __ bind(done);
+}
+
+void G1BarrierSetAssembler::load_at(MacroAssembler* masm, DecoratorSet decorators, BasicType type,
+                                    Register dst, Address src, Register tmp1, Register tmp2, Register tmp3) {
+  bool on_oop = type == T_OBJECT || type == T_ARRAY;
+  bool on_weak = (decorators & ON_WEAK_OOP_REF) != 0;
+  bool on_phantom = (decorators & ON_PHANTOM_OOP_REF) != 0;
+  bool on_reference = on_weak || on_phantom;
+
+  ModRefBarrierSetAssembler::load_at(masm, decorators, type, dst, src, tmp1, tmp2, tmp3);
+  if (on_oop && on_reference) {
+    // Generate the G1 pre-barrier code to log the value of
+    // the referent field in an SATB buffer.
+    g1_write_barrier_pre(masm, noreg, noreg, dst, tmp1, tmp2);
+  }
+}
+
+
+void G1BarrierSetAssembler::oop_store_at(MacroAssembler* masm, DecoratorSet decorators, BasicType type,
+                                         Address obj, Register new_val, Register tmp1, Register tmp2, Register tmp3, bool is_null) {
+  bool in_heap = (decorators & IN_HEAP) != 0;
+  bool in_concurrent_root = (decorators & IN_CONCURRENT_ROOT) != 0;
+
+  bool needs_pre_barrier = in_heap || in_concurrent_root;
+  bool needs_post_barrier = (new_val != noreg) && in_heap;
+
+  // flatten object address if needed
+  assert (obj.mode() == basic_offset, "pre- or post-indexing is not supported here");
+
+  const Register store_addr = obj.base();
+  if (obj.index() != noreg) {
+    assert (obj.disp() == 0, "index or displacement, not both");
+#ifdef AARCH64
+    __ add(store_addr, obj.base(), obj.index(), obj.extend(), obj.shift_imm());
+#else
+    assert(obj.offset_op() == add_offset, "addition is expected");
+    __ add(store_addr, obj.base(), AsmOperand(obj.index(), obj.shift(), obj.shift_imm()));
+#endif // AARCH64
+  } else if (obj.disp() != 0) {
+    __ add(store_addr, obj.base(), obj.disp());
+  }
+
+  if (needs_pre_barrier) {
+    g1_write_barrier_pre(masm, store_addr, new_val, tmp1, tmp2, tmp3);
+  }
+
+  if (is_null) {
+    BarrierSetAssembler::store_at(masm, decorators, type, Address(store_addr), new_val, tmp1, tmp2, tmp3, true);
+  } else {
+    // G1 barrier needs uncompressed oop for region cross check.
+    Register val_to_store = new_val;
+    if (UseCompressedOops) {
+      val_to_store = tmp1;
+      __ mov(val_to_store, new_val);
+    }
+    BarrierSetAssembler::store_at(masm, decorators, type, Address(store_addr), val_to_store, tmp1, tmp2, tmp3, false);
+    if (needs_post_barrier) {
+      g1_write_barrier_post(masm, store_addr, new_val, tmp1, tmp2, tmp3);
+    }
+  }
+};
+
 #ifdef COMPILER1
 
 #undef __
--- a/src/hotspot/cpu/arm/gc/g1/g1BarrierSetAssembler_arm.hpp	Wed May 02 22:11:35 2018 -0700
+++ b/src/hotspot/cpu/arm/gc/g1/g1BarrierSetAssembler_arm.hpp	Fri May 04 08:50:01 2018 -0700
@@ -41,6 +41,27 @@
   void gen_write_ref_array_post_barrier(MacroAssembler* masm, DecoratorSet decorators,
                                         Register addr, Register count, Register tmp);
 
+  void g1_write_barrier_pre(MacroAssembler* masm,
+                            Register store_addr,
+                            Register new_val,
+                            Register pre_val,
+                            Register tmp1,
+                            Register tmp2);
+
+  void g1_write_barrier_post(MacroAssembler* masm,
+                             Register store_addr,
+                             Register new_val,
+                             Register tmp1,
+                             Register tmp2,
+                             Register tmp3);
+
+  virtual void oop_store_at(MacroAssembler* masm, DecoratorSet decorators, BasicType type,
+                            Address obj, Register new_val, Register tmp1, Register tmp2, Register tmp3, bool is_null);
+
+public:
+  virtual void load_at(MacroAssembler* masm, DecoratorSet decorators, BasicType type,
+                       Register dst, Address src, Register tmp1, Register tmp2, Register tmp3);
+
 #ifdef COMPILER1
 public:
   void gen_pre_barrier_stub(LIR_Assembler* ce, G1PreBarrierStub* stub);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/cpu/arm/gc/shared/barrierSetAssembler_arm.cpp	Fri May 04 08:50:01 2018 -0700
@@ -0,0 +1,87 @@
+/*
+ * 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 "precompiled.hpp"
+#include "gc/shared/barrierSetAssembler.hpp"
+
+#define __ masm->
+
+void BarrierSetAssembler::load_at(MacroAssembler* masm, DecoratorSet decorators, BasicType type,
+                                  Register dst, Address src, Register tmp1, Register tmp2, Register tmp3) {
+  bool on_heap = (decorators & IN_HEAP) != 0;
+  bool on_root = (decorators & IN_ROOT) != 0;
+  switch (type) {
+  case T_OBJECT:
+  case T_ARRAY: {
+    if (on_heap) {
+#ifdef AARCH64
+      if (UseCompressedOops) {
+        __ ldr_w(dst, src);
+        __ decode_heap_oop(dst);
+      } else
+#endif // AARCH64
+      {
+        __ ldr(dst, src);
+      }
+    } else {
+      assert(on_root, "why else?");
+      __ ldr(dst, src);
+    }
+    break;
+  }
+  default: Unimplemented();
+  }
+
+}
+
+void BarrierSetAssembler::store_at(MacroAssembler* masm, DecoratorSet decorators, BasicType type,
+                                   Address obj, Register val, Register tmp1, Register tmp2, Register tmp3, bool is_null) {
+  bool on_heap = (decorators & IN_HEAP) != 0;
+  bool on_root = (decorators & IN_ROOT) != 0;
+  switch (type) {
+  case T_OBJECT:
+  case T_ARRAY: {
+    if (on_heap) {
+#ifdef AARCH64
+      if (UseCompressedOops) {
+        assert(!dst.uses(src), "not enough registers");
+        if (!is_null) {
+          __ encode_heap_oop(src);
+        }
+        __ str_w(val, obj);
+      } else
+#endif // AARCH64
+      {
+        __ str(val, obj);
+      }
+    } else {
+      assert(on_root, "why else?");
+      __ str(val, obj);
+    }
+    break;
+  }
+  default: Unimplemented();
+  }
+}
+
--- a/src/hotspot/cpu/arm/gc/shared/barrierSetAssembler_arm.hpp	Wed May 02 22:11:35 2018 -0700
+++ b/src/hotspot/cpu/arm/gc/shared/barrierSetAssembler_arm.hpp	Fri May 04 08:50:01 2018 -0700
@@ -36,6 +36,11 @@
   virtual void arraycopy_epilogue(MacroAssembler* masm, DecoratorSet decorators, bool is_oop,
                                   Register addr, Register count, Register tmp) {}
 
+  virtual void load_at(MacroAssembler* masm, DecoratorSet decorators, BasicType type,
+                       Register dst, Address src, Register tmp1, Register tmp2, Register tmp3);
+  virtual void store_at(MacroAssembler* masm, DecoratorSet decorators, BasicType type,
+                        Address obj, Register new_val, Register tmp1, Register tmp2, Register tmp3, bool is_null);
+
   virtual void barrier_stubs_init() {}
 };
 
--- a/src/hotspot/cpu/arm/gc/shared/cardTableBarrierSetAssembler_arm.cpp	Wed May 02 22:11:35 2018 -0700
+++ b/src/hotspot/cpu/arm/gc/shared/cardTableBarrierSetAssembler_arm.cpp	Fri May 04 08:50:01 2018 -0700
@@ -72,3 +72,111 @@
   __ b(L_cardtable_loop, ge);
   __ BIND(L_done);
 }
+
+void CardTableBarrierSetAssembler::oop_store_at(MacroAssembler* masm, DecoratorSet decorators, BasicType type,
+                                             Address obj, Register new_val, Register tmp1, Register tmp2, Register tmp3, bool is_null) {
+  bool on_array = (decorators & IN_HEAP_ARRAY) != 0;
+  bool on_anonymous = (decorators & ON_UNKNOWN_OOP_REF) != 0;
+  bool precise = on_array || on_anonymous;
+
+  if (is_null) {
+    BarrierSetAssembler::store_at(masm, decorators, type, obj, new_val, tmp1, tmp2, tmp3, true);
+  } else {
+    assert (!precise || (obj.index() == noreg && obj.disp() == 0),
+            "store check address should be calculated beforehand");
+
+    store_check_part1(masm, tmp1);
+    BarrierSetAssembler::store_at(masm, decorators, type, obj, new_val, tmp1, tmp2, tmp3, false);
+    new_val = noreg;
+    store_check_part2(masm, obj.base(), tmp1, tmp2);
+  }
+}
+
+// The 1st part of the store check.
+// Sets card_table_base register.
+void CardTableBarrierSetAssembler::store_check_part1(MacroAssembler* masm, Register card_table_base) {
+  // Check barrier set type (should be card table) and element size
+  BarrierSet* bs = BarrierSet::barrier_set();
+  assert(bs->kind() == BarrierSet::CardTableBarrierSet,
+         "Wrong barrier set kind");
+
+  CardTableBarrierSet* ctbs = barrier_set_cast<CardTableBarrierSet>(bs);
+  CardTable* ct = ctbs->card_table();
+  assert(sizeof(*ct->byte_map_base()) == sizeof(jbyte), "Adjust store check code");
+
+  // Load card table base address.
+
+  /* Performance note.
+
+     There is an alternative way of loading card table base address
+     from thread descriptor, which may look more efficient:
+
+     ldr(card_table_base, Address(Rthread, JavaThread::card_table_base_offset()));
+
+     However, performance measurements of micro benchmarks and specJVM98
+     showed that loading of card table base from thread descriptor is
+     7-18% slower compared to loading of literal embedded into the code.
+     Possible cause is a cache miss (card table base address resides in a
+     rarely accessed area of thread descriptor).
+  */
+  // TODO-AARCH64 Investigate if mov_slow is faster than ldr from Rthread on AArch64
+  __ mov_address(card_table_base, (address)ct->byte_map_base(), symbolic_Relocation::card_table_reference);
+}
+
+// The 2nd part of the store check.
+void CardTableBarrierSetAssembler::store_check_part2(MacroAssembler* masm, Register obj, Register card_table_base, Register tmp) {
+  assert_different_registers(obj, card_table_base, tmp);
+
+  BarrierSet* bs = BarrierSet::barrier_set();
+  assert(bs->kind() == BarrierSet::CardTableBarrierSet,
+         "Wrong barrier set kind");
+
+  CardTableBarrierSet* ctbs = barrier_set_cast<CardTableBarrierSet>(bs);
+  CardTable* ct = ctbs->card_table();
+  assert(sizeof(*ct->byte_map_base()) == sizeof(jbyte), "Adjust store check code");
+
+  assert(CardTable::dirty_card_val() == 0, "Dirty card value must be 0 due to optimizations.");
+#ifdef AARCH64
+  add(card_table_base, card_table_base, AsmOperand(obj, lsr, CardTable::card_shift));
+  Address card_table_addr(card_table_base);
+#else
+  Address card_table_addr(card_table_base, obj, lsr, CardTable::card_shift);
+#endif
+
+  if (UseCondCardMark) {
+    if (ct->scanned_concurrently()) {
+      __ membar(MacroAssembler::Membar_mask_bits(MacroAssembler::StoreLoad), noreg);
+    }
+    Label already_dirty;
+
+    __ ldrb(tmp, card_table_addr);
+    __ cbz(tmp, already_dirty);
+
+    set_card(masm, card_table_base, card_table_addr, tmp);
+    __ bind(already_dirty);
+
+  } else {
+    if (ct->scanned_concurrently()) {
+      __ membar(MacroAssembler::Membar_mask_bits(MacroAssembler::StoreStore), noreg);
+    }
+    set_card(masm, card_table_base, card_table_addr, tmp);
+  }
+}
+
+void CardTableBarrierSetAssembler::set_card(MacroAssembler* masm, Register card_table_base, Address card_table_addr, Register tmp) {
+#ifdef AARCH64
+  strb(ZR, card_table_addr);
+#else
+  CardTableBarrierSet* ctbs = barrier_set_cast<CardTableBarrierSet>(BarrierSet::barrier_set());
+  CardTable* ct = ctbs->card_table();
+  if ((((uintptr_t)ct->byte_map_base() & 0xff) == 0)) {
+    // Card table is aligned so the lowest byte of the table address base is zero.
+    // This works only if the code is not saved for later use, possibly
+    // in a context where the base would no longer be aligned.
+    __ strb(card_table_base, card_table_addr);
+  } else {
+    __ mov(tmp, 0);
+    __ strb(tmp, card_table_addr);
+  }
+#endif // AARCH64
+}
--- a/src/hotspot/cpu/arm/gc/shared/cardTableBarrierSetAssembler_arm.hpp	Wed May 02 22:11:35 2018 -0700
+++ b/src/hotspot/cpu/arm/gc/shared/cardTableBarrierSetAssembler_arm.hpp	Fri May 04 08:50:01 2018 -0700
@@ -29,9 +29,18 @@
 #include "gc/shared/modRefBarrierSetAssembler.hpp"
 
 class CardTableBarrierSetAssembler: public ModRefBarrierSetAssembler {
+private:
+  void store_check(MacroAssembler* masm, Register obj, Address dst);
+  void store_check_part1(MacroAssembler* masm, Register card_table_base);
+  void store_check_part2(MacroAssembler* masm, Register obj, Register card_table_base, Register tmp);
+
+  void set_card(MacroAssembler* masm, Register card_table_base, Address card_table_addr, Register tmp);
+
 protected:
   virtual void gen_write_ref_array_post_barrier(MacroAssembler* masm, DecoratorSet decorators,
                                                 Register addr, Register count, Register tmp);
+  virtual void oop_store_at(MacroAssembler* masm, DecoratorSet decorators, BasicType type,
+                            Address obj, Register new_val, Register tmp1, Register tmp2, Register tmp3, bool is_null);
 };
 
 #endif // #ifndef CPU_ARM_GC_SHARED_CARDTABLEBARRIERSETASSEMBLER_ARM_HPP
--- a/src/hotspot/cpu/arm/gc/shared/modRefBarrierSetAssembler_arm.cpp	Wed May 02 22:11:35 2018 -0700
+++ b/src/hotspot/cpu/arm/gc/shared/modRefBarrierSetAssembler_arm.cpp	Fri May 04 08:50:01 2018 -0700
@@ -42,3 +42,12 @@
     gen_write_ref_array_post_barrier(masm, decorators, addr, count, tmp);
   }
 }
+
+void ModRefBarrierSetAssembler::store_at(MacroAssembler* masm, DecoratorSet decorators, BasicType type,
+                                         Address obj, Register new_val, Register tmp1, Register tmp2, Register tmp3, bool is_null) {
+  if (type == T_OBJECT || type == T_ARRAY) {
+    oop_store_at(masm, decorators, type, obj, new_val, tmp1, tmp2, tmp3, is_null);
+  } else {
+    BarrierSetAssembler::store_at(masm, decorators, type, obj, new_val, tmp1, tmp2, tmp3, is_null);
+  }
+}
--- a/src/hotspot/cpu/arm/gc/shared/modRefBarrierSetAssembler_arm.hpp	Wed May 02 22:11:35 2018 -0700
+++ b/src/hotspot/cpu/arm/gc/shared/modRefBarrierSetAssembler_arm.hpp	Fri May 04 08:50:01 2018 -0700
@@ -28,6 +28,10 @@
 #include "asm/macroAssembler.hpp"
 #include "gc/shared/barrierSetAssembler.hpp"
 
+// The ModRefBarrierSetAssembler filters away accesses on BasicTypes other
+// than T_OBJECT/T_ARRAY (oops). The oop accesses call one of the protected
+// accesses, which are overridden in the concrete BarrierSetAssembler.
+
 class ModRefBarrierSetAssembler: public BarrierSetAssembler {
 protected:
   virtual void gen_write_ref_array_pre_barrier(MacroAssembler* masm, DecoratorSet decorators,
@@ -35,11 +39,16 @@
   virtual void gen_write_ref_array_post_barrier(MacroAssembler* masm, DecoratorSet decorators,
                                                 Register addr, Register count, Register tmp) {}
 
+  virtual void oop_store_at(MacroAssembler* masm, DecoratorSet decorators, BasicType type,
+                            Address obj, Register val, Register tmp1, Register tmp2, Register tmp3, bool is_null) = 0;
+
 public:
   virtual void arraycopy_prologue(MacroAssembler* masm, DecoratorSet decorators, bool is_oop,
                                   Register addr, Register count, int callee_saved_regs);
   virtual void arraycopy_epilogue(MacroAssembler* masm, DecoratorSet decorators, bool is_oop,
                                   Register addr, Register count, Register tmp);
+  virtual void store_at(MacroAssembler* masm, DecoratorSet decorators, BasicType type,
+                        Address obj, Register val, Register tmp1, Register tmp2, Register tmp3, bool is_null);
 };
 
 #endif // CPU_ARM_GC_SHARED_MODREFBARRIERSETASSEMBLER_ARM_HPP
--- a/src/hotspot/cpu/arm/interp_masm_arm.cpp	Wed May 02 22:11:35 2018 -0700
+++ b/src/hotspot/cpu/arm/interp_masm_arm.cpp	Fri May 04 08:50:01 2018 -0700
@@ -43,11 +43,6 @@
 #include "runtime/frame.inline.hpp"
 #include "runtime/sharedRuntime.hpp"
 
-#if INCLUDE_ALL_GCS
-#include "gc/g1/g1BarrierSet.hpp"
-#include "gc/g1/heapRegion.hpp"
-#endif // INCLUDE_ALL_GCS
-
 //--------------------------------------------------------------------
 // Implementation of InterpreterMacroAssembler
 
@@ -406,91 +401,6 @@
 }
 
 
-// The 1st part of the store check.
-// Sets card_table_base register.
-void InterpreterMacroAssembler::store_check_part1(Register card_table_base) {
-  // Check barrier set type (should be card table) and element size
-  BarrierSet* bs = BarrierSet::barrier_set();
-  assert(bs->kind() == BarrierSet::CardTableBarrierSet,
-         "Wrong barrier set kind");
-
-  CardTableBarrierSet* ctbs = barrier_set_cast<CardTableBarrierSet>(bs);
-  CardTable* ct = ctbs->card_table();
-  assert(sizeof(*ct->byte_map_base()) == sizeof(jbyte), "Adjust store check code");
-
-  // Load card table base address.
-
-  /* Performance note.
-
-     There is an alternative way of loading card table base address
-     from thread descriptor, which may look more efficient:
-
-     ldr(card_table_base, Address(Rthread, JavaThread::card_table_base_offset()));
-
-     However, performance measurements of micro benchmarks and specJVM98
-     showed that loading of card table base from thread descriptor is
-     7-18% slower compared to loading of literal embedded into the code.
-     Possible cause is a cache miss (card table base address resides in a
-     rarely accessed area of thread descriptor).
-  */
-  // TODO-AARCH64 Investigate if mov_slow is faster than ldr from Rthread on AArch64
-  mov_address(card_table_base, (address)ct->byte_map_base(), symbolic_Relocation::card_table_reference);
-}
-
-// The 2nd part of the store check.
-void InterpreterMacroAssembler::store_check_part2(Register obj, Register card_table_base, Register tmp) {
-  assert_different_registers(obj, card_table_base, tmp);
-
-  assert(CardTable::dirty_card_val() == 0, "Dirty card value must be 0 due to optimizations.");
-#ifdef AARCH64
-  add(card_table_base, card_table_base, AsmOperand(obj, lsr, CardTable::card_shift));
-  Address card_table_addr(card_table_base);
-#else
-  Address card_table_addr(card_table_base, obj, lsr, CardTable::card_shift);
-#endif
-
-  if (UseCondCardMark) {
-#if INCLUDE_ALL_GCS
-    if (UseConcMarkSweepGC) {
-      membar(MacroAssembler::Membar_mask_bits(MacroAssembler::StoreLoad), noreg);
-    }
-#endif
-    Label already_dirty;
-
-    ldrb(tmp, card_table_addr);
-    cbz(tmp, already_dirty);
-
-    set_card(card_table_base, card_table_addr, tmp);
-    bind(already_dirty);
-
-  } else {
-#if INCLUDE_ALL_GCS
-    if (UseConcMarkSweepGC && CMSPrecleaningEnabled) {
-      membar(MacroAssembler::Membar_mask_bits(MacroAssembler::StoreStore), noreg);
-    }
-#endif
-    set_card(card_table_base, card_table_addr, tmp);
-  }
-}
-
-void InterpreterMacroAssembler::set_card(Register card_table_base, Address card_table_addr, Register tmp) {
-#ifdef AARCH64
-  strb(ZR, card_table_addr);
-#else
-  CardTableBarrierSet* ctbs = barrier_set_cast<CardTableBarrierSet>(BarrierSet::barrier_set());
-  CardTable* ct = ctbs->card_table();
-  if ((((uintptr_t)ct->byte_map_base() & 0xff) == 0)) {
-    // Card table is aligned so the lowest byte of the table address base is zero.
-    // This works only if the code is not saved for later use, possibly
-    // in a context where the base would no longer be aligned.
-    strb(card_table_base, card_table_addr);
-  } else {
-    mov(tmp, 0);
-    strb(tmp, card_table_addr);
-  }
-#endif // AARCH64
-}
-
 //////////////////////////////////////////////////////////////////////////////////
 
 
--- a/src/hotspot/cpu/arm/interp_masm_arm.hpp	Wed May 02 22:11:35 2018 -0700
+++ b/src/hotspot/cpu/arm/interp_masm_arm.hpp	Fri May 04 08:50:01 2018 -0700
@@ -144,11 +144,6 @@
   // load cpool->resolved_klass_at(index); Rtemp is corrupted upon return
   void load_resolved_klass_at_offset(Register Rcpool, Register Rindex, Register Rklass);
 
-  void store_check_part1(Register card_table_base);                // Sets card_table_base register.
-  void store_check_part2(Register obj, Register card_table_base, Register tmp);
-
-  void set_card(Register card_table_base, Address card_table_addr, Register tmp);
-
   void pop_ptr(Register r);
   void pop_i(Register r = R0_tos);
 #ifdef AARCH64
--- a/src/hotspot/cpu/arm/macroAssembler_arm.cpp	Wed May 02 22:11:35 2018 -0700
+++ b/src/hotspot/cpu/arm/macroAssembler_arm.cpp	Fri May 04 08:50:01 2018 -0700
@@ -31,6 +31,7 @@
 #include "compiler/disassembler.hpp"
 #include "gc/shared/barrierSet.hpp"
 #include "gc/shared/cardTable.hpp"
+#include "gc/shared/barrierSetAssembler.hpp"
 #include "gc/shared/cardTableBarrierSet.hpp"
 #include "gc/shared/collectedHeap.inline.hpp"
 #include "interpreter/interpreter.hpp"
@@ -44,12 +45,6 @@
 #include "runtime/sharedRuntime.hpp"
 #include "runtime/stubRoutines.hpp"
 #include "utilities/macros.hpp"
-#if INCLUDE_ALL_GCS
-#include "gc/g1/g1BarrierSet.hpp"
-#include "gc/g1/g1CardTable.hpp"
-#include "gc/g1/g1ThreadLocalData.hpp"
-#include "gc/g1/heapRegion.hpp"
-#endif
 
 // Implementation of AddressLiteral
 
@@ -2131,22 +2126,15 @@
   cbz(value, done);             // Use NULL as-is.
   STATIC_ASSERT(JNIHandles::weak_tag_mask == 1u);
   tbz(value, 0, not_weak);      // Test for jweak tag.
+
   // Resolve jweak.
-  ldr(value, Address(value, -JNIHandles::weak_tag_value));
-  verify_oop(value);
-#if INCLUDE_ALL_GCS
-  if (UseG1GC) {
-    g1_write_barrier_pre(noreg, // store_addr
-                         noreg, // new_val
-                         value, // pre_val
-                         tmp1,  // tmp1
-                         tmp2); // tmp2
-    }
-#endif // INCLUDE_ALL_GCS
+  access_load_at(T_OBJECT, IN_ROOT | ON_PHANTOM_OOP_REF,
+                 Address(value, -JNIHandles::weak_tag_value), value, tmp1, tmp2, noreg);
   b(done);
   bind(not_weak);
   // Resolve (untagged) jobject.
-  ldr(value, Address(value));
+  access_load_at(T_OBJECT, IN_ROOT | IN_CONCURRENT_ROOT,
+                 Address(value, 0), value, tmp1, tmp2, noreg);
   verify_oop(value);
   bind(done);
 }
@@ -2154,183 +2142,6 @@
 
 //////////////////////////////////////////////////////////////////////////////////
 
-#if INCLUDE_ALL_GCS
-
-// G1 pre-barrier.
-// Blows all volatile registers (R0-R3 on 32-bit ARM, R0-R18 on AArch64, Rtemp, LR).
-// If store_addr != noreg, then previous value is loaded from [store_addr];
-// in such case store_addr and new_val registers are preserved;
-// otherwise pre_val register is preserved.
-void MacroAssembler::g1_write_barrier_pre(Register store_addr,
-                                          Register new_val,
-                                          Register pre_val,
-                                          Register tmp1,
-                                          Register tmp2) {
-  Label done;
-  Label runtime;
-
-  if (store_addr != noreg) {
-    assert_different_registers(store_addr, new_val, pre_val, tmp1, tmp2, noreg);
-  } else {
-    assert (new_val == noreg, "should be");
-    assert_different_registers(pre_val, tmp1, tmp2, noreg);
-  }
-
-  Address in_progress(Rthread, in_bytes(G1ThreadLocalData::satb_mark_queue_active_offset()));
-  Address index(Rthread, in_bytes(G1ThreadLocalData::satb_mark_queue_index_offset()));
-  Address buffer(Rthread, in_bytes(G1ThreadLocalData::satb_mark_queue_buffer_offset()));
-
-  // Is marking active?
-  assert(in_bytes(SATBMarkQueue::byte_width_of_active()) == 1, "adjust this code");
-  ldrb(tmp1, in_progress);
-  cbz(tmp1, done);
-
-  // Do we need to load the previous value?
-  if (store_addr != noreg) {
-    load_heap_oop(pre_val, Address(store_addr, 0));
-  }
-
-  // Is the previous value null?
-  cbz(pre_val, done);
-
-  // Can we store original value in the thread's buffer?
-  // Is index == 0?
-  // (The index field is typed as size_t.)
-
-  ldr(tmp1, index);           // tmp1 := *index_adr
-  ldr(tmp2, buffer);
-
-  subs(tmp1, tmp1, wordSize); // tmp1 := tmp1 - wordSize
-  b(runtime, lt);             // If negative, goto runtime
-
-  str(tmp1, index);           // *index_adr := tmp1
-
-  // Record the previous value
-  str(pre_val, Address(tmp2, tmp1));
-  b(done);
-
-  bind(runtime);
-
-  // save the live input values
-#ifdef AARCH64
-  if (store_addr != noreg) {
-    raw_push(store_addr, new_val);
-  } else {
-    raw_push(pre_val, ZR);
-  }
-#else
-  if (store_addr != noreg) {
-    // avoid raw_push to support any ordering of store_addr and new_val
-    push(RegisterSet(store_addr) | RegisterSet(new_val));
-  } else {
-    push(pre_val);
-  }
-#endif // AARCH64
-
-  if (pre_val != R0) {
-    mov(R0, pre_val);
-  }
-  mov(R1, Rthread);
-
-  call_VM_leaf(CAST_FROM_FN_PTR(address, SharedRuntime::g1_wb_pre), R0, R1);
-
-#ifdef AARCH64
-  if (store_addr != noreg) {
-    raw_pop(store_addr, new_val);
-  } else {
-    raw_pop(pre_val, ZR);
-  }
-#else
-  if (store_addr != noreg) {
-    pop(RegisterSet(store_addr) | RegisterSet(new_val));
-  } else {
-    pop(pre_val);
-  }
-#endif // AARCH64
-
-  bind(done);
-}
-
-// G1 post-barrier.
-// Blows all volatile registers (R0-R3 on 32-bit ARM, R0-R18 on AArch64, Rtemp, LR).
-void MacroAssembler::g1_write_barrier_post(Register store_addr,
-                                           Register new_val,
-                                           Register tmp1,
-                                           Register tmp2,
-                                           Register tmp3) {
-
-  Address queue_index(Rthread, in_bytes(G1ThreadLocalData::dirty_card_queue_index_offset()));
-  Address buffer(Rthread, in_bytes(G1ThreadLocalData::dirty_card_queue_buffer_offset()));
-
-  BarrierSet* bs = BarrierSet::barrier_set();
-  CardTableBarrierSet* ctbs = barrier_set_cast<CardTableBarrierSet>(bs);
-  CardTable* ct = ctbs->card_table();
-  Label done;
-  Label runtime;
-
-  // Does store cross heap regions?
-
-  eor(tmp1, store_addr, new_val);
-#ifdef AARCH64
-  logical_shift_right(tmp1, tmp1, HeapRegion::LogOfHRGrainBytes);
-  cbz(tmp1, done);
-#else
-  movs(tmp1, AsmOperand(tmp1, lsr, HeapRegion::LogOfHRGrainBytes));
-  b(done, eq);
-#endif
-
-  // crosses regions, storing NULL?
-
-  cbz(new_val, done);
-
-  // storing region crossing non-NULL, is card already dirty?
-  const Register card_addr = tmp1;
-  assert(sizeof(*ct->byte_map_base()) == sizeof(jbyte), "adjust this code");
-
-  mov_address(tmp2, (address)ct->byte_map_base(), symbolic_Relocation::card_table_reference);
-  add(card_addr, tmp2, AsmOperand(store_addr, lsr, CardTable::card_shift));
-
-  ldrb(tmp2, Address(card_addr));
-  cmp(tmp2, (int)G1CardTable::g1_young_card_val());
-  b(done, eq);
-
-  membar(MacroAssembler::Membar_mask_bits(MacroAssembler::StoreLoad), tmp2);
-
-  assert(CardTable::dirty_card_val() == 0, "adjust this code");
-  ldrb(tmp2, Address(card_addr));
-  cbz(tmp2, done);
-
-  // storing a region crossing, non-NULL oop, card is clean.
-  // dirty card and log.
-
-  strb(zero_register(tmp2), Address(card_addr));
-
-  ldr(tmp2, queue_index);
-  ldr(tmp3, buffer);
-
-  subs(tmp2, tmp2, wordSize);
-  b(runtime, lt); // go to runtime if now negative
-
-  str(tmp2, queue_index);
-
-  str(card_addr, Address(tmp3, tmp2));
-  b(done);
-
-  bind(runtime);
-
-  if (card_addr != R0) {
-    mov(R0, card_addr);
-  }
-  mov(R1, Rthread);
-  call_VM_leaf(CAST_FROM_FN_PTR(address, SharedRuntime::g1_wb_post), R0, R1);
-
-  bind(done);
-}
-
-#endif // INCLUDE_ALL_GCS
-
-//////////////////////////////////////////////////////////////////////////////////
-
 #ifdef AARCH64
 
 void MacroAssembler::load_sized_value(Register dst, Address src, size_t size_in_bytes, bool is_signed) {
@@ -2873,38 +2684,39 @@
 #endif // AARCH64
 
 
-void MacroAssembler::load_heap_oop(Register dst, Address src) {
-#ifdef AARCH64
-  if (UseCompressedOops) {
-    ldr_w(dst, src);
-    decode_heap_oop(dst);
-    return;
+void MacroAssembler::load_heap_oop(Register dst, Address src, Register tmp1, Register tmp2, Register tmp3, DecoratorSet decorators) {
+  access_load_at(T_OBJECT, IN_HEAP | decorators, src, dst, tmp1, tmp2, tmp3);
+}
+
+// Blows src and flags.
+void MacroAssembler::store_heap_oop(Address obj, Register new_val, Register tmp1, Register tmp2, Register tmp3, DecoratorSet decorators) {
+  access_store_at(T_OBJECT, IN_HEAP | decorators, obj, new_val, tmp1, tmp2, tmp3, false);
+}
+
+void MacroAssembler::store_heap_oop_null(Address obj, Register new_val, Register tmp1, Register tmp2, Register tmp3, DecoratorSet decorators) {
+  access_store_at(T_OBJECT, IN_HEAP, obj, new_val, tmp1, tmp2, tmp3, true);
+}
+
+void MacroAssembler::access_load_at(BasicType type, DecoratorSet decorators,
+                                    Address src, Register dst, Register tmp1, Register tmp2, Register tmp3) {
+  BarrierSetAssembler* bs = BarrierSet::barrier_set()->barrier_set_assembler();
+  bool as_raw = (decorators & AS_RAW) != 0;
+  if (as_raw) {
+    bs->BarrierSetAssembler::load_at(this, decorators, type, dst, src, tmp1, tmp2, tmp3);
+  } else {
+    bs->load_at(this, decorators, type, dst, src, tmp1, tmp2, tmp3);
   }
-#endif // AARCH64
-  ldr(dst, src);
 }
 
-// Blows src and flags.
-void MacroAssembler::store_heap_oop(Register src, Address dst) {
-#ifdef AARCH64
-  if (UseCompressedOops) {
-    assert(!dst.uses(src), "not enough registers");
-    encode_heap_oop(src);
-    str_w(src, dst);
-    return;
+void MacroAssembler::access_store_at(BasicType type, DecoratorSet decorators,
+                                     Address obj, Register new_val, Register tmp1, Register tmp2, Register tmp3, bool is_null) {
+  BarrierSetAssembler* bs = BarrierSet::barrier_set()->barrier_set_assembler();
+  bool as_raw = (decorators & AS_RAW) != 0;
+  if (as_raw) {
+    bs->BarrierSetAssembler::store_at(this, decorators, type, obj, new_val, tmp1, tmp2, tmp3, is_null);
+  } else {
+    bs->store_at(this, decorators, type, obj, new_val, tmp1, tmp2, tmp3, is_null);
   }
-#endif // AARCH64
-  str(src, dst);
-}
-
-void MacroAssembler::store_heap_oop_null(Register src, Address dst) {
-#ifdef AARCH64
-  if (UseCompressedOops) {
-    str_w(src, dst);
-    return;
-  }
-#endif // AARCH64
-  str(src, dst);
 }
 
 
--- a/src/hotspot/cpu/arm/macroAssembler_arm.hpp	Wed May 02 22:11:35 2018 -0700
+++ b/src/hotspot/cpu/arm/macroAssembler_arm.hpp	Fri May 04 08:50:01 2018 -0700
@@ -401,27 +401,6 @@
 
   void resolve_jobject(Register value, Register tmp1, Register tmp2);
 
-#if INCLUDE_ALL_GCS
-  // G1 pre-barrier.
-  // Blows all volatile registers (R0-R3 on 32-bit ARM, R0-R18 on AArch64, Rtemp, LR).
-  // If store_addr != noreg, then previous value is loaded from [store_addr];
-  // in such case store_addr and new_val registers are preserved;
-  // otherwise pre_val register is preserved.
-  void g1_write_barrier_pre(Register store_addr,
-                            Register new_val,
-                            Register pre_val,
-                            Register tmp1,
-                            Register tmp2);
-
-  // G1 post-barrier.
-  // Blows all volatile registers (R0-R3 on 32-bit ARM, R0-R18 on AArch64, Rtemp, LR).
-  void g1_write_barrier_post(Register store_addr,
-                             Register new_val,
-                             Register tmp1,
-                             Register tmp2,
-                             Register tmp3);
-#endif // INCLUDE_ALL_GCS
-
 #ifndef AARCH64
   void nop() {
     mov(R0, R0);
@@ -1072,12 +1051,12 @@
 
     // oop manipulations
 
-  void load_heap_oop(Register dst, Address src);
-  void store_heap_oop(Register src, Address dst);
-  void store_heap_oop(Address dst, Register src) {
-    store_heap_oop(src, dst);
-  }
-  void store_heap_oop_null(Register src, Address dst);
+  void load_heap_oop(Register dst, Address src, Register tmp1 = noreg, Register tmp2 = noreg, Register tmp3 = noreg, DecoratorSet decorators = 0);
+  void store_heap_oop(Address obj, Register new_val, Register tmp1 = noreg, Register tmp2 = noreg, Register tmp3 = noreg, DecoratorSet decorators = 0);
+  void store_heap_oop_null(Address obj, Register new_val, Register tmp1 = noreg, Register tmp2 = noreg, Register tmp3 = noreg, DecoratorSet decorators = 0);
+
+  void access_load_at(BasicType type, DecoratorSet decorators, Address src, Register dst, Register tmp1, Register tmp2, Register tmp3);
+  void access_store_at(BasicType type, DecoratorSet decorators, Address obj, Register new_val, Register tmp1, Register tmp2, Register tmp3, bool is_null);
 
 #ifdef AARCH64
   void encode_heap_oop(Register dst, Register src);
--- a/src/hotspot/cpu/arm/stubGenerator_arm.cpp	Wed May 02 22:11:35 2018 -0700
+++ b/src/hotspot/cpu/arm/stubGenerator_arm.cpp	Fri May 04 08:50:01 2018 -0700
@@ -3260,7 +3260,7 @@
     __ align(OptoLoopAlignment);
     __ BIND(store_element);
     if (UseCompressedOops) {
-      __ store_heap_oop(R5, Address(to, BytesPerHeapOop, post_indexed));  // store the oop, changes flags
+      __ store_heap_oop(Address(to, BytesPerHeapOop, post_indexed), R5);  // store the oop, changes flags
       __ subs_32(count,count,1);
     } else {
       __ subs_32(count,count,1);
--- a/src/hotspot/cpu/arm/templateInterpreterGenerator_arm.cpp	Wed May 02 22:11:35 2018 -0700
+++ b/src/hotspot/cpu/arm/templateInterpreterGenerator_arm.cpp	Fri May 04 08:50:01 2018 -0700
@@ -852,80 +852,53 @@
 //
 
 address TemplateInterpreterGenerator::generate_Reference_get_entry(void) {
-#if INCLUDE_ALL_GCS
-  if (UseG1GC) {
-    // Code: _aload_0, _getfield, _areturn
-    // parameter size = 1
-    //
-    // The code that gets generated by this routine is split into 2 parts:
-    //    1. The "intrinsified" code for G1 (or any SATB based GC),
-    //    2. The slow path - which is an expansion of the regular method entry.
-    //
-    // Notes:-
-    // * In the G1 code we do not check whether we need to block for
-    //   a safepoint. If G1 is enabled then we must execute the specialized
-    //   code for Reference.get (except when the Reference object is null)
-    //   so that we can log the value in the referent field with an SATB
-    //   update buffer.
-    //   If the code for the getfield template is modified so that the
-    //   G1 pre-barrier code is executed when the current method is
-    //   Reference.get() then going through the normal method entry
-    //   will be fine.
-    // * The G1 code can, however, check the receiver object (the instance
-    //   of java.lang.Reference) and jump to the slow path if null. If the
-    //   Reference object is null then we obviously cannot fetch the referent
-    //   and so we don't need to call the G1 pre-barrier. Thus we can use the
-    //   regular method entry code to generate the NPE.
-    //
-    // This code is based on generate_accessor_enty.
-    //
-    // Rmethod: Method*
-    // Rthread: thread
-    // Rsender_sp: sender sp, must be preserved for slow path, set SP to it on fast path
-    // Rparams: parameters
+  // Code: _aload_0, _getfield, _areturn
+  // parameter size = 1
+  //
+  // The code that gets generated by this routine is split into 2 parts:
+  //    1. The "intrinsified" code performing an ON_WEAK_OOP_REF load,
+  //    2. The slow path - which is an expansion of the regular method entry.
+  //
+  // Notes:-
+  // * An intrinsic is always executed, where an ON_WEAK_OOP_REF load is performed.
+  // * We may jump to the slow path iff the receiver is null. If the
+  //   Reference object is null then we no longer perform an ON_WEAK_OOP_REF load
+  //   Thus we can use the regular method entry code to generate the NPE.
+  //
+  // Rmethod: Method*
+  // Rthread: thread
+  // Rsender_sp: sender sp, must be preserved for slow path, set SP to it on fast path
+  // Rparams: parameters
 
-    address entry = __ pc();
-    Label slow_path;
-    const Register Rthis = R0;
-    const Register Rret_addr = Rtmp_save1;
-    assert_different_registers(Rthis, Rret_addr, Rsender_sp);
+  address entry = __ pc();
+  Label slow_path;
+  const Register Rthis = R0;
+  const Register Rret_addr = Rtmp_save1;
+  assert_different_registers(Rthis, Rret_addr, Rsender_sp);
 
-    const int referent_offset = java_lang_ref_Reference::referent_offset;
-    guarantee(referent_offset > 0, "referent offset not initialized");
+  const int referent_offset = java_lang_ref_Reference::referent_offset;
+  guarantee(referent_offset > 0, "referent offset not initialized");
 
-    // Check if local 0 != NULL
-    // If the receiver is null then it is OK to jump to the slow path.
-    __ ldr(Rthis, Address(Rparams));
-    __ cbz(Rthis, slow_path);
+  // Check if local 0 != NULL
+  // If the receiver is null then it is OK to jump to the slow path.
+  __ ldr(Rthis, Address(Rparams));
+  __ cbz(Rthis, slow_path);
 
-    // Generate the G1 pre-barrier code to log the value of
-    // the referent field in an SATB buffer.
+  // Preserve LR
+  __ mov(Rret_addr, LR);
 
-    // Load the value of the referent field.
-    __ load_heap_oop(R0, Address(Rthis, referent_offset));
+  // Load the value of the referent field.
+  const Address field_address(Rthis, referent_offset);
+  __ load_heap_oop(R0, field_address, Rtemp, R1_tmp, R2_tmp, ON_WEAK_OOP_REF);
 
-    // Preserve LR
-    __ mov(Rret_addr, LR);
+  // _areturn
+  __ mov(SP, Rsender_sp);
+  __ ret(Rret_addr);
 
-    __ g1_write_barrier_pre(noreg,   // store_addr
-                            noreg,   // new_val
-                            R0,      // pre_val
-                            Rtemp,   // tmp1
-                            R1_tmp); // tmp2
-
-    // _areturn
-    __ mov(SP, Rsender_sp);
-    __ ret(Rret_addr);
-
-    // generate a vanilla interpreter entry as the slow path
-    __ bind(slow_path);
-    __ jump_to_entry(Interpreter::entry_for_kind(Interpreter::zerolocals));
-    return entry;
-  }
-#endif // INCLUDE_ALL_GCS
-
-  // If G1 is not enabled then attempt to go through the normal entry point
-  return NULL;
+  // generate a vanilla interpreter entry as the slow path
+  __ bind(slow_path);
+  __ jump_to_entry(Interpreter::entry_for_kind(Interpreter::zerolocals));
+  return entry;
 }
 
 // Not supported
--- a/src/hotspot/cpu/arm/templateTable_arm.cpp	Wed May 02 22:11:35 2018 -0700
+++ b/src/hotspot/cpu/arm/templateTable_arm.cpp	Fri May 04 08:50:01 2018 -0700
@@ -24,6 +24,7 @@
 
 #include "precompiled.hpp"
 #include "asm/macroAssembler.hpp"
+#include "gc/shared/barrierSetAssembler.hpp"
 #include "interpreter/interp_masm.hpp"
 #include "interpreter/interpreter.hpp"
 #include "interpreter/interpreterRuntime.hpp"
@@ -187,72 +188,24 @@
                          Register tmp1,
                          Register tmp2,
                          Register tmp3,
-                         BarrierSet::Name barrier,
-                         bool precise,
-                         bool is_null) {
+                         bool is_null,
+                         DecoratorSet decorators = 0) {
 
   assert_different_registers(obj.base(), new_val, tmp1, tmp2, tmp3, noreg);
-  switch (barrier) {
-#if INCLUDE_ALL_GCS
-    case BarrierSet::G1BarrierSet:
-      {
-        // flatten object address if needed
-        assert (obj.mode() == basic_offset, "pre- or post-indexing is not supported here");
-
-        const Register store_addr = obj.base();
-        if (obj.index() != noreg) {
-          assert (obj.disp() == 0, "index or displacement, not both");
-#ifdef AARCH64
-          __ add(store_addr, obj.base(), obj.index(), obj.extend(), obj.shift_imm());
-#else
-          assert(obj.offset_op() == add_offset, "addition is expected");
-          __ add(store_addr, obj.base(), AsmOperand(obj.index(), obj.shift(), obj.shift_imm()));
-#endif // AARCH64
-        } else if (obj.disp() != 0) {
-          __ add(store_addr, obj.base(), obj.disp());
-        }
-
-        __ g1_write_barrier_pre(store_addr, new_val, tmp1, tmp2, tmp3);
-        if (is_null) {
-          __ store_heap_oop_null(new_val, Address(store_addr));
-        } else {
-          // G1 barrier needs uncompressed oop for region cross check.
-          Register val_to_store = new_val;
-          if (UseCompressedOops) {
-            val_to_store = tmp1;
-            __ mov(val_to_store, new_val);
-          }
-          __ store_heap_oop(val_to_store, Address(store_addr)); // blows val_to_store:
-          val_to_store = noreg;
-          __ g1_write_barrier_post(store_addr, new_val, tmp1, tmp2, tmp3);
-        }
-      }
-      break;
-#endif // INCLUDE_ALL_GCS
-    case BarrierSet::CardTableBarrierSet:
-      {
-        if (is_null) {
-          __ store_heap_oop_null(new_val, obj);
-        } else {
-          assert (!precise || (obj.index() == noreg && obj.disp() == 0),
-                  "store check address should be calculated beforehand");
-
-          __ store_check_part1(tmp1);
-          __ store_heap_oop(new_val, obj); // blows new_val:
-          new_val = noreg;
-          __ store_check_part2(obj.base(), tmp1, tmp2);
-        }
-      }
-      break;
-    case BarrierSet::ModRef:
-      ShouldNotReachHere();
-      break;
-    default:
-      ShouldNotReachHere();
-      break;
+  if (is_null) {
+    __ store_heap_oop_null(obj, new_val, tmp1, tmp2, tmp3, decorators);
+  } else {
+    __ store_heap_oop(obj, new_val, tmp1, tmp2, tmp3, decorators);
   }
 }
 
+static void do_oop_load(InterpreterMacroAssembler* _masm,
+                        Register dst,
+                        Address obj,
+                        DecoratorSet decorators = 0) {
+  __ load_heap_oop(dst, obj, noreg, noreg, noreg, decorators);
+}
+
 Address TemplateTable::at_bcp(int offset) {
   assert(_desc->uses_bcp(), "inconsistent uses_bcp information");
   return Address(Rbcp, offset);
@@ -863,7 +816,7 @@
   const Register Rindex = R0_tos;
 
   index_check(Rarray, Rindex);
-  __ load_heap_oop(R0_tos, get_array_elem_addr(T_OBJECT, Rarray, Rindex, Rtemp));
+  do_oop_load(_masm, R0_tos, get_array_elem_addr(T_OBJECT, Rarray, Rindex, Rtemp), IN_HEAP_ARRAY);
 }
 
 
@@ -1248,7 +1201,7 @@
   __ add(Raddr_1, Raddr_1, AsmOperand(Rindex_4, lsl, LogBytesPerHeapOop));
 
   // Now store using the appropriate barrier
-  do_oop_store(_masm, Raddr_1, Rvalue_2, Rtemp, R0_tmp, R3_tmp, _bs->kind(), true, false);
+  do_oop_store(_masm, Raddr_1, Rvalue_2, Rtemp, R0_tmp, R3_tmp, false, IN_HEAP_ARRAY);
   __ b(done);
 
   __ bind(throw_array_store);
@@ -1264,7 +1217,7 @@
   __ profile_null_seen(R0_tmp);
 
   // Store a NULL
-  do_oop_store(_masm, Address::indexed_oop(Raddr_1, Rindex_4), Rvalue_2, Rtemp, R0_tmp, R3_tmp, _bs->kind(), true, true);
+  do_oop_store(_masm, Address::indexed_oop(Raddr_1, Rindex_4), Rvalue_2, Rtemp, R0_tmp, R3_tmp, true, IN_HEAP_ARRAY);
 
   // Pop stack arguments
   __ bind(done);
@@ -3286,7 +3239,7 @@
     // atos case for AArch64 and slow version on 32-bit ARM
     if(!atos_merged_with_itos) {
       __ bind(Latos);
-      __ load_heap_oop(R0_tos, Address(Robj, Roffset));
+      do_oop_load(_masm, R0_tos, Address(Robj, Roffset));
       __ push(atos);
       // Rewrite bytecode to be faster
       if (!is_static && rc == may_rewrite) {
@@ -3638,7 +3591,7 @@
     __ pop(atos);
     if (!is_static) pop_and_check_object(Robj);
     // Store into the field
-    do_oop_store(_masm, Address(Robj, Roffset), R0_tos, Rtemp, R1_tmp, R5_tmp, _bs->kind(), false, false);
+    do_oop_store(_masm, Address(Robj, Roffset), R0_tos, Rtemp, R1_tmp, R5_tmp, false);
     if (!is_static && rc == may_rewrite) {
       patch_bytecode(Bytecodes::_fast_aputfield, R0_tmp, Rtemp, true, byte_no);
     }
@@ -3816,7 +3769,7 @@
 #endif // AARCH64
 
     case Bytecodes::_fast_aputfield:
-      do_oop_store(_masm, Address(Robj, Roffset), R0_tos, Rtemp, R1_tmp, R2_tmp, _bs->kind(), false, false);
+      do_oop_store(_masm, Address(Robj, Roffset), R0_tos, Rtemp, R1_tmp, R2_tmp, false);
       break;
 
     default:
@@ -3912,7 +3865,7 @@
     case Bytecodes::_fast_dgetfield: __ add(Roffset, Robj, Roffset); __ fldd(D0_tos, Address(Roffset)); break;
 #endif // __SOFTFP__
 #endif // AARCH64
-    case Bytecodes::_fast_agetfield: __ load_heap_oop(R0_tos, Address(Robj, Roffset)); __ verify_oop(R0_tos); break;
+    case Bytecodes::_fast_agetfield: do_oop_load(_masm, R0_tos, Address(Robj, Roffset)); __ verify_oop(R0_tos); break;
     default:
       ShouldNotReachHere();
   }
@@ -3992,7 +3945,7 @@
   if (state == itos) {
     __ ldr_s32(R0_tos, Address(Robj, Roffset));
   } else if (state == atos) {
-    __ load_heap_oop(R0_tos, Address(Robj, Roffset));
+    do_oop_load(_masm, R0_tos, Address(Robj, Roffset));
     __ verify_oop(R0_tos);
   } else if (state == ftos) {
 #ifdef AARCH64
--- a/src/hotspot/cpu/ppc/assembler_ppc.cpp	Wed May 02 22:11:35 2018 -0700
+++ b/src/hotspot/cpu/ppc/assembler_ppc.cpp	Fri May 04 08:50:01 2018 -0700
@@ -37,10 +37,6 @@
 #include "runtime/sharedRuntime.hpp"
 #include "runtime/stubRoutines.hpp"
 #include "utilities/macros.hpp"
-#if INCLUDE_ALL_GCS
-#include "gc/g1/g1BarrierSet.hpp"
-#include "gc/g1/heapRegion.hpp"
-#endif // INCLUDE_ALL_GCS
 
 #ifdef PRODUCT
 #define BLOCK_COMMENT(str) // nothing
--- a/src/hotspot/cpu/s390/assembler_s390.cpp	Wed May 02 22:11:35 2018 -0700
+++ b/src/hotspot/cpu/s390/assembler_s390.cpp	Fri May 04 08:50:01 2018 -0700
@@ -38,10 +38,6 @@
 #include "runtime/sharedRuntime.hpp"
 #include "runtime/stubRoutines.hpp"
 #include "utilities/macros.hpp"
-#if INCLUDE_ALL_GCS
-#include "gc/g1/g1BarrierSet.hpp"
-#include "gc/g1/heapRegion.hpp"
-#endif
 
 // Convention: Use Z_R0 and Z_R1 instead of Z_scratch_* in all
 // assembler_s390.* files.
--- a/src/hotspot/cpu/x86/assembler_x86.cpp	Wed May 02 22:11:35 2018 -0700
+++ b/src/hotspot/cpu/x86/assembler_x86.cpp	Fri May 04 08:50:01 2018 -0700
@@ -36,10 +36,6 @@
 #include "runtime/sharedRuntime.hpp"
 #include "runtime/stubRoutines.hpp"
 #include "utilities/macros.hpp"
-#if INCLUDE_ALL_GCS
-#include "gc/g1/g1BarrierSet.hpp"
-#include "gc/g1/heapRegion.hpp"
-#endif // INCLUDE_ALL_GCS
 
 #ifdef PRODUCT
 #define BLOCK_COMMENT(str) /* nothing */
--- a/src/hotspot/cpu/zero/assembler_zero.cpp	Wed May 02 22:11:35 2018 -0700
+++ b/src/hotspot/cpu/zero/assembler_zero.cpp	Fri May 04 08:50:01 2018 -0700
@@ -37,10 +37,6 @@
 #include "runtime/sharedRuntime.hpp"
 #include "runtime/stubRoutines.hpp"
 #include "utilities/macros.hpp"
-#if INCLUDE_ALL_GCS
-#include "gc/g1/g1BarrierSet.hpp"
-#include "gc/g1/heapRegion.hpp"
-#endif // INCLUDE_ALL_GCS
 
 int AbstractAssembler::code_fill_byte() {
   return 0;
--- a/src/hotspot/cpu/zero/cppInterpreterGenerator_zero.cpp	Wed May 02 22:11:35 2018 -0700
+++ b/src/hotspot/cpu/zero/cppInterpreterGenerator_zero.cpp	Fri May 04 08:50:01 2018 -0700
@@ -65,7 +65,7 @@
 }
 
 address CppInterpreterGenerator::generate_Reference_get_entry(void) {
-#if INCLUDE_ALL_GCS
+#if INCLUDE_G1GC
   if (UseG1GC) {
     // We need to generate have a routine that generates code to:
     //   * load the value in the referent field
@@ -77,7 +77,7 @@
     // field as live.
     Unimplemented();
   }
-#endif // INCLUDE_ALL_GCS
+#endif // INCLUDE_G1GC
 
   // If G1 is not enabled then attempt to go through the normal entry point
   // Reference.get could be instrumented by jvmti
--- a/src/hotspot/os/linux/os_linux.cpp	Wed May 02 22:11:35 2018 -0700
+++ b/src/hotspot/os/linux/os_linux.cpp	Fri May 04 08:50:01 2018 -0700
@@ -3111,6 +3111,68 @@
   return nbot;
 }
 
+bool os::committed_in_range(address start, size_t size, address& committed_start, size_t& committed_size) {
+  int mincore_return_value;
+  const size_t stripe = 1024;  // query this many pages each time
+  unsigned char vec[stripe];
+  const size_t page_sz = os::vm_page_size();
+  size_t pages = size / page_sz;
+
+  assert(is_aligned(start, page_sz), "Start address must be page aligned");
+  assert(is_aligned(size, page_sz), "Size must be page aligned");
+
+  committed_start = NULL;
+
+  int loops = (pages + stripe - 1) / stripe;
+  int committed_pages = 0;
+  address loop_base = start;
+  for (int index = 0; index < loops; index ++) {
+    assert(pages > 0, "Nothing to do");
+    int pages_to_query = (pages >= stripe) ? stripe : pages;
+    pages -= pages_to_query;
+
+    // Get stable read
+    while ((mincore_return_value = mincore(loop_base, pages_to_query * page_sz, vec)) == -1 && errno == EAGAIN);
+
+    // During shutdown, some memory goes away without properly notifying NMT,
+    // E.g. ConcurrentGCThread/WatcherThread can exit without deleting thread object.
+    // Bailout and return as not committed for now.
+    if (mincore_return_value == -1 && errno == ENOMEM) {
+      return false;
+    }
+
+    assert(mincore_return_value == 0, "Range must be valid");
+    // Process this stripe
+    for (int vecIdx = 0; vecIdx < pages_to_query; vecIdx ++) {
+      if ((vec[vecIdx] & 0x01) == 0) { // not committed
+        // End of current contiguous region
+        if (committed_start != NULL) {
+          break;
+        }
+      } else { // committed
+        // Start of region
+        if (committed_start == NULL) {
+          committed_start = loop_base + page_sz * vecIdx;
+        }
+        committed_pages ++;
+      }
+    }
+
+    loop_base += pages_to_query * page_sz;
+  }
+
+  if (committed_start != NULL) {
+    assert(committed_pages > 0, "Must have committed region");
+    assert(committed_pages <= int(size / page_sz), "Can not commit more than it has");
+    assert(committed_start >= start && committed_start < start + size, "Out of range");
+    committed_size = page_sz * committed_pages;
+    return true;
+  } else {
+    assert(committed_pages == 0, "Should not have committed region");
+    return false;
+  }
+}
+
 
 // Linux uses a growable mapping for the stack, and if the mapping for
 // the stack guard pages is not removed when we detach a thread the
--- a/src/hotspot/os/linux/os_linux.inline.hpp	Wed May 02 22:11:35 2018 -0700
+++ b/src/hotspot/os/linux/os_linux.inline.hpp	Fri May 04 08:50:01 2018 -0700
@@ -98,26 +98,8 @@
 
 inline struct dirent* os::readdir(DIR* dirp, dirent *dbuf)
 {
-// readdir_r has been deprecated since glibc 2.24.
-// See https://sourceware.org/bugzilla/show_bug.cgi?id=19056 for more details.
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
-
-  dirent* p;
-  int status;
   assert(dirp != NULL, "just checking");
-
-  // NOTE: Linux readdir_r (on RH 6.2 and 7.2 at least) is NOT like the POSIX
-  // version. Here is the doc for this function:
-  // http://www.gnu.org/manual/glibc-2.2.3/html_node/libc_262.html
-
-  if((status = ::readdir_r(dirp, dbuf, &p)) != 0) {
-    errno = status;
-    return NULL;
-  } else
-    return p;
-
-#pragma GCC diagnostic pop
+  return ::readdir(dirp);
 }
 
 inline int os::closedir(DIR *dirp) {
--- a/src/hotspot/os/windows/attachListener_windows.cpp	Wed May 02 22:11:35 2018 -0700
+++ b/src/hotspot/os/windows/attachListener_windows.cpp	Fri May 04 08:50:01 2018 -0700
@@ -23,6 +23,7 @@
  */
 
 #include "precompiled.hpp"
+#include "logging/log.hpp"
 #include "runtime/interfaceSupport.inline.hpp"
 #include "runtime/os.hpp"
 #include "services/attachListener.hpp"
--- a/src/hotspot/os/windows/os_windows.cpp	Wed May 02 22:11:35 2018 -0700
+++ b/src/hotspot/os/windows/os_windows.cpp	Fri May 04 08:50:01 2018 -0700
@@ -365,6 +365,39 @@
   return sz;
 }
 
+bool os::committed_in_range(address start, size_t size, address& committed_start, size_t& committed_size) {
+  MEMORY_BASIC_INFORMATION minfo;
+  committed_start = NULL;
+  committed_size = 0;
+  address top = start + size;
+  const address start_addr = start;
+  while (start < top) {
+    VirtualQuery(start, &minfo, sizeof(minfo));
+    if ((minfo.State & MEM_COMMIT) == 0) {  // not committed
+      if (committed_start != NULL) {
+        break;
+      }
+    } else {  // committed
+      if (committed_start == NULL) {
+        committed_start = start;
+      }
+      size_t offset = start - (address)minfo.BaseAddress;
+      committed_size += minfo.RegionSize - offset;
+    }
+    start = (address)minfo.BaseAddress + minfo.RegionSize;
+  }
+
+  if (committed_start == NULL) {
+    assert(committed_size == 0, "Sanity");
+    return false;
+  } else {
+    assert(committed_start >= start_addr && committed_start < top, "Out of range");
+    // current region may go beyond the limit, trim to the limit
+    committed_size = MIN2(committed_size, size_t(top - committed_start));
+    return true;
+  }
+}
+
 struct tm* os::localtime_pd(const time_t* clock, struct tm* res) {
   const struct tm* time_struct_ptr = localtime(clock);
   if (time_struct_ptr != NULL) {
--- a/src/hotspot/share/aot/aotCodeHeap.cpp	Wed May 02 22:11:35 2018 -0700
+++ b/src/hotspot/share/aot/aotCodeHeap.cpp	Fri May 04 08:50:01 2018 -0700
@@ -421,9 +421,11 @@
     SET_AOT_GLOBAL_SYMBOL_VALUE("_aot_jvmci_runtime_new_multi_array", address, JVMCIRuntime::new_multi_array);
     SET_AOT_GLOBAL_SYMBOL_VALUE("_aot_jvmci_runtime_dynamic_new_array", address, JVMCIRuntime::dynamic_new_array);
     SET_AOT_GLOBAL_SYMBOL_VALUE("_aot_jvmci_runtime_validate_object", address, JVMCIRuntime::validate_object);
+#if INCLUDE_G1GC
     SET_AOT_GLOBAL_SYMBOL_VALUE("_aot_jvmci_runtime_write_barrier_pre", address, JVMCIRuntime::write_barrier_pre);
+    SET_AOT_GLOBAL_SYMBOL_VALUE("_aot_jvmci_runtime_write_barrier_post", address, JVMCIRuntime::write_barrier_post);
+#endif
     SET_AOT_GLOBAL_SYMBOL_VALUE("_aot_jvmci_runtime_identity_hash_code", address, JVMCIRuntime::identity_hash_code);
-    SET_AOT_GLOBAL_SYMBOL_VALUE("_aot_jvmci_runtime_write_barrier_post", address, JVMCIRuntime::write_barrier_post);
     SET_AOT_GLOBAL_SYMBOL_VALUE("_aot_jvmci_runtime_dynamic_new_instance", address, JVMCIRuntime::dynamic_new_instance);
     SET_AOT_GLOBAL_SYMBOL_VALUE("_aot_jvmci_runtime_thread_is_interrupted", address, JVMCIRuntime::thread_is_interrupted);
     SET_AOT_GLOBAL_SYMBOL_VALUE("_aot_jvmci_runtime_exception_handler_for_pc", address, JVMCIRuntime::exception_handler_for_pc);
@@ -552,7 +554,9 @@
     SET_AOT_GLOBAL_SYMBOL_VALUE("_aot_polling_page", address, os::get_polling_page());
     SET_AOT_GLOBAL_SYMBOL_VALUE("_aot_narrow_klass_base_address", address, Universe::narrow_klass_base());
     SET_AOT_GLOBAL_SYMBOL_VALUE("_aot_narrow_oop_base_address", address, Universe::narrow_oop_base());
+#if INCLUDE_G1GC
     SET_AOT_GLOBAL_SYMBOL_VALUE("_aot_log_of_heap_region_grain_bytes", int, HeapRegion::LogOfHRGrainBytes);
+#endif
     SET_AOT_GLOBAL_SYMBOL_VALUE("_aot_inline_contiguous_allocation_supported", bool, heap->supports_inline_contig_alloc());
     link_shared_runtime_symbols();
     link_stub_routines_symbols();
--- a/src/hotspot/share/classfile/classFileParser.cpp	Wed May 02 22:11:35 2018 -0700
+++ b/src/hotspot/share/classfile/classFileParser.cpp	Fri May 04 08:50:01 2018 -0700
@@ -3592,8 +3592,13 @@
   this_klass->set_methods(_methods);
   this_klass->set_inner_classes(_inner_classes);
   this_klass->set_local_interfaces(_local_interfaces);
-  this_klass->set_transitive_interfaces(_transitive_interfaces);
   this_klass->set_annotations(_combined_annotations);
+  // Delay the setting of _transitive_interfaces until after initialize_supers() in
+  // fill_instance_klass(). It is because the _transitive_interfaces may be shared with
+  // its _super. If an OOM occurs while loading the current klass, its _super field
+  // may not have been set. When GC tries to free the klass, the _transitive_interfaces
+  // may be deallocated mistakenly in InstanceKlass::deallocate_interfaces(). Subsequent
+  // dereferences to the deallocated _transitive_interfaces will result in a crash.
 
   // Clear out these fields so they don't get deallocated by the destructor
   clear_class_metadata();
@@ -5462,7 +5467,6 @@
   assert(NULL == _methods, "invariant");
   assert(NULL == _inner_classes, "invariant");
   assert(NULL == _local_interfaces, "invariant");
-  assert(NULL == _transitive_interfaces, "invariant");
   assert(NULL == _combined_annotations, "invariant");
 
   if (_has_final_method) {
@@ -5529,7 +5533,9 @@
   }
 
   // Fill in information needed to compute superclasses.
-  ik->initialize_supers(const_cast<InstanceKlass*>(_super_klass), CHECK);
+  ik->initialize_supers(const_cast<InstanceKlass*>(_super_klass), _transitive_interfaces, CHECK);
+  ik->set_transitive_interfaces(_transitive_interfaces);
+  _transitive_interfaces = NULL;
 
   // Initialize itable offset tables
   klassItable::setup_itable_offset_table(ik);
@@ -5834,7 +5840,6 @@
   _methods = NULL;
   _inner_classes = NULL;
   _local_interfaces = NULL;
-  _transitive_interfaces = NULL;
   _combined_annotations = NULL;
   _annotations = _type_annotations = NULL;
   _fields_annotations = _fields_type_annotations = NULL;
@@ -5886,6 +5891,7 @@
   }
 
   clear_class_metadata();
+  _transitive_interfaces = NULL;
 
   // deallocate the klass if already created.  Don't directly deallocate, but add
   // to the deallocate list so that the klass is removed from the CLD::_klasses list
--- a/src/hotspot/share/classfile/classLoader.cpp	Wed May 02 22:11:35 2018 -0700
+++ b/src/hotspot/share/classfile/classLoader.cpp	Fri May 04 08:50:01 2018 -0700
@@ -37,8 +37,6 @@
 #include "classfile/systemDictionary.hpp"
 #include "classfile/vmSymbols.hpp"
 #include "compiler/compileBroker.hpp"
-#include "gc/shared/collectedHeap.inline.hpp"
-#include "gc/shared/generation.hpp"
 #include "interpreter/bytecodeStream.hpp"
 #include "interpreter/oopMapCache.hpp"
 #include "logging/log.hpp"
--- a/src/hotspot/share/classfile/stringTable.cpp	Wed May 02 22:11:35 2018 -0700
+++ b/src/hotspot/share/classfile/stringTable.cpp	Fri May 04 08:50:01 2018 -0700
@@ -44,7 +44,7 @@
 #include "services/diagnosticCommand.hpp"
 #include "utilities/hashtable.inline.hpp"
 #include "utilities/macros.hpp"
-#if INCLUDE_ALL_GCS
+#if INCLUDE_G1GC
 #include "gc/g1/g1StringDedup.hpp"
 #endif
 
@@ -260,7 +260,7 @@
     string = java_lang_String::create_from_unicode(name, len, CHECK_NULL);
   }
 
-#if INCLUDE_ALL_GCS
+#if INCLUDE_G1GC
   if (G1StringDedup::is_enabled()) {
     // Deduplicate the string before it is interned. Note that we should never
     // deduplicate a string after it has been interned. Doing so will counteract
--- a/src/hotspot/share/classfile/symbolTable.cpp	Wed May 02 22:11:35 2018 -0700
+++ b/src/hotspot/share/classfile/symbolTable.cpp	Fri May 04 08:50:01 2018 -0700
@@ -29,7 +29,6 @@
 #include "classfile/symbolTable.hpp"
 #include "classfile/systemDictionary.hpp"
 #include "gc/shared/collectedHeap.inline.hpp"
-#include "gc/shared/gcLocker.hpp"
 #include "memory/allocation.inline.hpp"
 #include "memory/filemap.hpp"
 #include "memory/metaspaceClosure.hpp"
--- a/src/hotspot/share/code/compiledMethod.cpp	Wed May 02 22:11:35 2018 -0700
+++ b/src/hotspot/share/code/compiledMethod.cpp	Fri May 04 08:50:01 2018 -0700
@@ -389,22 +389,24 @@
 
 void CompiledMethod::clean_ic_if_metadata_is_dead(CompiledIC *ic) {
   if (ic->is_icholder_call()) {
-    // The only exception is compiledICHolder oops which may
+    // The only exception is compiledICHolder metdata which may
     // yet be marked below. (We check this further below).
-    CompiledICHolder* cichk_oop = ic->cached_icholder();
+    CompiledICHolder* cichk_metdata = ic->cached_icholder();
 
-    if (cichk_oop->is_loader_alive()) {
+    if (cichk_metdata->is_loader_alive()) {
       return;
     }
   } else {
-    Metadata* ic_oop = ic->cached_metadata();
-    if (ic_oop != NULL) {
-      if (ic_oop->is_klass()) {
-        if (((Klass*)ic_oop)->is_loader_alive()) {
+    Metadata* ic_metdata = ic->cached_metadata();
+    if (ic_metdata != NULL) {
+      if (ic_metdata->is_klass()) {
+        if (((Klass*)ic_metdata)->is_loader_alive()) {
           return;
         }
-      } else if (ic_oop->is_method()) {
-        if (((Method*)ic_oop)->method_holder()->is_loader_alive()) {
+      } else if (ic_metdata->is_method()) {
+        Method* method = (Method*)ic_metdata;
+        assert(!method->is_old(), "old method should have been cleaned");
+        if (method->method_holder()->is_loader_alive()) {
           return;
         }
       } else {
@@ -493,16 +495,6 @@
     // (See comment above.)
   }
 
-  // The RedefineClasses() API can cause the class unloading invariant
-  // to no longer be true. See jvmtiExport.hpp for details.
-  // Also, leave a debugging breadcrumb in local flag.
-  if (JvmtiExport::has_redefined_a_class()) {
-    // This set of the unloading_occurred flag is done before the
-    // call to post_compiled_method_unload() so that the unloading
-    // of this nmethod is reported.
-    unloading_occurred = true;
-  }
-
   // Exception cache
   clean_exception_cache();
 
@@ -581,16 +573,6 @@
     // (See comment above.)
   }
 
-  // The RedefineClasses() API can cause the class unloading invariant
-  // to no longer be true. See jvmtiExport.hpp for details.
-  // Also, leave a debugging breadcrumb in local flag.
-  if (JvmtiExport::has_redefined_a_class()) {
-    // This set of the unloading_occurred flag is done before the
-    // call to post_compiled_method_unload() so that the unloading
-    // of this nmethod is reported.
-    unloading_occurred = true;
-  }
-
   // Exception cache
   clean_exception_cache();
 
--- a/src/hotspot/share/compiler/abstractCompiler.cpp	Wed May 02 22:11:35 2018 -0700
+++ b/src/hotspot/share/compiler/abstractCompiler.cpp	Fri May 04 08:50:01 2018 -0700
@@ -21,7 +21,6 @@
 // questions.
 //
 
-
 #include "precompiled.hpp"
 #include "compiler/abstractCompiler.hpp"
 #include "compiler/compileBroker.hpp"
--- a/src/hotspot/share/compiler/oopMap.cpp	Wed May 02 22:11:35 2018 -0700
+++ b/src/hotspot/share/compiler/oopMap.cpp	Fri May 04 08:50:01 2018 -0700
@@ -266,9 +266,9 @@
 }
 
 static void add_derived_oop(oop* base, oop* derived) {
-#if !defined(TIERED) && !defined(INCLUDE_JVMCI)
+#if !defined(TIERED) && !INCLUDE_JVMCI
   COMPILER1_PRESENT(ShouldNotReachHere();)
-#endif // !defined(TIERED) && !defined(INCLUDE_JVMCI)
+#endif // !defined(TIERED) && !INCLUDE_JVMCI
 #if COMPILER2_OR_JVMCI
   DerivedPointerTable::add(derived, base);
 #endif // COMPILER2_OR_JVMCI
@@ -459,7 +459,7 @@
 #ifndef PRODUCT
 
 bool ImmutableOopMap::has_derived_pointer() const {
-#if !defined(TIERED) && !defined(INCLUDE_JVMCI)
+#if !defined(TIERED) && !INCLUDE_JVMCI
   COMPILER1_PRESENT(return false);
 #endif // !TIERED
 #if COMPILER2_OR_JVMCI
--- a/src/hotspot/share/gc/cms/concurrentMarkSweepGeneration.cpp	Wed May 02 22:11:35 2018 -0700
+++ b/src/hotspot/share/gc/cms/concurrentMarkSweepGeneration.cpp	Fri May 04 08:50:01 2018 -0700
@@ -290,13 +290,13 @@
   if (_ref_processor == NULL) {
     // Allocate and initialize a reference processor
     _ref_processor =
-      new ReferenceProcessor(_span,                               // span
+      new ReferenceProcessor(&_span_based_discoverer,
                              (ParallelGCThreads > 1) && ParallelRefProcEnabled, // mt processing
-                             ParallelGCThreads,                   // mt processing degree
-                             _cmsGen->refs_discovery_is_mt(),     // mt discovery
+                             ParallelGCThreads,                      // mt processing degree
+                             _cmsGen->refs_discovery_is_mt(),        // mt discovery
                              MAX2(ConcGCThreads, ParallelGCThreads), // mt discovery degree
-                             _cmsGen->refs_discovery_is_atomic(), // discovery is not atomic
-                             &_is_alive_closure);                 // closure for liveness info
+                             _cmsGen->refs_discovery_is_atomic(),    // discovery is not atomic
+                             &_is_alive_closure);                    // closure for liveness info
     // Initialize the _ref_processor field of CMSGen
     _cmsGen->set_ref_processor(_ref_processor);
 
@@ -445,7 +445,10 @@
                            CardTableRS*                   ct,
                            ConcurrentMarkSweepPolicy*     cp):
   _cmsGen(cmsGen),
+  // Adjust span to cover old (cms) gen
+  _span(cmsGen->reserved()),
   _ct(ct),
+  _span_based_discoverer(_span),
   _ref_processor(NULL),    // will be set later
   _conc_workers(NULL),     // may be set later
   _abort_preclean(false),
@@ -455,8 +458,6 @@
   _modUnionTable((CardTable::card_shift - LogHeapWordSize),
                  -1 /* lock-free */, "No_lock" /* dummy */),
   _modUnionClosurePar(&_modUnionTable),
-  // Adjust my span to cover old (cms) gen
-  _span(cmsGen->reserved()),
   // Construct the is_alive_closure with _span & markBitMap
   _is_alive_closure(_span, &_markBitMap),
   _restart_addr(NULL),
@@ -3744,7 +3745,6 @@
   }
 }
 
-
 size_t CMSCollector::preclean_work(bool clean_refs, bool clean_survivor) {
   assert(_collectorState == Precleaning ||
          _collectorState == AbortablePreclean, "incorrect state");
@@ -3761,7 +3761,7 @@
   // referents.
   if (clean_refs) {
     CMSPrecleanRefsYieldClosure yield_cl(this);
-    assert(rp->span().equals(_span), "Spans should be equal");
+    assert(_span_based_discoverer.span().equals(_span), "Spans should be equal");
     CMSKeepAliveClosure keep_alive(this, _span, &_markBitMap,
                                    &_markStack, true /* preclean */);
     CMSDrainMarkingStackClosure complete_trace(this,
@@ -5153,7 +5153,7 @@
   WorkGang* workers = heap->workers();
   assert(workers != NULL, "Need parallel worker threads.");
   CMSRefProcTaskProxy rp_task(task, &_collector,
-                              _collector.ref_processor()->span(),
+                              _collector.ref_processor_span(),
                               _collector.markBitMap(),
                               workers, _collector.task_queues());
   workers->run_task(&rp_task);
@@ -5174,13 +5174,13 @@
   HandleMark   hm;
 
   ReferenceProcessor* rp = ref_processor();
-  assert(rp->span().equals(_span), "Spans should be equal");
+  assert(_span_based_discoverer.span().equals(_span), "Spans should be equal");
   assert(!rp->enqueuing_is_done(), "Enqueuing should not be complete");
   // Process weak references.
   rp->setup_policy(false);
   verify_work_stacks_empty();
 
-  ReferenceProcessorPhaseTimes pt(_gc_timer_cm, rp->num_q());
+  ReferenceProcessorPhaseTimes pt(_gc_timer_cm, rp->num_queues());
   {
     GCTraceTime(Debug, gc, phases) t("Reference Processing", _gc_timer_cm);
 
@@ -5245,7 +5245,7 @@
       CodeCache::do_unloading(&_is_alive_closure, purged_class);
 
       // Prune dead klasses from subklass/sibling/implementor lists.
-      Klass::clean_weak_klass_links();
+      Klass::clean_weak_klass_links(purged_class);
     }
 
     {
--- a/src/hotspot/share/gc/cms/concurrentMarkSweepGeneration.hpp	Wed May 02 22:11:35 2018 -0700
+++ b/src/hotspot/share/gc/cms/concurrentMarkSweepGeneration.hpp	Fri May 04 08:50:01 2018 -0700
@@ -69,7 +69,6 @@
 class ParNewGeneration;
 class PromotionInfo;
 class ScanMarkedObjectsAgainCarefullyClosure;
-class TenuredGeneration;
 class SerialOldTracer;
 
 // A generic CMS bit map. It's the basis for both the CMS marking bit map
@@ -617,7 +616,7 @@
 
  protected:
   ConcurrentMarkSweepGeneration* _cmsGen;  // Old gen (CMS)
-  MemRegion                      _span;    // Span covering above two
+  MemRegion                      _span;    // Span covering above
   CardTableRS*                   _ct;      // Card table
 
   // CMS marking support structures
@@ -641,8 +640,9 @@
   NOT_PRODUCT(ssize_t _num_par_pushes;)
 
   // ("Weak") Reference processing support.
-  ReferenceProcessor*            _ref_processor;
-  CMSIsAliveClosure              _is_alive_closure;
+  SpanSubjectToDiscoveryClosure _span_based_discoverer;
+  ReferenceProcessor*           _ref_processor;
+  CMSIsAliveClosure             _is_alive_closure;
   // Keep this textually after _markBitMap and _span; c'tor dependency.
 
   ConcurrentMarkSweepThread*     _cmsThread;   // The thread doing the work
@@ -841,6 +841,7 @@
                ConcurrentMarkSweepPolicy*     cp);
   ConcurrentMarkSweepThread* cmsThread() { return _cmsThread; }
 
+  MemRegion ref_processor_span() const { return _span_based_discoverer.span(); }
   ReferenceProcessor* ref_processor() { return _ref_processor; }
   void ref_processor_init();
 
--- a/src/hotspot/share/gc/cms/parNewGeneration.cpp	Wed May 02 22:11:35 2018 -0700
+++ b/src/hotspot/share/gc/cms/parNewGeneration.cpp	Fri May 04 08:50:01 2018 -0700
@@ -983,7 +983,7 @@
   // Can  the mt_degree be set later (at run_task() time would be best)?
   rp->set_active_mt_degree(active_workers);
   ReferenceProcessorStats stats;
-  ReferenceProcessorPhaseTimes pt(_gc_timer, rp->num_q());
+  ReferenceProcessorPhaseTimes pt(_gc_timer, rp->num_queues());
   if (rp->processing_is_mt()) {
     ParNewRefProcTaskExecutor task_executor(*this, *_old_gen, thread_state_set);
     stats = rp->process_discovered_references(&is_alive, &keep_alive,
@@ -1471,8 +1471,9 @@
 void ParNewGeneration::ref_processor_init() {
   if (_ref_processor == NULL) {
     // Allocate and initialize a reference processor
+    _span_based_discoverer.set_span(_reserved);
     _ref_processor =
-      new ReferenceProcessor(_reserved,                  // span
+      new ReferenceProcessor(&_span_based_discoverer,    // span
                              ParallelRefProcEnabled && (ParallelGCThreads > 1), // mt processing
                              ParallelGCThreads,          // mt processing degree
                              refs_discovery_is_mt(),     // mt discovery
--- a/src/hotspot/share/gc/g1/g1Arguments.cpp	Wed May 02 22:11:35 2018 -0700
+++ b/src/hotspot/share/gc/g1/g1Arguments.cpp	Fri May 04 08:50:01 2018 -0700
@@ -81,11 +81,9 @@
     vm_exit_during_initialization("The flag -XX:+UseG1GC can not be combined with -XX:ParallelGCThreads=0", NULL);
   }
 
-#if INCLUDE_ALL_GCS
   if (FLAG_IS_DEFAULT(G1ConcRefinementThreads)) {
     FLAG_SET_ERGO(uint, G1ConcRefinementThreads, ParallelGCThreads);
   }
-#endif
 
   // MarkStackSize will be set (if it hasn't been set by the user)
   // when concurrent marking is initialized.
--- a/src/hotspot/share/gc/g1/g1CollectedHeap.cpp	Wed May 02 22:11:35 2018 -0700
+++ b/src/hotspot/share/gc/g1/g1CollectedHeap.cpp	Fri May 04 08:50:01 2018 -0700
@@ -988,9 +988,9 @@
 
   // Disable discovery and empty the discovered lists
   // for the CM ref processor.
-  ref_processor_cm()->disable_discovery();
-  ref_processor_cm()->abandon_partial_discovery();
-  ref_processor_cm()->verify_no_references_recorded();
+  _ref_processor_cm->disable_discovery();
+  _ref_processor_cm->abandon_partial_discovery();
+  _ref_processor_cm->verify_no_references_recorded();
 
   // Abandon current iterations of concurrent marking and concurrent
   // refinement, if any are in progress.
@@ -1080,10 +1080,10 @@
   // That will be done at the start of the next marking cycle.
   // We also know that the STW processor should no longer
   // discover any new references.
-  assert(!ref_processor_stw()->discovery_enabled(), "Postcondition");
-  assert(!ref_processor_cm()->discovery_enabled(), "Postcondition");
-  ref_processor_stw()->verify_no_references_recorded();
-  ref_processor_cm()->verify_no_references_recorded();
+  assert(!_ref_processor_stw->discovery_enabled(), "Postcondition");
+  assert(!_ref_processor_cm->discovery_enabled(), "Postcondition");
+  _ref_processor_stw->verify_no_references_recorded();
+  _ref_processor_cm->verify_no_references_recorded();
 }
 
 void G1CollectedHeap::print_heap_after_full_collection(G1HeapTransition* heap_transition) {
@@ -1410,10 +1410,12 @@
   _g1_policy(new G1Policy(_gc_timer_stw)),
   _collection_set(this, _g1_policy),
   _dirty_card_queue_set(false),
+  _ref_processor_stw(NULL),
+  _is_alive_closure_stw(this),
+  _is_subject_to_discovery_stw(this),
+  _ref_processor_cm(NULL),
   _is_alive_closure_cm(this),
-  _is_alive_closure_stw(this),
-  _ref_processor_cm(NULL),
-  _ref_processor_stw(NULL),
+  _is_subject_to_discovery_cm(this),
   _bot(NULL),
   _hot_card_cache(NULL),
   _g1_rem_set(NULL),
@@ -1786,43 +1788,27 @@
   //     * Discovery is atomic - i.e. not concurrent.
   //     * Reference discovery will not need a barrier.
 
-  MemRegion mr = reserved_region();
-
   bool mt_processing = ParallelRefProcEnabled && (ParallelGCThreads > 1);
 
   // Concurrent Mark ref processor
   _ref_processor_cm =
-    new ReferenceProcessor(mr,    // span
-                           mt_processing,
-                                // mt processing
-                           ParallelGCThreads,
-                                // degree of mt processing
-                           (ParallelGCThreads > 1) || (ConcGCThreads > 1),
-                                // mt discovery
-                           MAX2(ParallelGCThreads, ConcGCThreads),
-                                // degree of mt discovery
-                           false,
-                                // Reference discovery is not atomic
-                           &_is_alive_closure_cm);
-                                // is alive closure
-                                // (for efficiency/performance)
+    new ReferenceProcessor(&_is_subject_to_discovery_cm,
+                           mt_processing,                                  // mt processing
+                           ParallelGCThreads,                              // degree of mt processing
+                           (ParallelGCThreads > 1) || (ConcGCThreads > 1), // mt discovery
+                           MAX2(ParallelGCThreads, ConcGCThreads),         // degree of mt discovery
+                           false,                                          // Reference discovery is not atomic
+                           &_is_alive_closure_cm);                         // is alive closure
 
   // STW ref processor
   _ref_processor_stw =
-    new ReferenceProcessor(mr,    // span
-                           mt_processing,
-                                // mt processing
-                           ParallelGCThreads,
-                                // degree of mt processing
-                           (ParallelGCThreads > 1),
-                                // mt discovery
-                           ParallelGCThreads,
-                                // degree of mt discovery
-                           true,
-                                // Reference discovery is atomic
-                           &_is_alive_closure_stw);
-                                // is alive closure
-                                // (for efficiency/performance)
+    new ReferenceProcessor(&_is_subject_to_discovery_stw,
+                           mt_processing,                        // mt processing
+                           ParallelGCThreads,                    // degree of mt processing
+                           (ParallelGCThreads > 1),              // mt discovery
+                           ParallelGCThreads,                    // degree of mt discovery
+                           true,                                 // Reference discovery is atomic
+                           &_is_alive_closure_stw);              // is alive closure
 }
 
 CollectorPolicy* G1CollectedHeap::collector_policy() const {
@@ -2853,14 +2839,14 @@
       // reference processing currently works in G1.
 
       // Enable discovery in the STW reference processor
-      ref_processor_stw()->enable_discovery();
+      _ref_processor_stw->enable_discovery();
 
       {
         // We want to temporarily turn off discovery by the
         // CM ref processor, if necessary, and turn it back on
         // on again later if we do. Using a scoped
         // NoRefDiscovery object will do this.
-        NoRefDiscovery no_cm_discovery(ref_processor_cm());
+        NoRefDiscovery no_cm_discovery(_ref_processor_cm);
 
         // Forget the current alloc region (we might even choose it to be part
         // of the collection set!).
@@ -2998,8 +2984,8 @@
         _verifier->verify_after_gc(verify_type);
         _verifier->check_bitmaps("GC End");
 
-        assert(!ref_processor_stw()->discovery_enabled(), "Postcondition");
-        ref_processor_stw()->verify_no_references_recorded();
+        assert(!_ref_processor_stw->discovery_enabled(), "Postcondition");
+        _ref_processor_stw->verify_no_references_recorded();
 
         // CM reference discovery will be re-enabled if necessary.
       }
@@ -3543,6 +3529,7 @@
 // To minimize the remark pause times, the tasks below are done in parallel.
 class G1ParallelCleaningTask : public AbstractGangTask {
 private:
+  bool                          _unloading_occurred;
   G1StringAndSymbolCleaningTask _string_symbol_task;
   G1CodeCacheUnloadingTask      _code_cache_task;
   G1KlassCleaningTask           _klass_cleaning_task;
@@ -3555,6 +3542,7 @@
       _string_symbol_task(is_alive, true, true, G1StringDedup::is_enabled()),
       _code_cache_task(num_workers, is_alive, unloading_occurred),
       _klass_cleaning_task(),
+      _unloading_occurred(unloading_occurred),
       _resolved_method_cleaning_task() {
   }
 
@@ -3580,7 +3568,11 @@
     _code_cache_task.work_second_pass(worker_id);
 
     // Clean all klasses that were not unloaded.
-    _klass_cleaning_task.work();
+    // The weak metadata in klass doesn't need to be
+    // processed if there was no unloading.
+    if (_unloading_occurred) {
+      _klass_cleaning_task.work();
+    }
   }
 };
 
@@ -3642,26 +3634,21 @@
 
 // Weak Reference Processing support
 
-// An always "is_alive" closure that is used to preserve referents.
-// If the object is non-null then it's alive.  Used in the preservation
-// of referent objects that are pointed to by reference objects
-// discovered by the CM ref processor.
-class G1AlwaysAliveClosure: public BoolObjectClosure {
-public:
-  bool do_object_b(oop p) {
-    if (p != NULL) {
-      return true;
-    }
-    return false;
-  }
-};
-
 bool G1STWIsAliveClosure::do_object_b(oop p) {
   // An object is reachable if it is outside the collection set,
   // or is inside and copied.
   return !_g1h->is_in_cset(p) || p->is_forwarded();
 }
 
+bool G1STWSubjectToDiscoveryClosure::do_object_b(oop obj) {
+  assert(obj != NULL, "must not be NULL");
+  assert(_g1h->is_in_reserved(obj), "Trying to discover obj " PTR_FORMAT " not in heap", p2i(obj));
+  // The areas the CM and STW ref processor manage must be disjoint. The is_in_cset() below
+  // may falsely indicate that this is not the case here: however the collection set only
+  // contains old regions when concurrent mark is not running.
+  return _g1h->is_in_cset(obj) || _g1h->heap_region_containing(obj)->is_survivor();
+}
+
 // Non Copying Keep Alive closure
 class G1KeepAliveClosure: public OopClosure {
   G1CollectedHeap*_g1h;
@@ -3892,126 +3879,6 @@
 
 // End of weak reference support closures
 
-// Abstract task used to preserve (i.e. copy) any referent objects
-// that are in the collection set and are pointed to by reference
-// objects discovered by the CM ref processor.
-
-class G1ParPreserveCMReferentsTask: public AbstractGangTask {
-protected:
-  G1CollectedHeap*         _g1h;
-  G1ParScanThreadStateSet* _pss;
-  RefToScanQueueSet*       _queues;
-  ParallelTaskTerminator   _terminator;
-  uint                     _n_workers;
-
-public:
-  G1ParPreserveCMReferentsTask(G1CollectedHeap* g1h, G1ParScanThreadStateSet* per_thread_states, int workers, RefToScanQueueSet *task_queues) :
-    AbstractGangTask("ParPreserveCMReferents"),
-    _g1h(g1h),
-    _pss(per_thread_states),
-    _queues(task_queues),
-    _terminator(workers, _queues),
-    _n_workers(workers)
-  {
-    g1h->ref_processor_cm()->set_active_mt_degree(workers);
-  }
-
-  void work(uint worker_id) {
-    G1GCParPhaseTimesTracker x(_g1h->g1_policy()->phase_times(), G1GCPhaseTimes::PreserveCMReferents, worker_id);
-
-    ResourceMark rm;
-    HandleMark   hm;
-
-    G1ParScanThreadState*          pss = _pss->state_for_worker(worker_id);
-    pss->set_ref_discoverer(NULL);
-    assert(pss->queue_is_empty(), "both queue and overflow should be empty");
-
-    // Is alive closure
-    G1AlwaysAliveClosure always_alive;
-
-    // Copying keep alive closure. Applied to referent objects that need
-    // to be copied.
-    G1CopyingKeepAliveClosure keep_alive(_g1h, pss->closures()->raw_strong_oops(), pss);
-
-    ReferenceProcessor* rp = _g1h->ref_processor_cm();
-
-    uint limit = ReferenceProcessor::number_of_subclasses_of_ref() * rp->max_num_q();
-    uint stride = MIN2(MAX2(_n_workers, 1U), limit);
-
-    // limit is set using max_num_q() - which was set using ParallelGCThreads.
-    // So this must be true - but assert just in case someone decides to
-    // change the worker ids.
-    assert(worker_id < limit, "sanity");
-    assert(!rp->discovery_is_atomic(), "check this code");
-
-    // Select discovered lists [i, i+stride, i+2*stride,...,limit)
-    for (uint idx = worker_id; idx < limit; idx += stride) {
-      DiscoveredList& ref_list = rp->discovered_refs()[idx];
-
-      DiscoveredListIterator iter(ref_list, &keep_alive, &always_alive);
-      while (iter.has_next()) {
-        // Since discovery is not atomic for the CM ref processor, we
-        // can see some null referent objects.
-        iter.load_ptrs(DEBUG_ONLY(true));
-        oop ref = iter.obj();
-
-        // This will filter nulls.
-        if (iter.is_referent_alive()) {
-          iter.make_referent_alive();
-        }
-        iter.move_to_next();
-      }
-    }
-
-    // Drain the queue - which may cause stealing
-    G1ParEvacuateFollowersClosure drain_queue(_g1h, pss, _queues, &_terminator);
-    drain_queue.do_void();
-    // Allocation buffers were retired at the end of G1ParEvacuateFollowersClosure
-    assert(pss->queue_is_empty(), "should be");
-  }
-};
-
-void G1CollectedHeap::preserve_cm_referents(G1ParScanThreadStateSet* per_thread_states) {
-  // Any reference objects, in the collection set, that were 'discovered'
-  // by the CM ref processor should have already been copied (either by
-  // applying the external root copy closure to the discovered lists, or
-  // by following an RSet entry).
-  //
-  // But some of the referents, that are in the collection set, that these
-  // reference objects point to may not have been copied: the STW ref
-  // processor would have seen that the reference object had already
-  // been 'discovered' and would have skipped discovering the reference,
-  // but would not have treated the reference object as a regular oop.
-  // As a result the copy closure would not have been applied to the
-  // referent object.
-  //
-  // We need to explicitly copy these referent objects - the references
-  // will be processed at the end of remarking.
-  //
-  // We also need to do this copying before we process the reference
-  // objects discovered by the STW ref processor in case one of these
-  // referents points to another object which is also referenced by an
-  // object discovered by the STW ref processor.
-  double preserve_cm_referents_time = 0.0;
-
-  // To avoid spawning task when there is no work to do, check that
-  // a concurrent cycle is active and that some references have been
-  // discovered.
-  if (concurrent_mark()->cm_thread()->during_cycle() &&
-      ref_processor_cm()->has_discovered_references()) {
-    double preserve_cm_referents_start = os::elapsedTime();
-    uint no_of_gc_workers = workers()->active_workers();
-    G1ParPreserveCMReferentsTask keep_cm_referents(this,
-                                                   per_thread_states,
-                                                   no_of_gc_workers,
-                                                   _task_queues);
-    workers()->run_task(&keep_cm_referents);
-    preserve_cm_referents_time = os::elapsedTime() - preserve_cm_referents_start;
-  }
-
-  g1_policy()->phase_times()->record_preserve_cm_referents_time_ms(preserve_cm_referents_time * 1000.0);
-}
-
 // Weak Reference processing during an evacuation pause (part 1).
 void G1CollectedHeap::process_discovered_references(G1ParScanThreadStateSet* per_thread_states) {
   double ref_proc_start = os::elapsedTime();
@@ -4055,9 +3922,9 @@
     uint no_of_gc_workers = workers()->active_workers();
 
     // Parallel reference processing
-    assert(no_of_gc_workers <= rp->max_num_q(),
+    assert(no_of_gc_workers <= rp->max_num_queues(),
            "Mismatch between the number of GC workers %u and the maximum number of Reference process queues %u",
-           no_of_gc_workers,  rp->max_num_q());
+           no_of_gc_workers,  rp->max_num_queues());
 
     G1STWRefProcTaskExecutor par_task_executor(this, per_thread_states, workers(), _task_queues, no_of_gc_workers);
     stats = rp->process_discovered_references(&is_alive,
@@ -4095,9 +3962,9 @@
 
     uint n_workers = workers()->active_workers();
 
-    assert(n_workers <= rp->max_num_q(),
+    assert(n_workers <= rp->max_num_queues(),
            "Mismatch between the number of GC workers %u and the maximum number of Reference process queues %u",
-           n_workers,  rp->max_num_q());
+           n_workers,  rp->max_num_queues());
 
     G1STWRefProcTaskExecutor par_task_executor(this, per_thread_states, workers(), _task_queues, n_workers);
     rp->enqueue_discovered_references(&par_task_executor, pt);
@@ -4192,13 +4059,17 @@
 }
 
 void G1CollectedHeap::post_evacuate_collection_set(EvacuationInfo& evacuation_info, G1ParScanThreadStateSet* per_thread_states) {
+  // Also cleans the card table from temporary duplicate detection information used
+  // during UpdateRS/ScanRS.
+  g1_rem_set()->cleanup_after_oops_into_collection_set_do();
+
   // Process any discovered reference objects - we have
   // to do this _before_ we retire the GC alloc regions
   // as we may have to copy some 'reachable' referent
   // objects (and their reachable sub-graphs) that were
   // not copied during the pause.
-  preserve_cm_referents(per_thread_states);
   process_discovered_references(per_thread_states);
+  enqueue_discovered_references(per_thread_states);
 
   G1STWIsAliveClosure is_alive(this);
   G1KeepAliveClosure keep_alive(this);
@@ -4221,8 +4092,6 @@
     g1_policy()->phase_times()->record_string_dedup_fixup_time(fixup_time_ms);
   }
 
-  g1_rem_set()->cleanup_after_oops_into_collection_set_do();
-
   if (evacuation_failed()) {
     restore_after_evac_failure();
 
@@ -4234,15 +4103,6 @@
 
   _preserved_marks_set.assert_empty();
 
-  // Enqueue any remaining references remaining on the STW
-  // reference processor's discovered lists. We need to do
-  // this after the card table is cleaned (and verified) as
-  // the act of enqueueing entries on to the pending list
-  // will log these updates (and dirty their associated
-  // cards). We need these updates logged to update any
-  // RSets.
-  enqueue_discovered_references(per_thread_states);
-
   _allocator->release_gc_alloc_regions(evacuation_info);
 
   merge_per_thread_state_info(per_thread_states);
--- a/src/hotspot/share/gc/g1/g1CollectedHeap.hpp	Wed May 02 22:11:35 2018 -0700
+++ b/src/hotspot/share/gc/g1/g1CollectedHeap.hpp	Fri May 04 08:50:01 2018 -0700
@@ -107,13 +107,20 @@
 // (optional) _is_alive_non_header closure in the STW
 // reference processor. It is also extensively used during
 // reference processing during STW evacuation pauses.
-class G1STWIsAliveClosure: public BoolObjectClosure {
+class G1STWIsAliveClosure : public BoolObjectClosure {
   G1CollectedHeap* _g1h;
 public:
   G1STWIsAliveClosure(G1CollectedHeap* g1h) : _g1h(g1h) {}
   bool do_object_b(oop p);
 };
 
+class G1STWSubjectToDiscoveryClosure : public BoolObjectClosure {
+  G1CollectedHeap* _g1h;
+public:
+  G1STWSubjectToDiscoveryClosure(G1CollectedHeap* g1h) : _g1h(g1h) {}
+  bool do_object_b(oop p);
+};
+
 class G1RegionMappingChangedListener : public G1MappingChangedListener {
  private:
   void reset_from_card_cache(uint start_idx, size_t num_regions);
@@ -506,9 +513,6 @@
   // allocated block, or else "NULL".
   HeapWord* expand_and_allocate(size_t word_size);
 
-  // Preserve any referents discovered by concurrent marking that have not yet been
-  // copied by the STW pause.
-  void preserve_cm_referents(G1ParScanThreadStateSet* per_thread_states);
   // Process any reference objects discovered during
   // an incremental evacuation pause.
   void process_discovered_references(G1ParScanThreadStateSet* per_thread_states);
@@ -897,6 +901,8 @@
   // the discovered lists during reference discovery.
   G1STWIsAliveClosure _is_alive_closure_stw;
 
+  G1STWSubjectToDiscoveryClosure _is_subject_to_discovery_stw;
+
   // The (concurrent marking) reference processor...
   ReferenceProcessor* _ref_processor_cm;
 
@@ -908,6 +914,7 @@
   // discovery.
   G1CMIsAliveClosure _is_alive_closure_cm;
 
+  G1CMSubjectToDiscoveryClosure _is_subject_to_discovery_cm;
 public:
 
   RefToScanQueue *task_queue(uint i) const;
--- a/src/hotspot/share/gc/g1/g1ConcurrentMark.cpp	Wed May 02 22:11:35 2018 -0700
+++ b/src/hotspot/share/gc/g1/g1ConcurrentMark.cpp	Fri May 04 08:50:01 2018 -0700
@@ -1389,15 +1389,6 @@
   }
 }
 
-// Supporting Object and Oop closures for reference discovery
-// and processing in during marking
-
-bool G1CMIsAliveClosure::do_object_b(oop obj) {
-  HeapWord* addr = (HeapWord*)obj;
-  return addr != NULL &&
-         (!_g1h->is_in_g1_reserved(addr) || !_g1h->is_obj_ill(obj));
-}
-
 // 'Keep Alive' oop closure used by both serial parallel reference processing.
 // Uses the G1CMTask associated with a worker thread (for serial reference
 // processing the G1CMTask for worker 0 is used) to preserve (mark) and
@@ -1665,7 +1656,7 @@
     // Reference lists are balanced (see balance_all_queues() and balance_queues()).
     rp->set_active_mt_degree(active_workers);
 
-    ReferenceProcessorPhaseTimes pt(_gc_timer_cm, rp->num_q());
+    ReferenceProcessorPhaseTimes pt(_gc_timer_cm, rp->num_queues());
 
     // Process the weak references.
     const ReferenceProcessorStats& stats =
@@ -1684,7 +1675,7 @@
     assert(has_overflown() || _global_mark_stack.is_empty(),
            "Mark stack should be empty (unless it has overflown)");
 
-    assert(rp->num_q() == active_workers, "why not");
+    assert(rp->num_queues() == active_workers, "why not");
 
     rp->enqueue_discovered_references(executor, &pt);
 
--- a/src/hotspot/share/gc/g1/g1ConcurrentMark.hpp	Wed May 02 22:11:35 2018 -0700
+++ b/src/hotspot/share/gc/g1/g1ConcurrentMark.hpp	Fri May 04 08:50:01 2018 -0700
@@ -36,6 +36,7 @@
 class ConcurrentGCTimer;
 class G1ConcurrentMarkThread;
 class G1CollectedHeap;
+class G1CMOopClosure;
 class G1CMTask;
 class G1ConcurrentMark;
 class G1OldTracer;
@@ -109,7 +110,13 @@
   G1CollectedHeap* _g1h;
 public:
   G1CMIsAliveClosure(G1CollectedHeap* g1h) : _g1h(g1h) { }
+  bool do_object_b(oop obj);
+};
 
+class G1CMSubjectToDiscoveryClosure : public BoolObjectClosure {
+  G1CollectedHeap* _g1h;
+public:
+  G1CMSubjectToDiscoveryClosure(G1CollectedHeap* g1h) : _g1h(g1h) { }
   bool do_object_b(oop obj);
 };
 
--- a/src/hotspot/share/gc/g1/g1ConcurrentMark.inline.hpp	Wed May 02 22:11:35 2018 -0700
+++ b/src/hotspot/share/gc/g1/g1ConcurrentMark.inline.hpp	Fri May 04 08:50:01 2018 -0700
@@ -38,6 +38,22 @@
 #include "gc/shared/taskqueue.inline.hpp"
 #include "utilities/bitMap.inline.hpp"
 
+inline bool G1CMIsAliveClosure::do_object_b(oop obj) {
+  return !_g1h->is_obj_ill(obj);
+}
+
+inline bool G1CMSubjectToDiscoveryClosure::do_object_b(oop obj) {
+  // Re-check whether the passed object is null. With ReferentBasedDiscovery the
+  // mutator may have changed the referent's value (i.e. cleared it) between the
+  // time the referent was determined to be potentially alive and calling this
+  // method.
+  if (obj == NULL) {
+    return false;
+  }
+  assert(_g1h->is_in_reserved(obj), "Trying to discover obj " PTR_FORMAT " not in heap", p2i(obj));
+  return _g1h->heap_region_containing(obj)->is_old_or_humongous();
+}
+
 inline bool G1ConcurrentMark::mark_in_next_bitmap(uint const worker_id, oop const obj, size_t const obj_size) {
   HeapRegion* const hr = _g1h->heap_region_containing(obj);
   return mark_in_next_bitmap(worker_id, hr, obj, obj_size);
--- a/src/hotspot/share/gc/g1/g1FullCollector.cpp	Wed May 02 22:11:35 2018 -0700
+++ b/src/hotspot/share/gc/g1/g1FullCollector.cpp	Fri May 04 08:50:01 2018 -0700
@@ -112,7 +112,9 @@
     _preserved_marks_set(true),
     _serial_compaction_point(),
     _is_alive(heap->concurrent_mark()->next_mark_bitmap()),
-    _is_alive_mutator(heap->ref_processor_stw(), &_is_alive) {
+    _is_alive_mutator(heap->ref_processor_stw(), &_is_alive),
+    _always_subject_to_discovery(),
+    _is_subject_mutator(heap->ref_processor_stw(), &_always_subject_to_discovery) {
   assert(SafepointSynchronize::is_at_safepoint(), "must be at a safepoint");
 
   _preserved_marks_set.init(_num_workers);
--- a/src/hotspot/share/gc/g1/g1FullCollector.hpp	Wed May 02 22:11:35 2018 -0700
+++ b/src/hotspot/share/gc/g1/g1FullCollector.hpp	Fri May 04 08:50:01 2018 -0700
@@ -42,6 +42,16 @@
 class GCMemoryManager;
 class ReferenceProcessor;
 
+// Subject-to-discovery closure for reference processing during Full GC. During
+// Full GC the whole heap is subject to discovery.
+class G1FullGCSubjectToDiscoveryClosure: public BoolObjectClosure {
+public:
+  bool do_object_b(oop p) {
+    assert(p != NULL, "must be");
+    return true;
+  }
+};
+
 // The G1FullCollector holds data associated with the current Full GC.
 class G1FullCollector : StackObj {
   G1CollectedHeap*          _heap;
@@ -58,6 +68,9 @@
 
   static uint calc_active_workers();
 
+  G1FullGCSubjectToDiscoveryClosure _always_subject_to_discovery;
+  ReferenceProcessorSubjectToDiscoveryMutator _is_subject_mutator;
+
 public:
   G1FullCollector(G1CollectedHeap* heap, GCMemoryManager* memory_manager, bool explicit_gc, bool clear_soft_refs);
   ~G1FullCollector();
--- a/src/hotspot/share/gc/g1/g1FullGCMarker.cpp	Wed May 02 22:11:35 2018 -0700
+++ b/src/hotspot/share/gc/g1/g1FullGCMarker.cpp	Fri May 04 08:50:01 2018 -0700
@@ -24,6 +24,7 @@
 
 #include "precompiled.hpp"
 #include "gc/g1/g1FullGCMarker.inline.hpp"
+#include "gc/shared/referenceProcessor.hpp"
 
 G1FullGCMarker::G1FullGCMarker(uint worker_id, PreservedMarks* preserved_stack, G1CMBitMap* bitmap) :
     _worker_id(worker_id),
--- a/src/hotspot/share/gc/g1/g1FullGCReferenceProcessorExecutor.cpp	Wed May 02 22:11:35 2018 -0700
+++ b/src/hotspot/share/gc/g1/g1FullGCReferenceProcessorExecutor.cpp	Fri May 04 08:50:01 2018 -0700
@@ -34,7 +34,7 @@
 G1FullGCReferenceProcessingExecutor::G1FullGCReferenceProcessingExecutor(G1FullCollector* collector) :
     _collector(collector),
     _reference_processor(collector->reference_processor()),
-    _old_mt_degree(_reference_processor->num_q()) {
+    _old_mt_degree(_reference_processor->num_queues()) {
   if (_reference_processor->processing_is_mt()) {
     _reference_processor->set_active_mt_degree(_collector->workers());
   }
@@ -92,7 +92,7 @@
   G1FullGCMarker* marker = _collector->marker(0);
   G1IsAliveClosure is_alive(_collector->mark_bitmap());
   G1FullKeepAliveClosure keep_alive(marker);
-  ReferenceProcessorPhaseTimes pt(timer, _reference_processor->num_q());
+  ReferenceProcessorPhaseTimes pt(timer, _reference_processor->num_queues());
   AbstractRefProcTaskExecutor* executor = _reference_processor->processing_is_mt() ? this : NULL;
 
   // Process discovered references, use this executor if multi-threaded
--- a/src/hotspot/share/gc/g1/g1GCPhaseTimes.cpp	Wed May 02 22:11:35 2018 -0700
+++ b/src/hotspot/share/gc/g1/g1GCPhaseTimes.cpp	Fri May 04 08:50:01 2018 -0700
@@ -113,8 +113,6 @@
   _gc_par_phases[YoungFreeCSet] = new WorkerDataArray<double>(max_gc_threads, "Young Free Collection Set (ms):");
   _gc_par_phases[NonYoungFreeCSet] = new WorkerDataArray<double>(max_gc_threads, "Non-Young Free Collection Set (ms):");
 
-  _gc_par_phases[PreserveCMReferents] = new WorkerDataArray<double>(max_gc_threads, "Parallel Preserve CM Refs (ms):");
-
   reset();
 }
 
@@ -399,8 +397,7 @@
 
   debug_time("Code Roots Fixup", _cur_collection_code_root_fixup_time_ms);
 
-  debug_time("Preserve CM Refs", _recorded_preserve_cm_referents_time_ms);
-  trace_phase(_gc_par_phases[PreserveCMReferents]);
+  debug_time("Clear Card Table", _cur_clear_ct_time_ms);
 
   debug_time_for_reference("Reference Processing", _cur_ref_proc_time_ms);
   _ref_phase_times.print_all_references(2, false);
@@ -413,8 +410,6 @@
     debug_phase(_gc_par_phases[StringDedupTableFixup]);
   }
 
-  debug_time("Clear Card Table", _cur_clear_ct_time_ms);
-
   if (G1CollectedHeap::heap()->evacuation_failed()) {
     debug_time("Evacuation Failure", evac_fail_handling);
     trace_time("Recalculate Used", _cur_evac_fail_recalc_used);
--- a/src/hotspot/share/gc/g1/g1GCPhaseTimes.hpp	Wed May 02 22:11:35 2018 -0700
+++ b/src/hotspot/share/gc/g1/g1GCPhaseTimes.hpp	Fri May 04 08:50:01 2018 -0700
@@ -73,7 +73,6 @@
     StringDedupQueueFixup,
     StringDedupTableFixup,
     RedirtyCards,
-    PreserveCMReferents,
     YoungFreeCSet,
     NonYoungFreeCSet,
     GCParPhasesSentinel
--- a/src/hotspot/share/gc/g1/g1MonitoringSupport.cpp	Wed May 02 22:11:35 2018 -0700
+++ b/src/hotspot/share/gc/g1/g1MonitoringSupport.cpp	Fri May 04 08:50:01 2018 -0700
@@ -26,6 +26,7 @@
 #include "gc/g1/g1CollectedHeap.inline.hpp"
 #include "gc/g1/g1MonitoringSupport.hpp"
 #include "gc/g1/g1Policy.hpp"
+#include "gc/shared/collectorCounters.hpp"
 #include "gc/shared/hSpaceCounters.hpp"
 #include "memory/metaspaceCounters.hpp"
 
--- a/src/hotspot/share/gc/g1/g1RootProcessor.cpp	Wed May 02 22:11:35 2018 -0700
+++ b/src/hotspot/share/gc/g1/g1RootProcessor.cpp	Fri May 04 08:50:01 2018 -0700
@@ -38,6 +38,7 @@
 #include "gc/g1/g1RootClosures.hpp"
 #include "gc/g1/g1RootProcessor.hpp"
 #include "gc/g1/heapRegion.inline.hpp"
+#include "gc/shared/referenceProcessor.hpp"
 #include "gc/shared/weakProcessor.hpp"
 #include "memory/allocation.inline.hpp"
 #include "runtime/mutex.hpp"
--- a/src/hotspot/share/gc/parallel/asPSYoungGen.cpp	Wed May 02 22:11:35 2018 -0700
+++ b/src/hotspot/share/gc/parallel/asPSYoungGen.cpp	Fri May 04 08:50:01 2018 -0700
@@ -496,7 +496,7 @@
 
   _reserved = MemRegion((HeapWord*)virtual_space()->low_boundary(),
                         (HeapWord*)virtual_space()->high_boundary());
-  PSScavenge::reference_processor()->set_span(_reserved);
+  PSScavenge::set_subject_to_discovery_span(_reserved);
 
   HeapWord* new_eden_bottom = (HeapWord*)virtual_space()->low();
   HeapWord* eden_bottom = eden_space()->bottom();
--- a/src/hotspot/share/gc/parallel/parallelScavengeHeap.cpp	Wed May 02 22:11:35 2018 -0700
+++ b/src/hotspot/share/gc/parallel/parallelScavengeHeap.cpp	Fri May 04 08:50:01 2018 -0700
@@ -31,7 +31,7 @@
 #include "gc/parallel/objectStartArray.inline.hpp"
 #include "gc/parallel/parallelScavengeHeap.inline.hpp"
 #include "gc/parallel/psAdaptiveSizePolicy.hpp"
-#include "gc/parallel/psMarkSweep.hpp"
+#include "gc/parallel/psMarkSweepProxy.hpp"
 #include "gc/parallel/psMemoryPool.hpp"
 #include "gc/parallel/psParallelCompact.inline.hpp"
 #include "gc/parallel/psPromotionManager.hpp"
@@ -48,6 +48,7 @@
 #include "runtime/vmThread.hpp"
 #include "services/memoryManager.hpp"
 #include "services/memTracker.hpp"
+#include "utilities/macros.hpp"
 #include "utilities/vmError.hpp"
 
 PSYoungGen*  ParallelScavengeHeap::_young_gen = NULL;
@@ -155,7 +156,7 @@
   if (UseParallelOldGC) {
     PSParallelCompact::post_initialize();
   } else {
-    PSMarkSweep::initialize();
+    PSMarkSweepProxy::initialize();
   }
   PSPromotionManager::initialize();
 }
@@ -406,7 +407,7 @@
     bool maximum_compaction = clear_all_soft_refs;
     PSParallelCompact::invoke(maximum_compaction);
   } else {
-    PSMarkSweep::invoke(clear_all_soft_refs);
+    PSMarkSweepProxy::invoke(clear_all_soft_refs);
   }
 }
 
@@ -545,7 +546,7 @@
 jlong ParallelScavengeHeap::millis_since_last_gc() {
   return UseParallelOldGC ?
     PSParallelCompact::millis_since_last_gc() :
-    PSMarkSweep::millis_since_last_gc();
+    PSMarkSweepProxy::millis_since_last_gc();
 }
 
 void ParallelScavengeHeap::prepare_for_verify() {
@@ -602,7 +603,7 @@
   AdaptiveSizePolicyOutput::print();
   log_debug(gc, heap, exit)("Accumulated young generation GC time %3.7f secs", PSScavenge::accumulated_time()->seconds());
   log_debug(gc, heap, exit)("Accumulated old generation GC time %3.7f secs",
-      UseParallelOldGC ? PSParallelCompact::accumulated_time()->seconds() : PSMarkSweep::accumulated_time()->seconds());
+      UseParallelOldGC ? PSParallelCompact::accumulated_time()->seconds() : PSMarkSweepProxy::accumulated_time()->seconds());
 }
 
 
--- a/src/hotspot/share/gc/parallel/parallelScavengeHeap.inline.hpp	Wed May 02 22:11:35 2018 -0700
+++ b/src/hotspot/share/gc/parallel/parallelScavengeHeap.inline.hpp	Fri May 04 08:50:01 2018 -0700
@@ -26,13 +26,13 @@
 #define SHARE_VM_GC_PARALLEL_PARALLELSCAVENGEHEAP_INLINE_HPP
 
 #include "gc/parallel/parallelScavengeHeap.hpp"
-#include "gc/parallel/psMarkSweep.hpp"
+#include "gc/parallel/psMarkSweepProxy.hpp"
 #include "gc/parallel/psParallelCompact.inline.hpp"
 #include "gc/parallel/psScavenge.hpp"
 
 inline size_t ParallelScavengeHeap::total_invocations() {
   return UseParallelOldGC ? PSParallelCompact::total_invocations() :
-    PSMarkSweep::total_invocations();
+    PSMarkSweepProxy::total_invocations();
 }
 
 inline bool ParallelScavengeHeap::should_alloc_in_eden(const size_t size) const {
--- a/src/hotspot/share/gc/parallel/psMarkSweep.cpp	Wed May 02 22:11:35 2018 -0700
+++ b/src/hotspot/share/gc/parallel/psMarkSweep.cpp	Fri May 04 08:50:01 2018 -0700
@@ -65,9 +65,11 @@
 jlong               PSMarkSweep::_time_of_last_gc   = 0;
 CollectorCounters*  PSMarkSweep::_counters = NULL;
 
+SpanSubjectToDiscoveryClosure PSMarkSweep::_span_based_discoverer;
+
 void PSMarkSweep::initialize() {
-  MemRegion mr = ParallelScavengeHeap::heap()->reserved_region();
-  set_ref_processor(new ReferenceProcessor(mr));     // a vanilla ref proc
+  _span_based_discoverer.set_span(ParallelScavengeHeap::heap()->reserved_region());
+  set_ref_processor(new ReferenceProcessor(&_span_based_discoverer));     // a vanilla ref proc
   _counters = new CollectorCounters("PSMarkSweep", 1);
 }
 
@@ -258,7 +260,7 @@
     DerivedPointerTable::update_pointers();
 #endif
 
-    ReferenceProcessorPhaseTimes pt(_gc_timer, ref_processor()->num_q());
+    ReferenceProcessorPhaseTimes pt(_gc_timer, ref_processor()->num_queues());
 
     ref_processor()->enqueue_discovered_references(NULL, &pt);
 
@@ -537,7 +539,7 @@
     GCTraceTime(Debug, gc, phases) t("Reference Processing", _gc_timer);
 
     ref_processor()->setup_policy(clear_all_softrefs);
-    ReferenceProcessorPhaseTimes pt(_gc_timer, ref_processor()->num_q());
+    ReferenceProcessorPhaseTimes pt(_gc_timer, ref_processor()->num_queues());
     const ReferenceProcessorStats& stats =
       ref_processor()->process_discovered_references(
         is_alive_closure(), mark_and_push_closure(), follow_stack_closure(), NULL, &pt);
@@ -563,7 +565,7 @@
     CodeCache::do_unloading(is_alive_closure(), purged_class);
 
     // Prune dead klasses from subklass/sibling/implementor lists.
-    Klass::clean_weak_klass_links();
+    Klass::clean_weak_klass_links(purged_class);
   }
 
   {
--- a/src/hotspot/share/gc/parallel/psMarkSweep.hpp	Wed May 02 22:11:35 2018 -0700
+++ b/src/hotspot/share/gc/parallel/psMarkSweep.hpp	Fri May 04 08:50:01 2018 -0700
@@ -27,6 +27,7 @@
 
 #include "gc/serial/markSweep.hpp"
 #include "gc/shared/collectorCounters.hpp"
+#include "gc/shared/referenceProcessor.hpp"
 #include "utilities/stack.hpp"
 
 class PSAdaptiveSizePolicy;
@@ -39,6 +40,8 @@
   static jlong               _time_of_last_gc;   // ms
   static CollectorCounters*  _counters;
 
+  static SpanSubjectToDiscoveryClosure _span_based_discoverer;
+
   // Closure accessors
   static OopClosure* mark_and_push_closure()   { return &MarkSweep::mark_and_push_closure; }
   static VoidClosure* follow_stack_closure()   { return &MarkSweep::follow_stack_closure; }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/share/gc/parallel/psMarkSweepProxy.hpp	Fri May 04 08:50:01 2018 -0700
@@ -0,0 +1,53 @@
+/*
+ * 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.
+ *
+ */
+
+#ifndef SHARE_GC_PARALLEL_PSMARKSWEEPPROXY_HPP
+#define SHARE_GC_PARALLEL_PSMARKSWEEPPROXY_HPP
+
+#include "utilities/macros.hpp"
+#if INCLUDE_SERIALGC
+#include "gc/parallel/psMarkSweep.hpp"
+#endif
+
+#if INCLUDE_SERIALGC
+namespace PSMarkSweepProxy {
+  inline void initialize()                              { PSMarkSweep::initialize(); }
+  inline void invoke(bool maximum_heap_compaction)      { PSMarkSweep::invoke(maximum_heap_compaction); }
+  inline bool invoke_no_policy(bool clear_all_softrefs) { return PSMarkSweep::invoke_no_policy(clear_all_softrefs); }
+  inline jlong millis_since_last_gc()                   { return PSMarkSweep::millis_since_last_gc(); }
+  inline elapsedTimer* accumulated_time()               { return PSMarkSweep::accumulated_time(); }
+  inline uint total_invocations()                       { return PSMarkSweep::total_invocations(); }
+};
+#else
+namespace PSMarkSweepProxy {
+  inline void initialize()                { fatal("Serial GC excluded from build"); }
+  inline void invoke(bool)                { fatal("Serial GC excluded from build"); }
+  inline bool invoke_no_policy(bool)      { fatal("Serial GC excluded from build"); return false;}
+  inline jlong millis_since_last_gc()     { fatal("Serial GC excluded from build"); return 0L; }
+  inline elapsedTimer* accumulated_time() { fatal("Serial GC excluded from build"); return NULL; }
+  inline uint total_invocations()         { fatal("Serial GC excluded from build"); return 0u; }
+};
+#endif
+
+#endif // SHARE_GC_PARALLEL_PSMARKSWEEPPROXY_HPP
--- a/src/hotspot/share/gc/parallel/psOldGen.cpp	Wed May 02 22:11:35 2018 -0700
+++ b/src/hotspot/share/gc/parallel/psOldGen.cpp	Fri May 04 08:50:01 2018 -0700
@@ -139,10 +139,13 @@
                              SpaceDecorator::Clear,
                              SpaceDecorator::Mangle);
 
+#if INCLUDE_SERIALGC
   _object_mark_sweep = new PSMarkSweepDecorator(_object_space, start_array(), MarkSweepDeadRatio);
 
-  if (_object_mark_sweep == NULL)
+  if (_object_mark_sweep == NULL) {
     vm_exit_during_initialization("Could not complete allocation of old generation");
+  }
+#endif // INCLUDE_SERIALGC
 
   // Update the start_array
   start_array()->set_covered_region(cmr);
@@ -163,6 +166,8 @@
   return virtual_space()->reserved_size() != 0;
 }
 
+#if INCLUDE_SERIALGC
+
 void PSOldGen::precompact() {
   ParallelScavengeHeap* heap = ParallelScavengeHeap::heap();
 
@@ -183,6 +188,8 @@
   object_mark_sweep()->compact(ZapUnusedHeapArea);
 }
 
+#endif // INCLUDE_SERIALGC
+
 size_t PSOldGen::contiguous_available() const {
   return object_space()->free_in_bytes() + virtual_space()->uncommitted_size();
 }
--- a/src/hotspot/share/gc/parallel/psOldGen.hpp	Wed May 02 22:11:35 2018 -0700
+++ b/src/hotspot/share/gc/parallel/psOldGen.hpp	Fri May 04 08:50:01 2018 -0700
@@ -45,7 +45,9 @@
   PSVirtualSpace*          _virtual_space;     // Controls mapping and unmapping of virtual mem
   ObjectStartArray         _start_array;       // Keeps track of where objects start in a 512b block
   MutableSpace*            _object_space;      // Where all the objects live
+#if INCLUDE_SERIALGC
   PSMarkSweepDecorator*    _object_mark_sweep; // The mark sweep view of _object_space
+#endif
   const char* const        _name;              // Name of this generation.
 
   // Performance Counters
@@ -150,17 +152,21 @@
   }
 
   MutableSpace*         object_space() const      { return _object_space; }
+#if INCLUDE_SERIALGC
   PSMarkSweepDecorator* object_mark_sweep() const { return _object_mark_sweep; }
+#endif
   ObjectStartArray*     start_array()             { return &_start_array; }
   PSVirtualSpace*       virtual_space() const     { return _virtual_space;}
 
   // Has the generation been successfully allocated?
   bool is_allocated();
 
+#if INCLUDE_SERIALGC
   // MarkSweep methods
   virtual void precompact();
   void adjust_pointers();
   void compact();
+#endif
 
   // Size info
   size_t capacity_in_bytes() const        { return object_space()->capacity_in_bytes(); }
--- a/src/hotspot/share/gc/parallel/psParallelCompact.cpp	Wed May 02 22:11:35 2018 -0700
+++ b/src/hotspot/share/gc/parallel/psParallelCompact.cpp	Fri May 04 08:50:01 2018 -0700
@@ -34,8 +34,6 @@
 #include "gc/parallel/pcTasks.hpp"
 #include "gc/parallel/psAdaptiveSizePolicy.hpp"
 #include "gc/parallel/psCompactionManager.inline.hpp"
-#include "gc/parallel/psMarkSweep.hpp"
-#include "gc/parallel/psMarkSweepDecorator.hpp"
 #include "gc/parallel/psOldGen.hpp"
 #include "gc/parallel/psParallelCompact.inline.hpp"
 #include "gc/parallel/psPromotionManager.inline.hpp"
@@ -72,6 +70,7 @@
 #include "utilities/debug.hpp"
 #include "utilities/events.hpp"
 #include "utilities/formatBuffer.hpp"
+#include "utilities/macros.hpp"
 #include "utilities/stack.inline.hpp"
 
 #include <math.h>
@@ -117,6 +116,7 @@
 
 SpaceInfo PSParallelCompact::_space_info[PSParallelCompact::last_space_id];
 
+SpanSubjectToDiscoveryClosure PSParallelCompact::_span_based_discoverer;
 ReferenceProcessor* PSParallelCompact::_ref_processor = NULL;
 
 double PSParallelCompact::_dwl_mean;
@@ -843,14 +843,14 @@
 
 void PSParallelCompact::post_initialize() {
   ParallelScavengeHeap* heap = ParallelScavengeHeap::heap();
-  MemRegion mr = heap->reserved_region();
+  _span_based_discoverer.set_span(heap->reserved_region());
   _ref_processor =
-    new ReferenceProcessor(mr,            // span
+    new ReferenceProcessor(&_span_based_discoverer,
                            ParallelRefProcEnabled && (ParallelGCThreads > 1), // mt processing
-                           ParallelGCThreads, // mt processing degree
-                           true,              // mt discovery
-                           ParallelGCThreads, // mt discovery degree
-                           true,              // atomic_discovery
+                           ParallelGCThreads,   // mt processing degree
+                           true,                // mt discovery
+                           ParallelGCThreads,   // mt discovery degree
+                           true,                // atomic_discovery
                            &_is_alive_closure); // non-header is alive closure
   _counters = new CollectorCounters("PSParallelCompact", 1);
 
@@ -1038,7 +1038,7 @@
   DerivedPointerTable::update_pointers();
 #endif
 
-  ReferenceProcessorPhaseTimes pt(&_gc_timer, ref_processor()->num_q());
+  ReferenceProcessorPhaseTimes pt(&_gc_timer, ref_processor()->num_queues());
 
   ref_processor()->enqueue_discovered_references(NULL, &pt);
 
@@ -2105,7 +2105,7 @@
     GCTraceTime(Debug, gc, phases) tm("Reference Processing", &_gc_timer);
 
     ReferenceProcessorStats stats;
-    ReferenceProcessorPhaseTimes pt(&_gc_timer, ref_processor()->num_q());
+    ReferenceProcessorPhaseTimes pt(&_gc_timer, ref_processor()->num_queues());
     if (ref_processor()->processing_is_mt()) {
       RefProcTaskExecutor task_executor;
       stats = ref_processor()->process_discovered_references(
@@ -2139,7 +2139,7 @@
     CodeCache::do_unloading(is_alive_closure(), purged_class);
 
     // Prune dead klasses from subklass/sibling/implementor lists.
-    Klass::clean_weak_klass_links();
+    Klass::clean_weak_klass_links(purged_class);
   }
 
   {
--- a/src/hotspot/share/gc/parallel/psParallelCompact.hpp	Wed May 02 22:11:35 2018 -0700
+++ b/src/hotspot/share/gc/parallel/psParallelCompact.hpp	Fri May 04 08:50:01 2018 -0700
@@ -968,6 +968,7 @@
   static SpaceInfo            _space_info[last_space_id];
 
   // Reference processing (used in ...follow_contents)
+  static SpanSubjectToDiscoveryClosure  _span_based_discoverer;
   static ReferenceProcessor*  _ref_processor;
 
   // Values computed at initialization and used by dead_wood_limiter().
--- a/src/hotspot/share/gc/parallel/psScavenge.cpp	Wed May 02 22:11:35 2018 -0700
+++ b/src/hotspot/share/gc/parallel/psScavenge.cpp	Fri May 04 08:50:01 2018 -0700
@@ -28,7 +28,7 @@
 #include "gc/parallel/gcTaskManager.hpp"
 #include "gc/parallel/parallelScavengeHeap.hpp"
 #include "gc/parallel/psAdaptiveSizePolicy.hpp"
-#include "gc/parallel/psMarkSweep.hpp"
+#include "gc/parallel/psMarkSweepProxy.hpp"
 #include "gc/parallel/psParallelCompact.inline.hpp"
 #include "gc/parallel/psScavenge.inline.hpp"
 #include "gc/parallel/psTasks.hpp"
@@ -58,18 +58,19 @@
 #include "services/memoryService.hpp"
 #include "utilities/stack.inline.hpp"
 
-HeapWord*                  PSScavenge::_to_space_top_before_gc = NULL;
-int                        PSScavenge::_consecutive_skipped_scavenges = 0;
-ReferenceProcessor*        PSScavenge::_ref_processor = NULL;
-PSCardTable*               PSScavenge::_card_table = NULL;
-bool                       PSScavenge::_survivor_overflow = false;
-uint                       PSScavenge::_tenuring_threshold = 0;
-HeapWord*                  PSScavenge::_young_generation_boundary = NULL;
-uintptr_t                  PSScavenge::_young_generation_boundary_compressed = 0;
-elapsedTimer               PSScavenge::_accumulated_time;
-STWGCTimer                 PSScavenge::_gc_timer;
-ParallelScavengeTracer     PSScavenge::_gc_tracer;
-CollectorCounters*         PSScavenge::_counters = NULL;
+HeapWord*                     PSScavenge::_to_space_top_before_gc = NULL;
+int                           PSScavenge::_consecutive_skipped_scavenges = 0;
+SpanSubjectToDiscoveryClosure PSScavenge::_span_based_discoverer;
+ReferenceProcessor*           PSScavenge::_ref_processor = NULL;
+PSCardTable*                  PSScavenge::_card_table = NULL;
+bool                          PSScavenge::_survivor_overflow = false;
+uint                          PSScavenge::_tenuring_threshold = 0;
+HeapWord*                     PSScavenge::_young_generation_boundary = NULL;
+uintptr_t                     PSScavenge::_young_generation_boundary_compressed = 0;
+elapsedTimer                  PSScavenge::_accumulated_time;
+STWGCTimer                    PSScavenge::_gc_timer;
+ParallelScavengeTracer        PSScavenge::_gc_tracer;
+CollectorCounters*            PSScavenge::_counters = NULL;
 
 // Define before use
 class PSIsAliveClosure: public BoolObjectClosure {
@@ -234,7 +235,7 @@
     if (UseParallelOldGC) {
       full_gc_done = PSParallelCompact::invoke_no_policy(clear_all_softrefs);
     } else {
-      full_gc_done = PSMarkSweep::invoke_no_policy(clear_all_softrefs);
+      full_gc_done = PSMarkSweepProxy::invoke_no_policy(clear_all_softrefs);
     }
   }
 
@@ -416,7 +417,7 @@
       PSKeepAliveClosure keep_alive(promotion_manager);
       PSEvacuateFollowersClosure evac_followers(promotion_manager);
       ReferenceProcessorStats stats;
-      ReferenceProcessorPhaseTimes pt(&_gc_timer, reference_processor()->num_q());
+      ReferenceProcessorPhaseTimes pt(&_gc_timer, reference_processor()->num_queues());
       if (reference_processor()->processing_is_mt()) {
         PSRefProcTaskExecutor task_executor;
         stats = reference_processor()->process_discovered_references(
@@ -766,10 +767,9 @@
   set_young_generation_boundary(young_gen->eden_space()->bottom());
 
   // Initialize ref handling object for scavenging.
-  MemRegion mr = young_gen->reserved();
-
+  _span_based_discoverer.set_span(young_gen->reserved());
   _ref_processor =
-    new ReferenceProcessor(mr,                         // span
+    new ReferenceProcessor(&_span_based_discoverer,
                            ParallelRefProcEnabled && (ParallelGCThreads > 1), // mt processing
                            ParallelGCThreads,          // mt processing degree
                            true,                       // mt discovery
--- a/src/hotspot/share/gc/parallel/psScavenge.hpp	Wed May 02 22:11:35 2018 -0700
+++ b/src/hotspot/share/gc/parallel/psScavenge.hpp	Fri May 04 08:50:01 2018 -0700
@@ -65,14 +65,15 @@
 
  protected:
   // Flags/counters
-  static ReferenceProcessor*  _ref_processor;        // Reference processor for scavenging.
-  static PSIsAliveClosure     _is_alive_closure;     // Closure used for reference processing
-  static PSCardTable*         _card_table;           // We cache the card table for fast access.
-  static bool                 _survivor_overflow;    // Overflow this collection
-  static uint                 _tenuring_threshold;   // tenuring threshold for next scavenge
-  static elapsedTimer         _accumulated_time;     // total time spent on scavenge
-  static STWGCTimer           _gc_timer;             // GC time book keeper
-  static ParallelScavengeTracer _gc_tracer;          // GC tracing
+  static SpanSubjectToDiscoveryClosure _span_based_discoverer;
+  static ReferenceProcessor*           _ref_processor;        // Reference processor for scavenging.
+  static PSIsAliveClosure              _is_alive_closure;     // Closure used for reference processing
+  static PSCardTable*                  _card_table;           // We cache the card table for fast access.
+  static bool                          _survivor_overflow;    // Overflow this collection
+  static uint                          _tenuring_threshold;   // tenuring threshold for next scavenge
+  static elapsedTimer                  _accumulated_time;     // total time spent on scavenge
+  static STWGCTimer                    _gc_timer;             // GC time book keeper
+  static ParallelScavengeTracer        _gc_tracer;          // GC tracing
   // The lowest address possible for the young_gen.
   // This is used to decide if an oop should be scavenged,
   // cards should be marked, etc.
@@ -102,6 +103,9 @@
   // Performance Counters
   static CollectorCounters* counters()           { return _counters; }
 
+  static void set_subject_to_discovery_span(MemRegion mr) {
+    _span_based_discoverer.set_span(mr);
+  }
   // Used by scavenge_contents && psMarkSweep
   static ReferenceProcessor* const reference_processor() {
     assert(_ref_processor != NULL, "Sanity");
--- a/src/hotspot/share/gc/parallel/psTasks.cpp	Wed May 02 22:11:35 2018 -0700
+++ b/src/hotspot/share/gc/parallel/psTasks.cpp	Fri May 04 08:50:01 2018 -0700
@@ -27,7 +27,6 @@
 #include "classfile/systemDictionary.hpp"
 #include "code/codeCache.hpp"
 #include "gc/parallel/gcTaskManager.hpp"
-#include "gc/parallel/psMarkSweep.hpp"
 #include "gc/parallel/psCardTable.hpp"
 #include "gc/parallel/psPromotionManager.hpp"
 #include "gc/parallel/psPromotionManager.inline.hpp"
--- a/src/hotspot/share/gc/parallel/psYoungGen.cpp	Wed May 02 22:11:35 2018 -0700
+++ b/src/hotspot/share/gc/parallel/psYoungGen.cpp	Fri May 04 08:50:01 2018 -0700
@@ -730,6 +730,8 @@
   to_space()->object_iterate(blk);
 }
 
+#if INCLUDE_SERIALGC
+
 void PSYoungGen::precompact() {
   eden_mark_sweep()->precompact();
   from_mark_sweep()->precompact();
@@ -749,6 +751,8 @@
   to_mark_sweep()->compact(false);
 }
 
+#endif // INCLUDE_SERIALGC
+
 void PSYoungGen::print() const { print_on(tty); }
 void PSYoungGen::print_on(outputStream* st) const {
   st->print(" %-15s", "PSYoungGen");
@@ -839,7 +843,7 @@
 void PSYoungGen::reset_survivors_after_shrink() {
   _reserved = MemRegion((HeapWord*)virtual_space()->low_boundary(),
                         (HeapWord*)virtual_space()->high_boundary());
-  PSScavenge::reference_processor()->set_span(_reserved);
+  PSScavenge::set_subject_to_discovery_span(_reserved);
 
   MutableSpace* space_shrinking = NULL;
   if (from_space()->end() > to_space()->end()) {
--- a/src/hotspot/share/gc/parallel/psYoungGen.hpp	Wed May 02 22:11:35 2018 -0700
+++ b/src/hotspot/share/gc/parallel/psYoungGen.hpp	Fri May 04 08:50:01 2018 -0700
@@ -123,9 +123,11 @@
   PSMarkSweepDecorator* from_mark_sweep() const    { return _from_mark_sweep; }
   PSMarkSweepDecorator* to_mark_sweep() const      { return _to_mark_sweep;   }
 
+#if INCLUDE_SERIALGC
   void precompact();
   void adjust_pointers();
   void compact();
+#endif
 
   // Called during/after GC
   void swap_spaces();
--- a/src/hotspot/share/gc/parallel/vmPSOperations.cpp	Wed May 02 22:11:35 2018 -0700
+++ b/src/hotspot/share/gc/parallel/vmPSOperations.cpp	Fri May 04 08:50:01 2018 -0700
@@ -24,7 +24,6 @@
 
 #include "precompiled.hpp"
 #include "gc/parallel/parallelScavengeHeap.inline.hpp"
-#include "gc/parallel/psMarkSweep.hpp"
 #include "gc/parallel/psScavenge.hpp"
 #include "gc/parallel/vmPSOperations.hpp"
 #include "gc/shared/gcLocker.hpp"
--- a/src/hotspot/share/gc/serial/defNewGeneration.cpp	Wed May 02 22:11:35 2018 -0700
+++ b/src/hotspot/share/gc/serial/defNewGeneration.cpp	Fri May 04 08:50:01 2018 -0700
@@ -56,7 +56,7 @@
 #include "utilities/copy.hpp"
 #include "utilities/globalDefinitions.hpp"
 #include "utilities/stack.inline.hpp"
-#if INCLUDE_ALL_GCS
+#if INCLUDE_CMSGC
 #include "gc/cms/parOopClosures.hpp"
 #endif
 
@@ -646,7 +646,7 @@
   FastKeepAliveClosure keep_alive(this, &scan_weak_ref);
   ReferenceProcessor* rp = ref_processor();
   rp->setup_policy(clear_all_soft_refs);
-  ReferenceProcessorPhaseTimes pt(_gc_timer, rp->num_q());
+  ReferenceProcessorPhaseTimes pt(_gc_timer, rp->num_queues());
   const ReferenceProcessorStats& stats =
   rp->process_discovered_references(&is_alive, &keep_alive, &evacuate_followers,
                                     NULL, &pt);
@@ -1006,7 +1006,7 @@
   // have to use it here, as well.
   HeapWord* result = eden()->par_allocate(word_size);
   if (result != NULL) {
-#if INCLUDE_ALL_GCS
+#if INCLUDE_CMSGC
     if (CMSEdenChunksRecordAlways && _old_gen != NULL) {
       _old_gen->sample_eden_chunk();
     }
@@ -1024,7 +1024,7 @@
 HeapWord* DefNewGeneration::par_allocate(size_t word_size,
                                          bool is_tlab) {
   HeapWord* res = eden()->par_allocate(word_size);
-#if INCLUDE_ALL_GCS
+#if INCLUDE_CMSGC
   if (CMSEdenChunksRecordAlways && _old_gen != NULL) {
     _old_gen->sample_eden_chunk();
   }
--- a/src/hotspot/share/gc/serial/genMarkSweep.cpp	Wed May 02 22:11:35 2018 -0700
+++ b/src/hotspot/share/gc/serial/genMarkSweep.cpp	Fri May 04 08:50:01 2018 -0700
@@ -208,7 +208,7 @@
     GCTraceTime(Debug, gc, phases) tm_m("Reference Processing", gc_timer());
 
     ref_processor()->setup_policy(clear_all_softrefs);
-    ReferenceProcessorPhaseTimes pt(_gc_timer, ref_processor()->num_q());
+    ReferenceProcessorPhaseTimes pt(_gc_timer, ref_processor()->num_queues());
     const ReferenceProcessorStats& stats =
       ref_processor()->process_discovered_references(
         &is_alive, &keep_alive, &follow_stack_closure, NULL, &pt);
@@ -234,7 +234,7 @@
     CodeCache::do_unloading(&is_alive, purged_class);
 
     // Prune dead klasses from subklass/sibling/implementor lists.
-    Klass::clean_weak_klass_links();
+    Klass::clean_weak_klass_links(purged_class);
   }
 
   {
--- a/src/hotspot/share/gc/serial/tenuredGeneration.cpp	Wed May 02 22:11:35 2018 -0700
+++ b/src/hotspot/share/gc/serial/tenuredGeneration.cpp	Fri May 04 08:50:01 2018 -0700
@@ -39,7 +39,7 @@
 #include "oops/oop.inline.hpp"
 #include "runtime/java.hpp"
 #include "utilities/macros.hpp"
-#if INCLUDE_ALL_GCS
+#if INCLUDE_CMSGC
 #include "gc/cms/parOopClosures.hpp"
 #endif
 
--- a/src/hotspot/share/gc/serial/vmStructs_serial.hpp	Wed May 02 22:11:35 2018 -0700
+++ b/src/hotspot/share/gc/serial/vmStructs_serial.hpp	Fri May 04 08:50:01 2018 -0700
@@ -32,7 +32,14 @@
                             volatile_nonstatic_field,                         \
                             static_field)                                     \
   nonstatic_field(TenuredGeneration, _min_heap_delta_bytes, size_t)           \
-  nonstatic_field(TenuredGeneration, _the_space,            ContiguousSpace*)
+  nonstatic_field(TenuredGeneration, _the_space,            ContiguousSpace*) \
+                                                                              \
+  nonstatic_field(DefNewGeneration,  _old_gen,              Generation*)      \
+  nonstatic_field(DefNewGeneration,  _tenuring_threshold,   uint)             \
+  nonstatic_field(DefNewGeneration,  _age_table,            AgeTable)         \
+  nonstatic_field(DefNewGeneration,  _eden_space,           ContiguousSpace*) \
+  nonstatic_field(DefNewGeneration,  _from_space,           ContiguousSpace*) \
+  nonstatic_field(DefNewGeneration,  _to_space,             ContiguousSpace*)
 
 #define VM_TYPES_SERIALGC(declare_type,                                       \
                           declare_toplevel_type,                              \
@@ -41,6 +48,8 @@
   declare_type(TenuredGeneration,            CardGeneration)                  \
   declare_type(TenuredSpace,                 OffsetTableContigSpace)          \
                                                                               \
+  declare_type(DefNewGeneration,             Generation)                      \
+                                                                              \
   declare_toplevel_type(TenuredGeneration*)
 
 #define VM_INT_CONSTANTS_SERIALGC(declare_constant,                           \
--- a/src/hotspot/share/gc/shared/barrierSetConfig.hpp	Wed May 02 22:11:35 2018 -0700
+++ b/src/hotspot/share/gc/shared/barrierSetConfig.hpp	Fri May 04 08:50:01 2018 -0700
@@ -27,17 +27,10 @@
 
 #include "utilities/macros.hpp"
 
-#if INCLUDE_ALL_GCS
-#define FOR_EACH_CONCRETE_INCLUDE_ALL_GC_BARRIER_SET_DO(f) \
-  f(G1BarrierSet)
-#else
-#define FOR_EACH_CONCRETE_INCLUDE_ALL_GC_BARRIER_SET_DO(f)
-#endif
-
 // Do something for each concrete barrier set part of the build.
 #define FOR_EACH_CONCRETE_BARRIER_SET_DO(f)          \
   f(CardTableBarrierSet)                             \
-  FOR_EACH_CONCRETE_INCLUDE_ALL_GC_BARRIER_SET_DO(f)
+  G1GC_ONLY(f(G1BarrierSet))
 
 #define FOR_EACH_ABSTRACT_BARRIER_SET_DO(f)          \
   f(ModRef)
--- a/src/hotspot/share/gc/shared/barrierSetConfig.inline.hpp	Wed May 02 22:11:35 2018 -0700
+++ b/src/hotspot/share/gc/shared/barrierSetConfig.inline.hpp	Fri May 04 08:50:01 2018 -0700
@@ -30,7 +30,7 @@
 #include "gc/shared/modRefBarrierSet.inline.hpp"
 #include "gc/shared/cardTableBarrierSet.inline.hpp"
 
-#if INCLUDE_ALL_GCS
+#if INCLUDE_G1GC
 #include "gc/g1/g1BarrierSet.inline.hpp" // G1 support
 #endif
 
--- a/src/hotspot/share/gc/shared/blockOffsetTable.hpp	Wed May 02 22:11:35 2018 -0700
+++ b/src/hotspot/share/gc/shared/blockOffsetTable.hpp	Fri May 04 08:50:01 2018 -0700
@@ -153,14 +153,14 @@
 
   void fill_range(size_t start, size_t num_cards, u_char offset) {
     void* start_ptr = &_offset_array[start];
-#if INCLUDE_ALL_GCS
     // If collector is concurrent, special handling may be needed.
-    assert(!UseG1GC, "Shouldn't be here when using G1");
+    G1GC_ONLY(assert(!UseG1GC, "Shouldn't be here when using G1");)
+#if INCLUDE_CMSGC
     if (UseConcMarkSweepGC) {
       memset_with_concurrent_readers(start_ptr, offset, num_cards);
       return;
     }
-#endif // INCLUDE_ALL_GCS
+#endif // INCLUDE_CMSGC
     memset(start_ptr, offset, num_cards);
   }
 
--- a/src/hotspot/share/gc/shared/cardGeneration.cpp	Wed May 02 22:11:35 2018 -0700
+++ b/src/hotspot/share/gc/shared/cardGeneration.cpp	Fri May 04 08:50:01 2018 -0700
@@ -208,7 +208,7 @@
 
     const size_t free_after_gc = free();
     const double free_percentage = ((double)free_after_gc) / capacity_after_gc;
-    log_trace(gc, heap)("TenuredGeneration::compute_new_size:");
+    log_trace(gc, heap)("CardGeneration::compute_new_size:");
     log_trace(gc, heap)("    minimum_free_percentage: %6.2f  maximum_used_percentage: %6.2f",
                   minimum_free_percentage,
                   maximum_used_percentage);
--- a/src/hotspot/share/gc/shared/cardTableBarrierSet.cpp	Wed May 02 22:11:35 2018 -0700
+++ b/src/hotspot/share/gc/shared/cardTableBarrierSet.cpp	Fri May 04 08:50:01 2018 -0700
@@ -126,7 +126,7 @@
 // that specific collector in mind, and the documentation above suitably
 // extended and updated.
 void CardTableBarrierSet::on_slowpath_allocation_exit(JavaThread* thread, oop new_obj) {
-#if defined(COMPILER2) || INCLUDE_JVMCI
+#if COMPILER2_OR_JVMCI
   if (!ReduceInitialCardMarks) {
     return;
   }
@@ -148,13 +148,13 @@
       invalidate(mr);
     }
   }
-#endif // COMPILER2 || JVMCI
+#endif // COMPILER2_OR_JVMCI
 }
 
 void CardTableBarrierSet::initialize_deferred_card_mark_barriers() {
   // Used for ReduceInitialCardMarks (when COMPILER2 or JVMCI is used);
   // otherwise remains unused.
-#if defined(COMPILER2) || INCLUDE_JVMCI
+#if COMPILER2_OR_JVMCI
   _defer_initial_card_mark = is_server_compilation_mode_vm() && ReduceInitialCardMarks && can_elide_tlab_store_barriers()
                              && (DeferInitialCardMark || card_mark_must_follow_store());
 #else
@@ -163,7 +163,7 @@
 }
 
 void CardTableBarrierSet::flush_deferred_card_mark_barrier(JavaThread* thread) {
-#if defined(COMPILER2) || INCLUDE_JVMCI
+#if COMPILER2_OR_JVMCI
   MemRegion deferred = thread->deferred_card_mark();
   if (!deferred.is_empty()) {
     assert(_defer_initial_card_mark, "Otherwise should be empty");
--- a/src/hotspot/share/gc/shared/cardTableRS.cpp	Wed May 02 22:11:35 2018 -0700
+++ b/src/hotspot/share/gc/shared/cardTableRS.cpp	Fri May 04 08:50:01 2018 -0700
@@ -25,6 +25,7 @@
 #include "precompiled.hpp"
 #include "gc/shared/cardTableRS.hpp"
 #include "gc/shared/genCollectedHeap.hpp"
+#include "gc/shared/genOopClosures.hpp"
 #include "gc/shared/generation.hpp"
 #include "gc/shared/space.inline.hpp"
 #include "memory/allocation.inline.hpp"
--- a/src/hotspot/share/gc/shared/collectedHeap.inline.hpp	Wed May 02 22:11:35 2018 -0700
+++ b/src/hotspot/share/gc/shared/collectedHeap.inline.hpp	Fri May 04 08:50:01 2018 -0700
@@ -45,13 +45,13 @@
                                                  HeapWord* obj_ptr) {
   post_allocation_setup_no_klass_install(klass, obj_ptr);
   oop obj = (oop)obj_ptr;
-#if ! INCLUDE_ALL_GCS
-  obj->set_klass(klass);
-#else
+#if (INCLUDE_G1GC || INCLUDE_CMSGC)
   // Need a release store to ensure array/class length, mark word, and
   // object zeroing are visible before setting the klass non-NULL, for
   // concurrent collectors.
   obj->release_set_klass(klass);
+#else
+  obj->set_klass(klass);
 #endif
 }
 
--- a/src/hotspot/share/gc/shared/collectorPolicy.hpp	Wed May 02 22:11:35 2018 -0700
+++ b/src/hotspot/share/gc/shared/collectorPolicy.hpp	Fri May 04 08:50:01 2018 -0700
@@ -48,11 +48,8 @@
 // Forward declarations.
 class GenCollectorPolicy;
 class AdaptiveSizePolicy;
-#if INCLUDE_ALL_GCS
 class ConcurrentMarkSweepPolicy;
 class G1CollectorPolicy;
-#endif // INCLUDE_ALL_GCS
-
 class MarkSweepPolicy;
 
 class CollectorPolicy : public CHeapObj<mtGC> {
--- a/src/hotspot/share/gc/shared/gcConfig.cpp	Wed May 02 22:11:35 2018 -0700
+++ b/src/hotspot/share/gc/shared/gcConfig.cpp	Fri May 04 08:50:01 2018 -0700
@@ -23,16 +23,23 @@
  */
 
 #include "precompiled.hpp"
-#include "gc/serial/serialArguments.hpp"
 #include "gc/shared/gcConfig.hpp"
+#include "runtime/globals_extension.hpp"
 #include "runtime/java.hpp"
 #include "runtime/os.hpp"
 #include "utilities/macros.hpp"
-#if INCLUDE_ALL_GCS
+#if INCLUDE_CMSGC
+#include "gc/cms/cmsArguments.hpp"
+#endif
+#if INCLUDE_G1GC
+#include "gc/g1/g1Arguments.hpp"
+#endif
+#if INCLUDE_PARALLELGC
 #include "gc/parallel/parallelArguments.hpp"
-#include "gc/cms/cmsArguments.hpp"
-#include "gc/g1/g1Arguments.hpp"
-#endif // INCLUDE_ALL_GCS
+#endif
+#if INCLUDE_SERIALGC
+#include "gc/serial/serialArguments.hpp"
+#endif
 
 struct SupportedGC {
   bool&               _flag;
@@ -44,23 +51,19 @@
       _flag(flag), _name(name), _arguments(arguments), _hs_err_name(hs_err_name) {}
 };
 
-static SerialArguments   serialArguments;
-#if INCLUDE_ALL_GCS
-static ParallelArguments parallelArguments;
-static CMSArguments      cmsArguments;
-static G1Arguments       g1Arguments;
-#endif // INCLUDE_ALL_GCS
+     CMSGC_ONLY(static CMSArguments      cmsArguments;)
+      G1GC_ONLY(static G1Arguments       g1Arguments;)
+PARALLELGC_ONLY(static ParallelArguments parallelArguments;)
+  SERIALGC_ONLY(static SerialArguments   serialArguments;)
 
 // Table of supported GCs, for translating between command
 // line flag, CollectedHeap::Name and GCArguments instance.
 static const SupportedGC SupportedGCs[] = {
-  SupportedGC(UseSerialGC,        CollectedHeap::Serial,   serialArguments,   "serial gc"),
-#if INCLUDE_ALL_GCS
-  SupportedGC(UseParallelGC,      CollectedHeap::Parallel, parallelArguments, "parallel gc"),
-  SupportedGC(UseParallelOldGC,   CollectedHeap::Parallel, parallelArguments, "parallel gc"),
-  SupportedGC(UseConcMarkSweepGC, CollectedHeap::CMS,      cmsArguments,      "concurrent mark sweep gc"),
-  SupportedGC(UseG1GC,            CollectedHeap::G1,       g1Arguments,       "g1 gc"),
-#endif // INCLUDE_ALL_GCS
+       CMSGC_ONLY_ARG(SupportedGC(UseConcMarkSweepGC, CollectedHeap::CMS,      cmsArguments,      "concurrent mark sweep gc"))
+        G1GC_ONLY_ARG(SupportedGC(UseG1GC,            CollectedHeap::G1,       g1Arguments,       "g1 gc"))
+  PARALLELGC_ONLY_ARG(SupportedGC(UseParallelGC,      CollectedHeap::Parallel, parallelArguments, "parallel gc"))
+  PARALLELGC_ONLY_ARG(SupportedGC(UseParallelOldGC,   CollectedHeap::Parallel, parallelArguments, "parallel gc"))
+    SERIALGC_ONLY_ARG(SupportedGC(UseSerialGC,        CollectedHeap::Serial,   serialArguments,   "serial gc"))
 };
 
 #define FOR_EACH_SUPPORTED_GC(var) \
@@ -70,19 +73,25 @@
 bool GCConfig::_gc_selected_ergonomically = false;
 
 void GCConfig::select_gc_ergonomically() {
-#if INCLUDE_ALL_GCS
   if (os::is_server_class_machine()) {
+#if INCLUDE_G1GC
     FLAG_SET_ERGO_IF_DEFAULT(bool, UseG1GC, true);
+#elif INCLUDE_PARALLELGC
+    FLAG_SET_ERGO_IF_DEFAULT(bool, UseParallelGC, true);
+#elif INCLUDE_SERIALGC
+    FLAG_SET_ERGO_IF_DEFAULT(bool, UseSerialGC, true);
+#endif
   } else {
+#if INCLUDE_SERIALGC
     FLAG_SET_ERGO_IF_DEFAULT(bool, UseSerialGC, true);
+#endif
   }
-#else
-  UNSUPPORTED_OPTION(UseG1GC);
-  UNSUPPORTED_OPTION(UseParallelGC);
-  UNSUPPORTED_OPTION(UseParallelOldGC);
-  UNSUPPORTED_OPTION(UseConcMarkSweepGC);
-  FLAG_SET_ERGO_IF_DEFAULT(bool, UseSerialGC, true);
-#endif // INCLUDE_ALL_GCS
+
+  NOT_CMSGC(     UNSUPPORTED_OPTION(UseConcMarkSweepGC));
+  NOT_G1GC(      UNSUPPORTED_OPTION(UseG1GC);)
+  NOT_PARALLELGC(UNSUPPORTED_OPTION(UseParallelGC);)
+  NOT_PARALLELGC(UNSUPPORTED_OPTION(UseParallelOldGC));
+  NOT_SERIALGC(  UNSUPPORTED_OPTION(UseSerialGC);)
 }
 
 bool GCConfig::is_no_gc_selected() {
@@ -128,17 +137,25 @@
     _gc_selected_ergonomically = true;
   }
 
-  if (is_exactly_one_gc_selected()) {
-    // Exacly one GC selected
-    FOR_EACH_SUPPORTED_GC(gc) {
-      if (gc->_flag) {
-        return &gc->_arguments;
-      }
+  if (!is_exactly_one_gc_selected()) {
+    // More than one GC selected
+    vm_exit_during_initialization("Multiple garbage collectors selected", NULL);
+  }
+
+#if INCLUDE_PARALLELGC && !INCLUDE_SERIALGC
+  if (FLAG_IS_CMDLINE(UseParallelOldGC) && !UseParallelOldGC) {
+    vm_exit_during_initialization("This JVM build only supports UseParallelOldGC as the full GC");
+  }
+#endif
+
+  // Exactly one GC selected
+  FOR_EACH_SUPPORTED_GC(gc) {
+    if (gc->_flag) {
+      return &gc->_arguments;
     }
   }
 
-  // More than one GC selected
-  vm_exit_during_initialization("Multiple garbage collectors selected", NULL);
+  fatal("Should have found the selected GC");
 
   return NULL;
 }
--- a/src/hotspot/share/gc/shared/gcTrace.cpp	Wed May 02 22:11:35 2018 -0700
+++ b/src/hotspot/share/gc/shared/gcTrace.cpp	Fri May 04 08:50:01 2018 -0700
@@ -36,7 +36,7 @@
 #include "utilities/globalDefinitions.hpp"
 #include "utilities/macros.hpp"
 #include "utilities/ticks.inline.hpp"
-#if INCLUDE_ALL_GCS
+#if INCLUDE_G1GC
 #include "gc/g1/evacuationInfo.hpp"
 #endif
 
@@ -184,7 +184,7 @@
   send_concurrent_mode_failure_event();
 }
 
-#if INCLUDE_ALL_GCS
+#if INCLUDE_G1GC
 void G1MMUTracer::report_mmu(double time_slice_sec, double gc_time_sec, double max_time_sec) {
   send_g1_mmu_event(time_slice_sec * MILLIUNITS,
                     gc_time_sec * MILLIUNITS,
@@ -252,4 +252,4 @@
   _shared_gc_info.set_cause(cause);
 }
 
-#endif
+#endif // INCLUDE_G1GC
--- a/src/hotspot/share/gc/shared/gcTrace.hpp	Wed May 02 22:11:35 2018 -0700
+++ b/src/hotspot/share/gc/shared/gcTrace.hpp	Fri May 04 08:50:01 2018 -0700
@@ -34,7 +34,7 @@
 #include "memory/referenceType.hpp"
 #include "utilities/macros.hpp"
 #include "utilities/ticks.hpp"
-#if INCLUDE_ALL_GCS
+#if INCLUDE_G1GC
 #include "gc/g1/g1YCTypes.hpp"
 #endif
 
@@ -97,7 +97,7 @@
   void* dense_prefix() const { return _dense_prefix; }
 };
 
-#if INCLUDE_ALL_GCS
+#if INCLUDE_G1GC
 
 class G1YoungGCInfo {
   G1YCType _type;
@@ -109,7 +109,7 @@
   G1YCType type() const { return _type; }
 };
 
-#endif // INCLUDE_ALL_GCS
+#endif // INCLUDE_G1GC
 
 class GCTracer : public ResourceObj {
  protected:
@@ -232,7 +232,7 @@
   ParNewTracer() : YoungGCTracer(ParNew) {}
 };
 
-#if INCLUDE_ALL_GCS
+#if INCLUDE_G1GC
 class G1MMUTracer : public AllStatic {
   static void send_g1_mmu_event(double time_slice_ms, double gc_time_ms, double max_time_ms);
 
@@ -294,7 +294,7 @@
   G1FullGCTracer() : OldGCTracer(G1Full) {}
 };
 
-#endif
+#endif // INCLUDE_G1GC
 
 class CMSTracer : public OldGCTracer {
  public:
--- a/src/hotspot/share/gc/shared/gcTraceSend.cpp	Wed May 02 22:11:35 2018 -0700
+++ b/src/hotspot/share/gc/shared/gcTraceSend.cpp	Fri May 04 08:50:01 2018 -0700
@@ -31,11 +31,11 @@
 #include "runtime/os.hpp"
 #include "trace/traceBackend.hpp"
 #include "trace/tracing.hpp"
+#include "tracefiles/traceEventClasses.hpp"
 #include "utilities/macros.hpp"
-#if INCLUDE_ALL_GCS
+#if INCLUDE_G1GC
 #include "gc/g1/evacuationInfo.hpp"
 #include "gc/g1/g1YCTypes.hpp"
-#include "tracefiles/traceEventClasses.hpp"
 #endif
 
 // All GC dependencies against the trace framework is contained within this file.
@@ -188,7 +188,7 @@
   }
 }
 
-#if INCLUDE_ALL_GCS
+#if INCLUDE_G1GC
 void G1NewTracer::send_g1_young_gc_event() {
   EventG1GarbageCollection e(UNTIMED);
   if (e.should_commit()) {
@@ -311,7 +311,7 @@
   }
 }
 
-#endif
+#endif // INCLUDE_G1GC
 
 static TraceStructVirtualSpace to_trace_struct(const VirtualSpaceSummary& summary) {
   TraceStructVirtualSpace space;
--- a/src/hotspot/share/gc/shared/gc_globals.hpp	Wed May 02 22:11:35 2018 -0700
+++ b/src/hotspot/share/gc/shared/gc_globals.hpp	Fri May 04 08:50:01 2018 -0700
@@ -25,12 +25,18 @@
 #ifndef SHARE_GC_SHARED_GC_GLOBALS_HPP
 #define SHARE_GC_SHARED_GC_GLOBALS_HPP
 
+#include "utilities/macros.hpp"
+#if INCLUDE_CMSGC
+#include "gc/cms/cms_globals.hpp"
+#endif
+#if INCLUDE_G1GC
+#include "gc/g1/g1_globals.hpp"
+#endif
+#if INCLUDE_PARALLELGC
+#include "gc/parallel/parallel_globals.hpp"
+#endif
+#if INCLUDE_SERIALGC
 #include "gc/serial/serial_globals.hpp"
-#include "utilities/macros.hpp"
-#if INCLUDE_ALL_GCS
-#include "gc/cms/cms_globals.hpp"
-#include "gc/g1/g1_globals.hpp"
-#include "gc/parallel/parallel_globals.hpp"
 #endif
 
 #define GC_FLAGS(develop,                                                   \
@@ -48,7 +54,7 @@
                  constraint,                                                \
                  writeable)                                                 \
                                                                             \
-  ALL_GCS_ONLY(GC_CMS_FLAGS(                                                \
+  CMSGC_ONLY(GC_CMS_FLAGS(                                                  \
     develop,                                                                \
     develop_pd,                                                             \
     product,                                                                \
@@ -64,7 +70,7 @@
     constraint,                                                             \
     writeable))                                                             \
                                                                             \
-  ALL_GCS_ONLY(GC_G1_FLAGS(                                                 \
+  G1GC_ONLY(GC_G1_FLAGS(                                                    \
     develop,                                                                \
     develop_pd,                                                             \
     product,                                                                \
@@ -80,7 +86,7 @@
     constraint,                                                             \
     writeable))                                                             \
                                                                             \
-  ALL_GCS_ONLY(GC_PARALLEL_FLAGS(                                           \
+  PARALLELGC_ONLY(GC_PARALLEL_FLAGS(                                        \
     develop,                                                                \
     develop_pd,                                                             \
     product,                                                                \
@@ -96,7 +102,7 @@
     constraint,                                                             \
     writeable))                                                             \
                                                                             \
-  GC_SERIAL_FLAGS(                                                          \
+  SERIALGC_ONLY(GC_SERIAL_FLAGS(                                            \
     develop,                                                                \
     develop_pd,                                                             \
     product,                                                                \
@@ -110,7 +116,7 @@
     lp64_product,                                                           \
     range,                                                                  \
     constraint,                                                             \
-    writeable)                                                              \
+    writeable))                                                             \
                                                                             \
   /* gc */                                                                  \
                                                                             \
--- a/src/hotspot/share/gc/shared/genCollectedHeap.cpp	Wed May 02 22:11:35 2018 -0700
+++ b/src/hotspot/share/gc/shared/genCollectedHeap.cpp	Fri May 04 08:50:01 2018 -0700
@@ -30,6 +30,7 @@
 #include "classfile/vmSymbols.hpp"
 #include "code/codeCache.hpp"
 #include "code/icBuffer.hpp"
+#include "gc/serial/defNewGeneration.hpp"
 #include "gc/shared/adaptiveSizePolicy.hpp"
 #include "gc/shared/cardTableBarrierSet.hpp"
 #include "gc/shared/cardTableRS.hpp"
@@ -516,7 +517,7 @@
     }
     gen->collect(full, clear_soft_refs, size, is_tlab);
     if (!rp->enqueuing_is_done()) {
-      ReferenceProcessorPhaseTimes pt(NULL, rp->num_q());
+      ReferenceProcessorPhaseTimes pt(NULL, rp->num_queues());
       rp->enqueue_discovered_references(NULL, &pt);
       pt.print_enqueue_phase();
     } else {
@@ -1250,12 +1251,14 @@
   return (GenCollectedHeap*) heap;
 }
 
+#if INCLUDE_SERIALGC
 void GenCollectedHeap::prepare_for_compaction() {
   // Start by compacting into same gen.
   CompactPoint cp(_old_gen);
   _old_gen->prepare_for_compaction(&cp);
   _young_gen->prepare_for_compaction(&cp);
 }
+#endif // INCLUDE_SERIALGC
 
 void GenCollectedHeap::verify(VerifyOption option /* ignored */) {
   log_debug(gc, verify)("%s", _old_gen->name());
--- a/src/hotspot/share/gc/shared/genCollectedHeap.hpp	Wed May 02 22:11:35 2018 -0700
+++ b/src/hotspot/share/gc/shared/genCollectedHeap.hpp	Fri May 04 08:50:01 2018 -0700
@@ -502,10 +502,12 @@
   void check_for_non_bad_heap_word_value(HeapWord* addr,
     size_t size) PRODUCT_RETURN;
 
+#if INCLUDE_SERIALGC
   // For use by mark-sweep.  As implemented, mark-sweep-compact is global
   // in an essential way: compaction is performed across generations, by
   // iterating over spaces.
   void prepare_for_compaction();
+#endif
 
   // Perform a full collection of the generations up to and including max_generation.
   // This is the low level interface used by the public versions of
--- a/src/hotspot/share/gc/shared/genMemoryPools.cpp	Wed May 02 22:11:35 2018 -0700
+++ b/src/hotspot/share/gc/shared/genMemoryPools.cpp	Fri May 04 08:50:01 2018 -0700
@@ -23,10 +23,12 @@
  */
 
 #include "precompiled.hpp"
-#include "gc/serial/defNewGeneration.hpp"
 #include "gc/shared/generation.hpp"
 #include "gc/shared/genMemoryPools.hpp"
 #include "gc/shared/space.hpp"
+#if INCLUDE_SERIALGC
+#include "gc/serial/defNewGeneration.hpp"
+#endif
 
 ContiguousSpacePool::ContiguousSpacePool(ContiguousSpace* space,
                                          const char* name,
@@ -48,6 +50,8 @@
   return MemoryUsage(initial_size(), used, committed, maxSize);
 }
 
+#if INCLUDE_SERIALGC
+
 SurvivorContiguousSpacePool::SurvivorContiguousSpacePool(DefNewGeneration* young_gen,
                                                          const char* name,
                                                          size_t max_size,
@@ -72,6 +76,8 @@
   return MemoryUsage(initial_size(), used, committed, maxSize);
 }
 
+#endif // INCLUDE_SERIALGC
+
 GenerationPool::GenerationPool(Generation* gen,
                                const char* name,
                                bool support_usage_threshold) :
--- a/src/hotspot/share/gc/shared/genOopClosures.cpp	Wed May 02 22:11:35 2018 -0700
+++ b/src/hotspot/share/gc/shared/genOopClosures.cpp	Fri May 04 08:50:01 2018 -0700
@@ -22,12 +22,16 @@
  */
 
 #include "precompiled.hpp"
-#include "gc/serial/serial_specialized_oop_closures.hpp"
 #include "gc/shared/genOopClosures.inline.hpp"
 #include "memory/iterator.inline.hpp"
+#if INCLUDE_SERIALGC
+#include "gc/serial/serial_specialized_oop_closures.hpp"
+#endif
 
 void FilteringClosure::do_oop(oop* p)       { do_oop_nv(p); }
 void FilteringClosure::do_oop(narrowOop* p) { do_oop_nv(p); }
 
+#if INCLUDE_SERIALGC
 // Generate Serial GC specialized oop_oop_iterate functions.
 SPECIALIZED_OOP_OOP_ITERATE_CLOSURES_S(ALL_KLASS_OOP_OOP_ITERATE_DEFN)
+#endif
--- a/src/hotspot/share/gc/shared/genOopClosures.hpp	Wed May 02 22:11:35 2018 -0700
+++ b/src/hotspot/share/gc/shared/genOopClosures.hpp	Fri May 04 08:50:01 2018 -0700
@@ -94,6 +94,7 @@
   void do_cld_barrier();
 };
 
+#if INCLUDE_SERIALGC
 
 // Closure for scanning DefNewGeneration.
 //
@@ -132,6 +133,8 @@
   inline void do_oop_nv(narrowOop* p);
 };
 
+#endif // INCLUDE_SERIALGC
+
 class CLDScanClosure: public CLDClosure {
   OopsInClassLoaderDataOrGenClosure*   _scavenge_closure;
   // true if the the modified oops state should be saved.
@@ -161,6 +164,8 @@
   inline bool do_metadata_nv()        { assert(!_cl->do_metadata(), "assumption broken, must change to 'return _cl->do_metadata()'"); return false; }
 };
 
+#if INCLUDE_SERIALGC
+
 // Closure for scanning DefNewGeneration's weak references.
 // NOTE: very much like ScanClosure but not derived from
 //  OopsInGenClosure -- weak references are processed all
@@ -178,4 +183,6 @@
   inline void do_oop_nv(narrowOop* p);
 };
 
+#endif // INCLUDE_SERIALGC
+
 #endif // SHARE_VM_GC_SHARED_GENOOPCLOSURES_HPP
--- a/src/hotspot/share/gc/shared/genOopClosures.inline.hpp	Wed May 02 22:11:35 2018 -0700
+++ b/src/hotspot/share/gc/shared/genOopClosures.inline.hpp	Fri May 04 08:50:01 2018 -0700
@@ -25,7 +25,6 @@
 #ifndef SHARE_VM_GC_SHARED_GENOOPCLOSURES_INLINE_HPP
 #define SHARE_VM_GC_SHARED_GENOOPCLOSURES_INLINE_HPP
 
-#include "gc/serial/defNewGeneration.hpp"
 #include "gc/shared/cardTableRS.hpp"
 #include "gc/shared/genCollectedHeap.hpp"
 #include "gc/shared/genOopClosures.hpp"
@@ -34,6 +33,9 @@
 #include "oops/access.inline.hpp"
 #include "oops/compressedOops.inline.hpp"
 #include "oops/oop.inline.hpp"
+#if INCLUDE_SERIALGC
+#include "gc/serial/defNewGeneration.inline.hpp"
+#endif
 
 inline OopsInGenClosure::OopsInGenClosure(Generation* gen) :
   ExtendedOopClosure(gen->ref_processor()), _orig_gen(gen), _rs(NULL) {
@@ -78,6 +80,8 @@
   }
 }
 
+#if INCLUDE_SERIALGC
+
 // NOTE! Any changes made here should also be made
 // in FastScanClosure::do_oop_work()
 template <class T> inline void ScanClosure::do_oop_work(T* p) {
@@ -129,6 +133,8 @@
 inline void FastScanClosure::do_oop_nv(oop* p)       { FastScanClosure::do_oop_work(p); }
 inline void FastScanClosure::do_oop_nv(narrowOop* p) { FastScanClosure::do_oop_work(p); }
 
+#endif // INCLUDE_SERIALGC
+
 template <class T> void FilteringClosure::do_oop_work(T* p) {
   T heap_oop = RawAccess<>::oop_load(p);
   if (!CompressedOops::is_null(heap_oop)) {
@@ -142,6 +148,8 @@
 void FilteringClosure::do_oop_nv(oop* p)       { FilteringClosure::do_oop_work(p); }
 void FilteringClosure::do_oop_nv(narrowOop* p) { FilteringClosure::do_oop_work(p); }
 
+#if INCLUDE_SERIALGC
+
 // Note similarity to ScanClosure; the difference is that
 // the barrier set is taken care of outside this closure.
 template <class T> inline void ScanWeakRefClosure::do_oop_work(T* p) {
@@ -158,4 +166,6 @@
 inline void ScanWeakRefClosure::do_oop_nv(oop* p)       { ScanWeakRefClosure::do_oop_work(p); }
 inline void ScanWeakRefClosure::do_oop_nv(narrowOop* p) { ScanWeakRefClosure::do_oop_work(p); }
 
+#endif // INCLUDE_SERIALGC
+
 #endif // SHARE_VM_GC_SHARED_GENOOPCLOSURES_INLINE_HPP
--- a/src/hotspot/share/gc/shared/generation.cpp	Wed May 02 22:11:35 2018 -0700
+++ b/src/hotspot/share/gc/shared/generation.cpp	Fri May 04 08:50:01 2018 -0700
@@ -23,7 +23,6 @@
  */
 
 #include "precompiled.hpp"
-#include "gc/serial/genMarkSweep.hpp"
 #include "gc/shared/blockOffsetTable.inline.hpp"
 #include "gc/shared/cardTableRS.hpp"
 #include "gc/shared/collectedHeap.inline.hpp"
@@ -77,7 +76,8 @@
 void Generation::ref_processor_init() {
   assert(_ref_processor == NULL, "a reference processor already exists");
   assert(!_reserved.is_empty(), "empty generation?");
-  _ref_processor = new ReferenceProcessor(_reserved);    // a vanilla reference processor
+  _span_based_discoverer.set_span(_reserved);
+  _ref_processor = new ReferenceProcessor(&_span_based_discoverer);    // a vanilla reference processor
   if (_ref_processor == NULL) {
     vm_exit_during_initialization("Could not allocate ReferenceProcessor object");
   }
@@ -303,6 +303,8 @@
   space_iterate(&blk);
 }
 
+#if INCLUDE_SERIALGC
+
 void Generation::prepare_for_compaction(CompactPoint* cp) {
   // Generic implementation, can be specialized
   CompactibleSpace* space = first_compaction_space();
@@ -333,3 +335,5 @@
     sp = sp->next_compaction_space();
   }
 }
+
+#endif // INCLUDE_SERIALGC
--- a/src/hotspot/share/gc/shared/generation.hpp	Wed May 02 22:11:35 2018 -0700
+++ b/src/hotspot/share/gc/shared/generation.hpp	Fri May 04 08:50:01 2018 -0700
@@ -100,6 +100,7 @@
   VirtualSpace _virtual_space;
 
   // ("Weak") Reference processing support
+  SpanSubjectToDiscoveryClosure _span_based_discoverer;
   ReferenceProcessor* _ref_processor;
 
   // Performance Counters
@@ -400,6 +401,7 @@
   GCStats* gc_stats() const { return _gc_stats; }
   virtual void update_gc_stats(Generation* current_generation, bool full) {}
 
+#if INCLUDE_SERIALGC
   // Mark sweep support phase2
   virtual void prepare_for_compaction(CompactPoint* cp);
   // Mark sweep support phase3
@@ -407,6 +409,7 @@
   // Mark sweep support phase4
   virtual void compact();
   virtual void post_compact() { ShouldNotReachHere(); }
+#endif
 
   // Support for CMS's rescan. In this general form we return a pointer
   // to an abstract object that can be used, based on specific previously
--- a/src/hotspot/share/gc/shared/generationSpec.cpp	Wed May 02 22:11:35 2018 -0700
+++ b/src/hotspot/share/gc/shared/generationSpec.cpp	Fri May 04 08:50:01 2018 -0700
@@ -23,28 +23,32 @@
  */
 
 #include "precompiled.hpp"
-#include "gc/serial/defNewGeneration.hpp"
-#include "gc/serial/tenuredGeneration.hpp"
 #include "gc/shared/cardTableRS.hpp"
 #include "gc/shared/generationSpec.hpp"
 #include "memory/binaryTreeDictionary.hpp"
 #include "memory/filemap.hpp"
 #include "runtime/java.hpp"
 #include "utilities/macros.hpp"
-#if INCLUDE_ALL_GCS
+#if INCLUDE_CMSGC
 #include "gc/cms/concurrentMarkSweepGeneration.hpp"
 #include "gc/cms/parNewGeneration.hpp"
-#endif // INCLUDE_ALL_GCS
+#endif
+#if INCLUDE_SERIALGC
+#include "gc/serial/defNewGeneration.hpp"
+#include "gc/serial/tenuredGeneration.hpp"
+#endif
 
 Generation* GenerationSpec::init(ReservedSpace rs, CardTableRS* remset) {
   switch (name()) {
+#if INCLUDE_SERIALGC
     case Generation::DefNew:
       return new DefNewGeneration(rs, init_size());
 
     case Generation::MarkSweepCompact:
       return new TenuredGeneration(rs, init_size(), remset);
+#endif
 
-#if INCLUDE_ALL_GCS
+#if INCLUDE_CMSGC
     case Generation::ParNew:
       return new ParNewGeneration(rs, init_size());
 
@@ -64,7 +68,7 @@
 
       return g;
     }
-#endif // INCLUDE_ALL_GCS
+#endif // INCLUDE_CMSGC
 
     default:
       guarantee(false, "unrecognized GenerationName");
--- a/src/hotspot/share/gc/shared/jvmFlagConstraintsGC.cpp	Wed May 02 22:11:35 2018 -0700
+++ b/src/hotspot/share/gc/shared/jvmFlagConstraintsGC.cpp	Fri May 04 08:50:01 2018 -0700
@@ -25,6 +25,7 @@
 #include "precompiled.hpp"
 #include "gc/shared/collectedHeap.hpp"
 #include "gc/shared/collectorPolicy.hpp"
+#include "gc/shared/gcConfig.hpp"
 #include "gc/shared/jvmFlagConstraintsGC.hpp"
 #include "gc/shared/plab.hpp"
 #include "gc/shared/threadLocalAllocBuffer.hpp"
@@ -36,9 +37,13 @@
 #include "utilities/align.hpp"
 #include "utilities/defaultStream.hpp"
 #include "utilities/macros.hpp"
-#if INCLUDE_ALL_GCS
+#if INCLUDE_CMSGC
 #include "gc/cms/jvmFlagConstraintsCMS.hpp"
+#endif
+#if INCLUDE_G1GC
 #include "gc/g1/jvmFlagConstraintsG1.hpp"
+#endif
+#if INCLUDE_PARALLELGC
 #include "gc/parallel/jvmFlagConstraintsParallel.hpp"
 #endif
 #ifdef COMPILER1
@@ -60,12 +65,14 @@
 JVMFlag::Error ParallelGCThreadsConstraintFunc(uint value, bool verbose) {
   JVMFlag::Error status = JVMFlag::SUCCESS;
 
-#if INCLUDE_ALL_GCS
+#if INCLUDE_PARALLELGC
   status = ParallelGCThreadsConstraintFuncParallel(value, verbose);
   if (status != JVMFlag::SUCCESS) {
     return status;
   }
+#endif
 
+#if INCLUDE_CMSGC
   status = ParallelGCThreadsConstraintFuncCMS(value, verbose);
   if (status != JVMFlag::SUCCESS) {
     return status;
@@ -78,42 +85,44 @@
 // As ConcGCThreads should be smaller than ParallelGCThreads,
 // we need constraint function.
 JVMFlag::Error ConcGCThreadsConstraintFunc(uint value, bool verbose) {
-#if INCLUDE_ALL_GCS
   // CMS and G1 GCs use ConcGCThreads.
-  if ((UseConcMarkSweepGC || UseG1GC) && (value > ParallelGCThreads)) {
+  if ((GCConfig::is_gc_selected(CollectedHeap::CMS) ||
+       GCConfig::is_gc_selected(CollectedHeap::G1)) && (value > ParallelGCThreads)) {
     CommandLineError::print(verbose,
                             "ConcGCThreads (" UINT32_FORMAT ") must be "
                             "less than or equal to ParallelGCThreads (" UINT32_FORMAT ")\n",
                             value, ParallelGCThreads);
     return JVMFlag::VIOLATES_CONSTRAINT;
   }
-#endif
+
   return JVMFlag::SUCCESS;
 }
 
 static JVMFlag::Error MinPLABSizeBounds(const char* name, size_t value, bool verbose) {
-#if INCLUDE_ALL_GCS
-  if ((UseConcMarkSweepGC || UseG1GC || UseParallelGC) && (value < PLAB::min_size())) {
+  if ((GCConfig::is_gc_selected(CollectedHeap::CMS) ||
+       GCConfig::is_gc_selected(CollectedHeap::G1)  ||
+       GCConfig::is_gc_selected(CollectedHeap::Parallel)) && (value < PLAB::min_size())) {
     CommandLineError::print(verbose,
                             "%s (" SIZE_FORMAT ") must be "
                             "greater than or equal to ergonomic PLAB minimum size (" SIZE_FORMAT ")\n",
                             name, value, PLAB::min_size());
     return JVMFlag::VIOLATES_CONSTRAINT;
   }
-#endif // INCLUDE_ALL_GCS
+
   return JVMFlag::SUCCESS;
 }
 
 JVMFlag::Error MaxPLABSizeBounds(const char* name, size_t value, bool verbose) {
-#if INCLUDE_ALL_GCS
-  if ((UseConcMarkSweepGC || UseG1GC || UseParallelGC) && (value > PLAB::max_size())) {
+  if ((GCConfig::is_gc_selected(CollectedHeap::CMS) ||
+       GCConfig::is_gc_selected(CollectedHeap::G1)  ||
+       GCConfig::is_gc_selected(CollectedHeap::Parallel)) && (value > PLAB::max_size())) {
     CommandLineError::print(verbose,
                             "%s (" SIZE_FORMAT ") must be "
                             "less than or equal to ergonomic PLAB maximum size (" SIZE_FORMAT ")\n",
                             name, value, PLAB::max_size());
     return JVMFlag::VIOLATES_CONSTRAINT;
   }
-#endif // INCLUDE_ALL_GCS
+
   return JVMFlag::SUCCESS;
 }
 
@@ -133,13 +142,15 @@
 JVMFlag::Error OldPLABSizeConstraintFunc(size_t value, bool verbose) {
   JVMFlag::Error status = JVMFlag::SUCCESS;
 
-#if INCLUDE_ALL_GCS
+#if INCLUDE_CMSGC
   if (UseConcMarkSweepGC) {
     return OldPLABSizeConstraintFuncCMS(value, verbose);
-  } else {
+  } else
+#endif
+  {
     status = MinMaxPLABSizeBounds("OldPLABSize", value, verbose);
   }
-#endif
+
   return status;
 }
 
@@ -221,7 +232,7 @@
 }
 
 JVMFlag::Error InitialTenuringThresholdConstraintFunc(uintx value, bool verbose) {
-#if INCLUDE_ALL_GCS
+#if INCLUDE_PARALLELGC
   JVMFlag::Error status = InitialTenuringThresholdConstraintFuncParallel(value, verbose);
   if (status != JVMFlag::SUCCESS) {
     return status;
@@ -232,7 +243,7 @@
 }
 
 JVMFlag::Error MaxTenuringThresholdConstraintFunc(uintx value, bool verbose) {
-#if INCLUDE_ALL_GCS
+#if INCLUDE_PARALLELGC
   JVMFlag::Error status = MaxTenuringThresholdConstraintFuncParallel(value, verbose);
   if (status != JVMFlag::SUCCESS) {
     return status;
@@ -253,7 +264,7 @@
 }
 
 JVMFlag::Error MaxGCPauseMillisConstraintFunc(uintx value, bool verbose) {
-#if INCLUDE_ALL_GCS
+#if INCLUDE_G1GC
   JVMFlag::Error status = MaxGCPauseMillisConstraintFuncG1(value, verbose);
   if (status != JVMFlag::SUCCESS) {
     return status;
@@ -264,7 +275,7 @@
 }
 
 JVMFlag::Error GCPauseIntervalMillisConstraintFunc(uintx value, bool verbose) {
-#if INCLUDE_ALL_GCS
+#if INCLUDE_G1GC
   JVMFlag::Error status = GCPauseIntervalMillisConstraintFuncG1(value, verbose);
   if (status != JVMFlag::SUCCESS) {
     return status;
@@ -302,7 +313,7 @@
 static JVMFlag::Error MaxSizeForHeapAlignment(const char* name, size_t value, bool verbose) {
   size_t heap_alignment;
 
-#if INCLUDE_ALL_GCS
+#if INCLUDE_G1GC
   if (UseG1GC) {
     // For G1 GC, we don't know until G1CollectorPolicy is created.
     heap_alignment = MaxSizeForHeapAlignmentG1();
@@ -343,7 +354,7 @@
 }
 
 JVMFlag::Error NewSizeConstraintFunc(size_t value, bool verbose) {
-#if INCLUDE_ALL_GCS
+#if INCLUDE_G1GC
   JVMFlag::Error status = NewSizeConstraintFuncG1(value, verbose);
   if (status != JVMFlag::SUCCESS) {
     return status;
--- a/src/hotspot/share/gc/shared/jvmFlagConstraintsGC.hpp	Wed May 02 22:11:35 2018 -0700
+++ b/src/hotspot/share/gc/shared/jvmFlagConstraintsGC.hpp	Fri May 04 08:50:01 2018 -0700
@@ -27,9 +27,13 @@
 
 #include "utilities/globalDefinitions.hpp"
 #include "utilities/macros.hpp"
-#if INCLUDE_ALL_GCS
+#if INCLUDE_CMSGC
 #include "gc/cms/jvmFlagConstraintsCMS.hpp"
+#endif
+#if INCLUDE_G1GC
 #include "gc/g1/jvmFlagConstraintsG1.hpp"
+#endif
+#if INCLUDE_PARALLELGC
 #include "gc/parallel/jvmFlagConstraintsParallel.hpp"
 #endif
 
--- a/src/hotspot/share/gc/shared/oopStorage.cpp	Wed May 02 22:11:35 2018 -0700
+++ b/src/hotspot/share/gc/shared/oopStorage.cpp	Fri May 04 08:50:01 2018 -0700
@@ -28,20 +28,22 @@
 #include "logging/log.hpp"
 #include "logging/logStream.hpp"
 #include "memory/allocation.inline.hpp"
-#include "memory/resourceArea.hpp"
 #include "runtime/atomic.hpp"
+#include "runtime/globals.hpp"
 #include "runtime/handles.inline.hpp"
 #include "runtime/mutex.hpp"
 #include "runtime/mutexLocker.hpp"
 #include "runtime/orderAccess.inline.hpp"
 #include "runtime/safepoint.hpp"
 #include "runtime/stubRoutines.hpp"
+#include "runtime/thread.hpp"
 #include "utilities/align.hpp"
 #include "utilities/count_trailing_zeros.hpp"
 #include "utilities/debug.hpp"
 #include "utilities/globalDefinitions.hpp"
 #include "utilities/macros.hpp"
 #include "utilities/ostream.hpp"
+#include "utilities/spinYield.hpp"
 
 OopStorage::BlockEntry::BlockEntry() : _prev(NULL), _next(NULL) {}
 
@@ -108,6 +110,90 @@
   }
 }
 
+OopStorage::BlockArray::BlockArray(size_t size) :
+  _size(size),
+  _block_count(0),
+  _refcount(0)
+{}
+
+OopStorage::BlockArray::~BlockArray() {
+  assert(_refcount == 0, "precondition");
+}
+
+OopStorage::BlockArray* OopStorage::BlockArray::create(size_t size, AllocFailType alloc_fail) {
+  size_t size_in_bytes = blocks_offset() + sizeof(Block*) * size;
+  void* mem = NEW_C_HEAP_ARRAY3(char, size_in_bytes, mtGC, CURRENT_PC, alloc_fail);
+  if (mem == NULL) return NULL;
+  return new (mem) BlockArray(size);
+}
+
+void OopStorage::BlockArray::destroy(BlockArray* ba) {
+  ba->~BlockArray();
+  FREE_C_HEAP_ARRAY(char, ba);
+}
+
+size_t OopStorage::BlockArray::size() const {
+  return _size;
+}
+
+size_t OopStorage::BlockArray::block_count() const {
+  return _block_count;
+}
+
+size_t OopStorage::BlockArray::block_count_acquire() const {
+  return OrderAccess::load_acquire(&_block_count);
+}
+
+void OopStorage::BlockArray::increment_refcount() const {
+  int new_value = Atomic::add(1, &_refcount);
+  assert(new_value >= 1, "negative refcount %d", new_value - 1);
+}
+
+bool OopStorage::BlockArray::decrement_refcount() const {
+  int new_value = Atomic::sub(1, &_refcount);
+  assert(new_value >= 0, "negative refcount %d", new_value);
+  return new_value == 0;
+}
+
+bool OopStorage::BlockArray::push(Block* block) {
+  size_t index = _block_count;
+  if (index < _size) {
+    block->set_active_index(index);
+    *block_ptr(index) = block;
+    // Use a release_store to ensure all the setup is complete before
+    // making the block visible.
+    OrderAccess::release_store(&_block_count, index + 1);
+    return true;
+  } else {
+    return false;
+  }
+}
+
+void OopStorage::BlockArray::remove(Block* block) {
+  assert(_block_count > 0, "array is empty");
+  size_t index = block->active_index();
+  assert(*block_ptr(index) == block, "block not present");
+  size_t last_index = _block_count - 1;
+  Block* last_block = *block_ptr(last_index);
+  last_block->set_active_index(index);
+  *block_ptr(index) = last_block;
+  _block_count = last_index;
+}
+
+void OopStorage::BlockArray::copy_from(const BlockArray* from) {
+  assert(_block_count == 0, "array must be empty");
+  size_t count = from->_block_count;
+  assert(count <= _size, "precondition");
+  Block* const* from_ptr = from->block_ptr(0);
+  Block** to_ptr = block_ptr(0);
+  for (size_t i = 0; i < count; ++i) {
+    Block* block = *from_ptr++;
+    assert(block->active_index() == i, "invariant");
+    *to_ptr++ = block;
+  }
+  _block_count = count;
+}
+
 // Blocks start with an array of BitsPerWord oop entries.  That array
 // is divided into conceptual BytesPerWord sections of BitsPerByte
 // entries.  Blocks are allocated aligned on section boundaries, for
@@ -125,7 +211,7 @@
   _allocated_bitmask(0),
   _owner(owner),
   _memory(memory),
-  _active_entry(),
+  _active_index(0),
   _allocate_entry(),
   _deferred_updates_next(NULL),
   _release_refcount(0)
@@ -146,10 +232,6 @@
   const_cast<OopStorage* volatile&>(_owner) = NULL;
 }
 
-const OopStorage::BlockEntry& OopStorage::Block::get_active_entry(const Block& block) {
-  return block._active_entry;
-}
-
 const OopStorage::BlockEntry& OopStorage::Block::get_allocate_entry(const Block& block) {
   return block._allocate_entry;
 }
@@ -204,6 +286,20 @@
   return (base <= ptr) && (ptr < (base + ARRAY_SIZE(_data)));
 }
 
+size_t OopStorage::Block::active_index() const {
+  return _active_index;
+}
+
+void OopStorage::Block::set_active_index(size_t index) {
+  _active_index = index;
+}
+
+size_t OopStorage::Block::active_index_safe(const Block* block) {
+  STATIC_ASSERT(sizeof(intptr_t) == sizeof(block->_active_index));
+  assert(CanUseSafeFetchN(), "precondition");
+  return SafeFetchN((intptr_t*)&block->_active_index, 0);
+}
+
 unsigned OopStorage::Block::get_index(const oop* ptr) const {
   assert(contains(ptr), PTR_FORMAT " not in block " PTR_FORMAT, p2i(ptr), p2i(this));
   return static_cast<unsigned>(ptr - get_pointer(0));
@@ -246,7 +342,7 @@
 
 // This can return a false positive if ptr is not contained by some
 // block.  For some uses, it is a precondition that ptr is valid,
-// e.g. contained in some block in owner's _active_list.  Other uses
+// e.g. contained in some block in owner's _active_array.  Other uses
 // require additional validation of the result.
 OopStorage::Block*
 OopStorage::Block::block_for_ptr(const OopStorage* owner, const oop* ptr) {
@@ -280,12 +376,12 @@
 // Allocation involves the _allocate_list, which contains a subset of the
 // blocks owned by a storage object.  This is a doubly-linked list, linked
 // through dedicated fields in the blocks.  Full blocks are removed from this
-// list, though they are still present in the _active_list.  Empty blocks are
+// list, though they are still present in the _active_array.  Empty blocks are
 // kept at the end of the _allocate_list, to make it easy for empty block
 // deletion to find them.
 //
 // allocate(), and delete_empty_blocks_concurrent() lock the
-// _allocate_mutex while performing any list modifications.
+// _allocate_mutex while performing any list and array modifications.
 //
 // allocate() and release() update a block's _allocated_bitmask using CAS
 // loops.  This prevents loss of updates even though release() performs
@@ -299,7 +395,7 @@
 //
 // 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
+// avoiding iteration over the _active_array).  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:
 //
@@ -340,7 +436,7 @@
           // 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());
+          log_info(oopstorage, ref)("%s: failed block allocation", name());
           return NULL;
         }
       }
@@ -348,17 +444,21 @@
       // Add new block to storage.
       log_info(oopstorage, blocks)("%s: new block " PTR_FORMAT, name(), p2i(block));
 
+      // Add new block to the _active_array, growing if needed.
+      if (!_active_array->push(block)) {
+        if (expand_active_array()) {
+          guarantee(_active_array->push(block), "push failed after expansion");
+        } else {
+          log_info(oopstorage, blocks)("%s: failed active array expand", name());
+          Block::delete_block(*block);
+          return NULL;
+        }
+      }
       // Add to end of _allocate_list.  The mutex release allowed
       // other threads to add blocks to the _allocate_list.  We prefer
       // to allocate from non-empty blocks, to allow empty blocks to
       // be deleted.
       _allocate_list.push_back(*block);
-      // 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);
     }
     block = _allocate_list.head();
   }
@@ -383,6 +483,123 @@
   return result;
 }
 
+// Create a new, larger, active array with the same content as the
+// current array, and then replace, relinquishing the old array.
+// Return true if the array was successfully expanded, false to
+// indicate allocation failure.
+bool OopStorage::expand_active_array() {
+  assert_lock_strong(_allocate_mutex);
+  BlockArray* old_array = _active_array;
+  size_t new_size = 2 * old_array->size();
+  log_info(oopstorage, blocks)("%s: expand active array " SIZE_FORMAT,
+                               name(), new_size);
+  BlockArray* new_array = BlockArray::create(new_size, AllocFailStrategy::RETURN_NULL);
+  if (new_array == NULL) return false;
+  new_array->copy_from(old_array);
+  replace_active_array(new_array);
+  relinquish_block_array(old_array);
+  return true;
+}
+
+OopStorage::ProtectActive::ProtectActive() : _enter(0), _exit() {}
+
+// Begin read-side critical section.
+uint OopStorage::ProtectActive::read_enter() {
+  return Atomic::add(2u, &_enter);
+}
+
+// End read-side critical section.
+void OopStorage::ProtectActive::read_exit(uint enter_value) {
+  Atomic::add(2u, &_exit[enter_value & 1]);
+}
+
+// Wait until all readers that entered the critical section before
+// synchronization have exited that critical section.
+void OopStorage::ProtectActive::write_synchronize() {
+  SpinYield spinner;
+  // Determine old and new exit counters, based on bit0 of the
+  // on-entry _enter counter.
+  uint value = OrderAccess::load_acquire(&_enter);
+  volatile uint* new_ptr = &_exit[(value + 1) & 1];
+  // Atomically change the in-use exit counter to the new counter, by
+  // adding 1 to the _enter counter (flipping bit0 between 0 and 1)
+  // and initializing the new exit counter to that enter value.  Note:
+  // The new exit counter is not being used by read operations until
+  // this change succeeds.
+  uint old;
+  do {
+    old = value;
+    *new_ptr = ++value;
+    value = Atomic::cmpxchg(value, &_enter, old);
+  } while (old != value);
+  // Readers that entered the critical section before we changed the
+  // selected exit counter will use the old exit counter.  Readers
+  // entering after the change will use the new exit counter.  Wait
+  // for all the critical sections started before the change to
+  // complete, e.g. for the value of old_ptr to catch up with old.
+  volatile uint* old_ptr = &_exit[old & 1];
+  while (old != OrderAccess::load_acquire(old_ptr)) {
+    spinner.wait();
+  }
+}
+
+// Make new_array the _active_array.  Increments new_array's refcount
+// to account for the new reference.  The assignment is atomic wrto
+// obtain_active_array; once this function returns, it is safe for the
+// caller to relinquish the old array.
+void OopStorage::replace_active_array(BlockArray* new_array) {
+  // Caller has the old array that is the current value of _active_array.
+  // Update new_array refcount to account for the new reference.
+  new_array->increment_refcount();
+  // Install new_array, ensuring its initialization is complete first.
+  OrderAccess::release_store(&_active_array, new_array);
+  // Wait for any readers that could read the old array from _active_array.
+  _protect_active.write_synchronize();
+  // All obtain critical sections that could see the old array have
+  // completed, having incremented the refcount of the old array.  The
+  // caller can now safely relinquish the old array.
+}
+
+// Atomically (wrto replace_active_array) get the active array and
+// increment its refcount.  This provides safe access to the array,
+// even if an allocate operation expands and replaces the value of
+// _active_array.  The caller must relinquish the array when done
+// using it.
+OopStorage::BlockArray* OopStorage::obtain_active_array() const {
+  uint enter_value = _protect_active.read_enter();
+  BlockArray* result = OrderAccess::load_acquire(&_active_array);
+  result->increment_refcount();
+  _protect_active.read_exit(enter_value);
+  return result;
+}
+
+// Decrement refcount of array and destroy if refcount is zero.
+void OopStorage::relinquish_block_array(BlockArray* array) const {
+  if (array->decrement_refcount()) {
+    assert(array != _active_array, "invariant");
+    BlockArray::destroy(array);
+  }
+}
+
+class OopStorage::WithActiveArray : public StackObj {
+  const OopStorage* _storage;
+  BlockArray* _active_array;
+
+public:
+  WithActiveArray(const OopStorage* storage) :
+    _storage(storage),
+    _active_array(storage->obtain_active_array())
+  {}
+
+  ~WithActiveArray() {
+    _storage->relinquish_block_array(_active_array);
+  }
+
+  BlockArray& active_array() const {
+    return *_active_array;
+  }
+};
+
 OopStorage::Block* OopStorage::find_block_or_null(const oop* ptr) const {
   assert(ptr != NULL, "precondition");
   return Block::block_for_ptr(this, ptr);
@@ -392,7 +609,6 @@
                                     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)) {
@@ -546,20 +762,21 @@
   return dup;
 }
 
+const size_t initial_active_array_size = 8;
+
 OopStorage::OopStorage(const char* name,
                        Mutex* allocate_mutex,
                        Mutex* active_mutex) :
   _name(dup_name(name)),
-  _active_list(&Block::get_active_entry),
+  _active_array(BlockArray::create(initial_active_array_size)),
   _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),
   _concurrent_iteration_active(false)
 {
+  _active_array->increment_refcount();
   assert(_active_mutex->rank() < _allocate_mutex->rank(),
          "%s: active_mutex must have lower rank than allocate_mutex", _name);
   assert(_active_mutex->_safepoint_check_required != Mutex::_safepoint_check_always,
@@ -583,10 +800,13 @@
   while ((block = _allocate_list.head()) != NULL) {
     _allocate_list.unlink(*block);
   }
-  while ((block = _active_list.head()) != NULL) {
-    _active_list.unlink(*block);
+  bool unreferenced = _active_array->decrement_refcount();
+  assert(unreferenced, "deleting storage while _active_array is referenced");
+  for (size_t i = _active_array->block_count(); 0 < i; ) {
+    block = _active_array->at(--i);
     Block::delete_block(*block);
   }
+  BlockArray::destroy(_active_array);
   FREE_C_HEAP_ARRAY(char, _name);
 }
 
@@ -598,16 +818,13 @@
   // Don't interfere with a concurrent iteration.
   if (_concurrent_iteration_active) return;
   // Delete empty (and otherwise deletable) blocks from end of _allocate_list.
-  for (const Block* block = _allocate_list.ctail();
+  for (Block* block = _allocate_list.tail();
        (block != NULL) && block->is_deletable();
-       block = _allocate_list.ctail()) {
-    _active_list.unlink(*block);
+       block = _allocate_list.tail()) {
+    _active_array->remove(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() {
@@ -616,14 +833,14 @@
   // 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.
-  size_t limit = _block_count;
+  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();
+    Block* block = _allocate_list.tail();
     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
@@ -635,12 +852,7 @@
       MutexLockerEx aml(_active_mutex, Mutex::_no_safepoint_check_flag);
       // Don't interfere with a concurrent iteration.
       if (_concurrent_iteration_active) return;
-      // Remove block from _active_list, updating head if needed.
-      _active_list.unlink(*block);
-      --_block_count;
-      if (block == _active_head) {
-        _active_head = _active_list.head();
-      }
+      _active_array->remove(block);
     }
     // Remove block from _allocate_list and delete it.
     _allocate_list.unlink(*block);
@@ -653,18 +865,17 @@
 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.
+    // Prevent block deletion and _active_array modification.
     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;
-        }
+    // Block could be a false positive, so get index carefully.
+    size_t index = Block::active_index_safe(block);
+    if ((index < _active_array->block_count()) &&
+        (block == _active_array->at(index)) &&
+        block->contains(ptr)) {
+      if ((block->allocated_bitmask() & block->bitmask_for_entry(ptr)) != 0) {
+        return ALLOCATED_ENTRY;
+      } else {
+        return UNALLOCATED_ENTRY;
       }
     }
   }
@@ -676,30 +887,50 @@
 }
 
 size_t OopStorage::block_count() const {
-  return _block_count;
+  WithActiveArray wab(this);
+  // Count access is racy, but don't care.
+  return wab.active_array().block_count();
 }
 
 size_t OopStorage::total_memory_usage() const {
   size_t total_size = sizeof(OopStorage);
   total_size += strlen(name()) + 1;
-  total_size += block_count() * Block::allocation_size();
+  total_size += sizeof(BlockArray);
+  WithActiveArray wab(this);
+  const BlockArray& blocks = wab.active_array();
+  // Count access is racy, but don't care.
+  total_size += blocks.block_count() * Block::allocation_size();
+  total_size += blocks.size() * sizeof(Block*);
   return total_size;
 }
 
 // Parallel iteration support
 
-static char* not_started_marker_dummy = NULL;
-static void* const not_started_marker = &not_started_marker_dummy;
+uint OopStorage::BasicParState::default_estimated_thread_count(bool concurrent) {
+  return concurrent ? ConcGCThreads : ParallelGCThreads;
+}
 
-OopStorage::BasicParState::BasicParState(OopStorage* storage, bool concurrent) :
+OopStorage::BasicParState::BasicParState(const OopStorage* storage,
+                                         uint estimated_thread_count,
+                                         bool concurrent) :
   _storage(storage),
-  _next_block(not_started_marker),
+  _active_array(_storage->obtain_active_array()),
+  _block_count(0),              // initialized properly below
+  _next_block(0),
+  _estimated_thread_count(estimated_thread_count),
   _concurrent(concurrent)
 {
+  assert(estimated_thread_count > 0, "estimated thread count must be positive");
   update_iteration_state(true);
+  // Get the block count *after* iteration state updated, so concurrent
+  // empty block deletion is suppressed and can't reduce the count.  But
+  // ensure the count we use was written after the block with that count
+  // was fully initialized; see BlockArray::push.
+  _block_count = _active_array->block_count_acquire();
 }
 
 OopStorage::BasicParState::~BasicParState() {
+  _storage->relinquish_block_array(_active_array);
   update_iteration_state(false);
 }
 
@@ -711,29 +942,49 @@
   }
 }
 
-void OopStorage::BasicParState::ensure_iteration_started() {
-  if (!_concurrent) {
-    assert_at_safepoint();
+bool OopStorage::BasicParState::claim_next_segment(IterationData* data) {
+  data->_processed += data->_segment_end - data->_segment_start;
+  size_t start = OrderAccess::load_acquire(&_next_block);
+  if (start >= _block_count) {
+    return finish_iteration(data); // No more blocks available.
   }
-  assert(!_concurrent || _storage->_concurrent_iteration_active, "invariant");
-  // Ensure _next_block is not the not_started_marker, setting it to
-  // the _active_head to start the iteration if necessary.
-  if (OrderAccess::load_acquire(&_next_block) == not_started_marker) {
-    Atomic::cmpxchg(_storage->_active_head, &_next_block, not_started_marker);
+  // Try to claim several at a time, but not *too* many.  We want to
+  // avoid deciding there are many available and selecting a large
+  // quantity, get delayed, and then end up claiming most or all of
+  // the remaining largish amount of work, leaving nothing for other
+  // threads to do.  But too small a step can lead to contention
+  // over _next_block, esp. when the work per block is small.
+  size_t max_step = 10;
+  size_t remaining = _block_count - start;
+  size_t step = MIN2(max_step, 1 + (remaining / _estimated_thread_count));
+  // Atomic::add with possible overshoot.  This can perform better
+  // than a CAS loop on some platforms when there is contention.
+  // We can cope with the uncertainty by recomputing start/end from
+  // the result of the add, and dealing with potential overshoot.
+  size_t end = Atomic::add(step, &_next_block);
+  // _next_block may have changed, so recompute start from result of add.
+  start = end - step;
+  // _next_block may have changed so much that end has overshot.
+  end = MIN2(end, _block_count);
+  // _next_block may have changed so much that even start has overshot.
+  if (start < _block_count) {
+    // Record claimed segment for iteration.
+    data->_segment_start = start;
+    data->_segment_end = end;
+    return true;                // Success.
+  } else {
+    // No more blocks to claim.
+    return finish_iteration(data);
   }
-  assert(_next_block != not_started_marker, "postcondition");
 }
 
-OopStorage::Block* OopStorage::BasicParState::claim_next_block() {
-  assert(_next_block != not_started_marker, "Iteration not started");
-  void* next = _next_block;
-  while (next != NULL) {
-    void* new_next = _storage->_active_list.next(*static_cast<Block*>(next));
-    void* fetched = Atomic::cmpxchg(new_next, &_next_block, next);
-    if (fetched == next) break; // Claimed.
-    next = fetched;
-  }
-  return static_cast<Block*>(next);
+bool OopStorage::BasicParState::finish_iteration(const IterationData* data) const {
+  log_debug(oopstorage, blocks, stats)
+           ("Parallel iteration on %s: blocks = " SIZE_FORMAT
+            ", processed = " SIZE_FORMAT " (%2.f%%)",
+            _storage->name(), _block_count, data->_processed,
+            percent_of(data->_processed, _block_count));
+  return false;
 }
 
 const char* OopStorage::name() const { return _name; }
@@ -742,7 +993,7 @@
 
 void OopStorage::print_on(outputStream* st) const {
   size_t allocations = _allocation_count;
-  size_t blocks = _block_count;
+  size_t blocks = _active_array->block_count();
 
   double data_size = section_size * section_count;
   double alloc_percentage = percent_of((double)allocations, blocks * data_size);
--- a/src/hotspot/share/gc/shared/oopStorage.hpp	Wed May 02 22:11:35 2018 -0700
+++ b/src/hotspot/share/gc/shared/oopStorage.hpp	Fri May 04 08:50:01 2018 -0700
@@ -170,27 +170,11 @@
   // classes. C++03 introduced access for nested classes with DR45, but xlC
   // version 12 rejects it.
 NOT_AIX( private: )
-  class Block;                  // Forward decl; defined in .inline.hpp file.
-  class BlockList;              // Forward decl for BlockEntry friend decl.
+  class Block;                  // Fixed-size array of oops, plus bookkeeping.
+  class BlockArray;             // Array of Blocks, plus bookkeeping.
+  class BlockEntry;             // Provides BlockList links in a Block.
 
-  class BlockEntry {
-    friend class BlockList;
-
-    // Members are mutable, and we deal exclusively with pointers to
-    // const, to make const blocks easier to use; a block being const
-    // doesn't prevent modifying its list state.
-    mutable const Block* _prev;
-    mutable const Block* _next;
-
-    // Noncopyable.
-    BlockEntry(const BlockEntry&);
-    BlockEntry& operator=(const BlockEntry&);
-
-  public:
-    BlockEntry();
-    ~BlockEntry();
-  };
-
+  // Doubly-linked list of Blocks.
   class BlockList {
     const Block* _head;
     const Block* _tail;
@@ -205,6 +189,7 @@
     ~BlockList();
 
     Block* head();
+    Block* tail();
     const Block* chead() const;
     const Block* ctail() const;
 
@@ -219,19 +204,34 @@
     void unlink(const Block& block);
   };
 
+  // RCU-inspired protection of access to _active_array.
+  class ProtectActive {
+    volatile uint _enter;
+    volatile uint _exit[2];
+
+  public:
+    ProtectActive();
+
+    uint read_enter();
+    void read_exit(uint enter_value);
+    void write_synchronize();
+  };
+
 private:
   const char* _name;
-  BlockList _active_list;
+  BlockArray* _active_array;
   BlockList _allocate_list;
-  Block* volatile _active_head;
   Block* volatile _deferred_updates;
 
   Mutex* _allocate_mutex;
   Mutex* _active_mutex;
 
-  // Counts are volatile for racy unlocked accesses.
+  // Volatile for racy unlocked accesses.
   volatile size_t _allocation_count;
-  volatile size_t _block_count;
+
+  // Protection for _active_array.
+  mutable ProtectActive _protect_active;
+
   // mutable because this gets set even for const iteration.
   mutable bool _concurrent_iteration_active;
 
@@ -239,6 +239,13 @@
   void delete_empty_block(const Block& block);
   bool reduce_deferred_updates();
 
+  // Managing _active_array.
+  bool expand_active_array();
+  void replace_active_array(BlockArray* new_array);
+  BlockArray* obtain_active_array() const;
+  void relinquish_block_array(BlockArray* array) const;
+  class WithActiveArray;        // RAII helper for active array access.
+
   template<typename F, typename Storage>
   static bool iterate_impl(F f, Storage* storage);
 
--- a/src/hotspot/share/gc/shared/oopStorage.inline.hpp	Wed May 02 22:11:35 2018 -0700
+++ b/src/hotspot/share/gc/shared/oopStorage.inline.hpp	Fri May 04 08:50:01 2018 -0700
@@ -30,10 +30,107 @@
 #include "metaprogramming/isConst.hpp"
 #include "oops/oop.hpp"
 #include "runtime/safepoint.hpp"
+#include "utilities/align.hpp"
 #include "utilities/count_trailing_zeros.hpp"
 #include "utilities/debug.hpp"
 #include "utilities/globalDefinitions.hpp"
 
+// Array of all active blocks.  Refcounted for lock-free reclaim of
+// old array when a new array is allocated for expansion.
+class OopStorage::BlockArray {
+  friend class OopStorage::TestAccess;
+
+  size_t _size;
+  volatile size_t _block_count;
+  mutable volatile int _refcount;
+  // Block* _blocks[1];            // Pseudo flexible array member.
+
+  BlockArray(size_t size);
+  ~BlockArray();
+
+  // Noncopyable
+  BlockArray(const BlockArray&);
+  BlockArray& operator=(const BlockArray&);
+
+  static size_t blocks_offset();
+  Block* const* base_ptr() const;
+
+  Block* const* block_ptr(size_t index) const;
+  Block** block_ptr(size_t index);
+
+public:
+  static BlockArray* create(size_t size, AllocFailType alloc_fail = AllocFailStrategy::EXIT_OOM);
+  static void destroy(BlockArray* ba);
+
+  inline Block* at(size_t i) const;
+
+  size_t size() const;
+  size_t block_count() const;
+  size_t block_count_acquire() const;
+  void increment_refcount() const;
+  bool decrement_refcount() const; // Return true if zero, otherwise false
+
+  // Support for OopStorage::allocate.
+  // Add block to the end of the array.  Updates block count at the
+  // end of the operation, with a release_store. Returns true if the
+  // block was added, false if there was no room available.
+  // precondition: owner's _allocation_mutex is locked, or at safepoint.
+  bool push(Block* block);
+
+  // Support OopStorage::delete_empty_blocks_xxx operations.
+  // Remove block from the array.
+  // precondition: block must be present at its active_index element.
+  void remove(Block* block);
+
+  void copy_from(const BlockArray* from);
+};
+
+inline size_t OopStorage::BlockArray::blocks_offset() {
+  return align_up(sizeof(BlockArray), sizeof(Block*));
+}
+
+inline OopStorage::Block* const* OopStorage::BlockArray::base_ptr() const {
+  const void* ptr = reinterpret_cast<const char*>(this) + blocks_offset();
+  return reinterpret_cast<Block* const*>(ptr);
+}
+
+inline OopStorage::Block* const* OopStorage::BlockArray::block_ptr(size_t index) const {
+  return base_ptr() + index;
+}
+
+inline OopStorage::Block** OopStorage::BlockArray::block_ptr(size_t index) {
+  return const_cast<Block**>(base_ptr() + index);
+}
+
+inline OopStorage::Block* OopStorage::BlockArray::at(size_t index) const {
+  assert(index < _block_count, "precondition");
+  return *block_ptr(index);
+}
+
+// A Block has an embedded BlockEntry to provide the links between
+// Blocks in a BlockList.
+class OopStorage::BlockEntry {
+  friend class OopStorage::BlockList;
+
+  // Members are mutable, and we deal exclusively with pointers to
+  // const, to make const blocks easier to use; a block being const
+  // doesn't prevent modifying its list state.
+  mutable const Block* _prev;
+  mutable const Block* _next;
+
+  // Noncopyable.
+  BlockEntry(const BlockEntry&);
+  BlockEntry& operator=(const BlockEntry&);
+
+public:
+  BlockEntry();
+  ~BlockEntry();
+};
+
+// Fixed-sized array of oops, plus bookkeeping data.
+// All blocks are in the storage's _active_array, at the block's _active_index.
+// Non-full blocks are in the storage's _allocate_list, linked through the
+// block's _allocate_entry.  Empty blocks are at the end of that list.
 class OopStorage::Block /* No base class, to avoid messing up alignment. */ {
   // _data must be the first non-static data member, for alignment.
   oop _data[BitsPerWord];
@@ -42,7 +139,7 @@
   volatile uintx _allocated_bitmask; // One bit per _data element.
   const OopStorage* _owner;
   void* _memory;              // Unaligned storage containing block.
-  BlockEntry _active_entry;
+  size_t _active_index;
   BlockEntry _allocate_entry;
   Block* volatile _deferred_updates_next;
   volatile uintx _release_refcount;
@@ -61,7 +158,6 @@
   Block& operator=(const Block&);
 
 public:
-  static const BlockEntry& get_active_entry(const Block& block);
   static const BlockEntry& get_allocate_entry(const Block& block);
 
   static size_t allocation_size();
@@ -84,6 +180,10 @@
 
   bool contains(const oop* ptr) const;
 
+  size_t active_index() const;
+  void set_active_index(size_t index);
+  static size_t active_index_safe(const Block* block); // Returns 0 if access fails.
+
   // Returns NULL if ptr is not in a block or not allocated in that block.
   static Block* block_for_ptr(const OopStorage* owner, const oop* ptr);
 
@@ -101,6 +201,10 @@
   return const_cast<Block*>(_head);
 }
 
+inline OopStorage::Block* OopStorage::BlockList::tail() {
+  return const_cast<Block*>(_tail);
+}
+
 inline const OopStorage::Block* OopStorage::BlockList::chead() const {
   return _head;
 }
@@ -253,9 +357,10 @@
   // Propagate const/non-const iteration to the block layer, by using
   // const or non-const blocks as corresponding to Storage.
   typedef typename Conditional<IsConst<Storage>::value, const Block*, Block*>::type BlockPtr;
-  for (BlockPtr block = storage->_active_head;
-       block != NULL;
-       block = storage->_active_list.next(*block)) {
+  BlockArray* blocks = storage->_active_array;
+  size_t limit = blocks->block_count();
+  for (size_t i = 0; i < limit; ++i) {
+    BlockPtr block = blocks->at(i);
     if (!block->iterate(f)) {
       return false;
     }
--- a/src/hotspot/share/gc/shared/oopStorageParState.hpp	Wed May 02 22:11:35 2018 -0700
+++ b/src/hotspot/share/gc/shared/oopStorageParState.hpp	Fri May 04 08:50:01 2018 -0700
@@ -36,9 +36,8 @@
 //
 // Concurrent Iteration
 //
-// Iteration involves the _active_list, which contains all of the blocks owned
-// by a storage object.  This is a doubly-linked list, linked through
-// dedicated fields in the blocks.
+// Iteration involves the _active_array (a BlockArray), which contains all of
+// the blocks owned by a storage object.
 //
 // At most one concurrent ParState can exist at a time for a given storage
 // object.
@@ -48,27 +47,29 @@
 // sets it false when the state is destroyed.  These assignments are made with
 // _active_mutex locked.  Meanwhile, empty block deletion is not done while
 // _concurrent_iteration_active is true.  The flag check and the dependent
-// removal of a block from the _active_list is performed with _active_mutex
+// removal of a block from the _active_array is performed with _active_mutex
 // locked.  This prevents concurrent iteration and empty block deletion from
 // interfering with with each other.
 //
 // Both allocate() and delete_empty_blocks_concurrent() lock the
-// _allocate_mutex while performing their respective list manipulations,
-// preventing them from interfering with each other.
+// _allocate_mutex while performing their respective list and array
+// manipulations, preventing them from interfering with each other.
 //
-// When allocate() creates a new block, it is added to the front of the
-// _active_list.  Then _active_head is set to the new block.  When concurrent
-// iteration is started (by a parallel worker thread calling the state's
-// iterate() function), the current _active_head is used as the initial block
-// for the iteration, with iteration proceeding down the list headed by that
-// block.
+// When allocate() creates a new block, it is added to the end of the
+// _active_array.  Then _active_array's _block_count is incremented to account
+// for the new block.  When concurrent iteration is started (by a parallel
+// worker thread calling the state's iterate() function), the current
+// _active_array and its _block_count are captured for use by the iteration,
+// with iteration processing all blocks in that array up to that block count.
 //
-// As a result, the list over which concurrent iteration operates is stable.
-// However, once the iteration is started, later allocations may add blocks to
-// the front of the list that won't be examined by the iteration.  And while
-// the list is stable, concurrent allocate() and release() operations may
-// change the set of allocated entries in a block at any time during the
-// iteration.
+// As a result, the sequence over which concurrent iteration operates is
+// stable.  However, once the iteration is started, later allocations may add
+// blocks to the end of the array that won't be examined by the iteration.
+// An allocation may even require expansion of the array, so the iteration is
+// no longer processing the current array, but rather the previous one.
+// And while the sequence is stable, concurrent allocate() and release()
+// operations may change the set of allocated entries in a block at any time
+// during the iteration.
 //
 // As a result, a concurrent iteration handler must accept that some
 // allocations and releases that occur after the iteration started will not be
@@ -138,36 +139,49 @@
 //   invoked on p.
 
 class OopStorage::BasicParState {
-  OopStorage* _storage;
-  void* volatile _next_block;
+  const OopStorage* _storage;
+  BlockArray* _active_array;
+  size_t _block_count;
+  volatile size_t _next_block;
+  uint _estimated_thread_count;
   bool _concurrent;
 
   // Noncopyable.
   BasicParState(const BasicParState&);
   BasicParState& operator=(const BasicParState&);
 
+  struct IterationData;
+
   void update_iteration_state(bool value);
-  void ensure_iteration_started();
-  Block* claim_next_block();
+  bool claim_next_segment(IterationData* data);
+  bool finish_iteration(const IterationData* data) const;
 
   // Wrapper for iteration handler; ignore handler result and return true.
   template<typename F> class AlwaysTrueFn;
 
 public:
-  BasicParState(OopStorage* storage, bool concurrent);
+  BasicParState(const OopStorage* storage,
+                uint estimated_thread_count,
+                bool concurrent);
   ~BasicParState();
 
   template<bool is_const, typename F> void iterate(F f);
+
+  static uint default_estimated_thread_count(bool concurrent);
 };
 
 template<bool concurrent, bool is_const>
 class OopStorage::ParState {
   BasicParState _basic_state;
 
+  typedef typename Conditional<is_const,
+                               const OopStorage*,
+                               OopStorage*>::type StoragePtr;
+
 public:
-  ParState(const OopStorage* storage) :
-    // For simplicity, always recorded as non-const.
-    _basic_state(const_cast<OopStorage*>(storage), concurrent)
+  ParState(StoragePtr storage,
+           uint estimated_thread_count = BasicParState::default_estimated_thread_count(concurrent)) :
+    _basic_state(storage, estimated_thread_count, concurrent)
   {}
 
   template<typename F> void iterate(F f);
@@ -179,8 +193,9 @@
   BasicParState _basic_state;
 
 public:
-  ParState(OopStorage* storage) :
-    _basic_state(storage, false)
+  ParState(OopStorage* storage,
+           uint estimated_thread_count = BasicParState::default_estimated_thread_count(false)) :
+    _basic_state(storage, estimated_thread_count, false)
   {}
 
   template<typename F> void iterate(F f);
--- a/src/hotspot/share/gc/shared/oopStorageParState.inline.hpp	Wed May 02 22:11:35 2018 -0700
+++ b/src/hotspot/share/gc/shared/oopStorageParState.inline.hpp	Fri May 04 08:50:01 2018 -0700
@@ -41,14 +41,26 @@
   bool operator()(OopPtr ptr) const { _f(ptr); return true; }
 };
 
+struct OopStorage::BasicParState::IterationData {
+  size_t _segment_start;
+  size_t _segment_end;
+  size_t _processed;
+};
+
 template<bool is_const, typename F>
 inline void OopStorage::BasicParState::iterate(F f) {
   // Wrap f in ATF so we can use Block::iterate.
   AlwaysTrueFn<F> atf_f(f);
-  ensure_iteration_started();
-  typename Conditional<is_const, const Block*, Block*>::type block;
-  while ((block = claim_next_block()) != NULL) {
-    block->iterate(atf_f);
+  IterationData data = {};      // zero initialize.
+  while (claim_next_segment(&data)) {
+    assert(data._segment_start < data._segment_end, "invariant");
+    assert(data._segment_end <= _block_count, "invariant");
+    typedef typename Conditional<is_const, const Block*, Block*>::type BlockPtr;
+    size_t i = data._segment_start;
+    do {
+      BlockPtr block = _active_array->at(i);
+      block->iterate(atf_f);
+    } while (++i < data._segment_end);
   }
 }
 
--- a/src/hotspot/share/gc/shared/preservedMarks.inline.hpp	Wed May 02 22:11:35 2018 -0700
+++ b/src/hotspot/share/gc/shared/preservedMarks.inline.hpp	Fri May 04 08:50:01 2018 -0700
@@ -26,6 +26,7 @@
 #define SHARE_VM_GC_SHARED_PRESERVEDMARKS_INLINE_HPP
 
 #include "gc/shared/preservedMarks.hpp"
+#include "logging/log.hpp"
 #include "oops/oop.inline.hpp"
 #include "utilities/stack.inline.hpp"
 
--- a/src/hotspot/share/gc/shared/referenceProcessor.cpp	Wed May 02 22:11:35 2018 -0700
+++ b/src/hotspot/share/gc/shared/referenceProcessor.cpp	Fri May 04 08:50:01 2018 -0700
@@ -92,37 +92,39 @@
   _discovering_refs = true;
 }
 
-ReferenceProcessor::ReferenceProcessor(MemRegion span,
+ReferenceProcessor::ReferenceProcessor(BoolObjectClosure* is_subject_to_discovery,
                                        bool      mt_processing,
                                        uint      mt_processing_degree,
                                        bool      mt_discovery,
                                        uint      mt_discovery_degree,
                                        bool      atomic_discovery,
                                        BoolObjectClosure* is_alive_non_header)  :
+  _is_subject_to_discovery(is_subject_to_discovery),
   _discovering_refs(false),
   _enqueuing_is_done(false),
   _is_alive_non_header(is_alive_non_header),
   _processing_is_mt(mt_processing),
   _next_id(0)
 {
-  _span = span;
+  assert(is_subject_to_discovery != NULL, "must be set");
+
   _discovery_is_atomic = atomic_discovery;
   _discovery_is_mt     = mt_discovery;
-  _num_q               = MAX2(1U, mt_processing_degree);
-  _max_num_q           = MAX2(_num_q, mt_discovery_degree);
+  _num_queues          = MAX2(1U, mt_processing_degree);
+  _max_num_queues      = MAX2(_num_queues, mt_discovery_degree);
   _discovered_refs     = NEW_C_HEAP_ARRAY(DiscoveredList,
-            _max_num_q * number_of_subclasses_of_ref(), mtGC);
+            _max_num_queues * number_of_subclasses_of_ref(), mtGC);
 
   if (_discovered_refs == NULL) {
     vm_exit_during_initialization("Could not allocated RefProc Array");
   }
   _discoveredSoftRefs    = &_discovered_refs[0];
-  _discoveredWeakRefs    = &_discoveredSoftRefs[_max_num_q];
-  _discoveredFinalRefs   = &_discoveredWeakRefs[_max_num_q];
-  _discoveredPhantomRefs = &_discoveredFinalRefs[_max_num_q];
+  _discoveredWeakRefs    = &_discoveredSoftRefs[_max_num_queues];
+  _discoveredFinalRefs   = &_discoveredWeakRefs[_max_num_queues];
+  _discoveredPhantomRefs = &_discoveredFinalRefs[_max_num_queues];
 
   // Initialize all entries to NULL
-  for (uint i = 0; i < _max_num_q * number_of_subclasses_of_ref(); i++) {
+  for (uint i = 0; i < _max_num_queues * number_of_subclasses_of_ref(); i++) {
     _discovered_refs[i].set_head(NULL);
     _discovered_refs[i].set_length(0);
   }
@@ -133,7 +135,7 @@
 #ifndef PRODUCT
 void ReferenceProcessor::verify_no_references_recorded() {
   guarantee(!_discovering_refs, "Discovering refs?");
-  for (uint i = 0; i < _max_num_q * number_of_subclasses_of_ref(); i++) {
+  for (uint i = 0; i < _max_num_queues * number_of_subclasses_of_ref(); i++) {
     guarantee(_discovered_refs[i].is_empty(),
               "Found non-empty discovered list at %u", i);
   }
@@ -141,7 +143,7 @@
 #endif
 
 void ReferenceProcessor::weak_oops_do(OopClosure* f) {
-  for (uint i = 0; i < _max_num_q * number_of_subclasses_of_ref(); i++) {
+  for (uint i = 0; i < _max_num_queues * number_of_subclasses_of_ref(); i++) {
     if (UseCompressedOops) {
       f->do_oop((narrowOop*)_discovered_refs[i].adr_head());
     } else {
@@ -181,7 +183,7 @@
 
 size_t ReferenceProcessor::total_count(DiscoveredList lists[]) const {
   size_t total = 0;
-  for (uint i = 0; i < _max_num_q; ++i) {
+  for (uint i = 0; i < _max_num_queues; ++i) {
     total += lists[i].length();
   }
   return total;
@@ -281,21 +283,21 @@
   log_develop_trace(gc, ref)("ReferenceProcessor::enqueue_discovered_reflist list " INTPTR_FORMAT, p2i(&refs_list));
 
   oop obj = NULL;
-  oop next_d = refs_list.head();
+  oop next_discovered = refs_list.head();
   // Walk down the list, self-looping the next field
   // so that the References are not considered active.
-  while (obj != next_d) {
-    obj = next_d;
+  while (obj != next_discovered) {
+    obj = next_discovered;
     assert(obj->is_instance(), "should be an instance object");
     assert(InstanceKlass::cast(obj->klass())->is_reference_instance_klass(), "should be reference object");
-    next_d = java_lang_ref_Reference::discovered(obj);
-    log_develop_trace(gc, ref)("        obj " INTPTR_FORMAT "/next_d " INTPTR_FORMAT, p2i(obj), p2i(next_d));
+    next_discovered = java_lang_ref_Reference::discovered(obj);
+    log_develop_trace(gc, ref)("        obj " INTPTR_FORMAT "/next_discovered " INTPTR_FORMAT, p2i(obj), p2i(next_discovered));
     assert(java_lang_ref_Reference::next(obj) == NULL,
            "Reference not active; should not be discovered");
     // Self-loop next, so as to make Ref not active.
     java_lang_ref_Reference::set_next_raw(obj, obj);
-    if (next_d != obj) {
-      HeapAccess<AS_NO_KEEPALIVE>::oop_store_at(obj, java_lang_ref_Reference::discovered_offset, next_d);
+    if (next_discovered != obj) {
+      HeapAccess<AS_NO_KEEPALIVE>::oop_store_at(obj, java_lang_ref_Reference::discovered_offset, next_discovered);
     } else {
       // This is the last object.
       // Swap refs_list into pending list and set obj's
@@ -319,14 +321,14 @@
   virtual void work(unsigned int work_id) {
     RefProcWorkerTimeTracker tt(ReferenceProcessorPhaseTimes::RefEnqueue, _phase_times, work_id);
 
-    assert(work_id < (unsigned int)_ref_processor.max_num_q(), "Index out-of-bounds");
+    assert(work_id < (unsigned int)_ref_processor.max_num_queues(), "Index out-of-bounds");
     // Simplest first cut: static partitioning.
     int index = work_id;
     // The increment on "index" must correspond to the maximum number of queues
     // (n_queues) with which that ReferenceProcessor was created.  That
     // is because of the "clever" way the discovered references lists were
     // allocated and are indexed into.
-    assert(_n_queues == (int) _ref_processor.max_num_q(), "Different number not expected");
+    assert(_n_queues == (int) _ref_processor.max_num_queues(), "Different number not expected");
     for (int j = 0;
          j < ReferenceProcessor::number_of_subclasses_of_ref();
          j++, index += _n_queues) {
@@ -350,11 +352,11 @@
 
   if (_processing_is_mt && task_executor != NULL) {
     // Parallel code
-    RefProcEnqueueTask tsk(*this, _discovered_refs, _max_num_q, phase_times);
+    RefProcEnqueueTask tsk(*this, _discovered_refs, _max_num_queues, phase_times);
     task_executor->execute(tsk);
   } else {
     // Serial code: call the parent class's implementation
-    for (uint i = 0; i < _max_num_q * number_of_subclasses_of_ref(); i++) {
+    for (uint i = 0; i < _max_num_queues * number_of_subclasses_of_ref(); i++) {
       enqueue_discovered_reflist(_discovered_refs[i]);
       _discovered_refs[i].set_head(NULL);
       _discovered_refs[i].set_length(0);
@@ -363,13 +365,14 @@
 }
 
 void DiscoveredListIterator::load_ptrs(DEBUG_ONLY(bool allow_null_referent)) {
-  _discovered_addr = java_lang_ref_Reference::discovered_addr_raw(_ref);
-  oop discovered = java_lang_ref_Reference::discovered(_ref);
-  assert(_discovered_addr && oopDesc::is_oop_or_null(discovered),
+  _current_discovered_addr = java_lang_ref_Reference::discovered_addr_raw(_current_discovered);
+  oop discovered = java_lang_ref_Reference::discovered(_current_discovered);
+  assert(_current_discovered_addr && oopDesc::is_oop_or_null(discovered),
          "Expected an oop or NULL for discovered field at " PTR_FORMAT, p2i(discovered));
-  _next = discovered;
-  _referent_addr = java_lang_ref_Reference::referent_addr_raw(_ref);
-  _referent = java_lang_ref_Reference::referent(_ref);
+  _next_discovered = discovered;
+
+  _referent_addr = java_lang_ref_Reference::referent_addr_raw(_current_discovered);
+  _referent = java_lang_ref_Reference::referent(_current_discovered);
   assert(Universe::heap()->is_in_reserved_or_null(_referent),
          "Wrong oop found in java.lang.Reference object");
   assert(allow_null_referent ?
@@ -381,23 +384,23 @@
 }
 
 void DiscoveredListIterator::remove() {
-  assert(oopDesc::is_oop(_ref), "Dropping a bad reference");
-  RawAccess<>::oop_store(_discovered_addr, oop(NULL));
+  assert(oopDesc::is_oop(_current_discovered), "Dropping a bad reference");
+  RawAccess<>::oop_store(_current_discovered_addr, oop(NULL));
 
   // First _prev_next ref actually points into DiscoveredList (gross).
   oop new_next;
-  if (_next == _ref) {
+  if (_next_discovered == _current_discovered) {
     // At the end of the list, we should make _prev point to itself.
     // If _ref is the first ref, then _prev_next will be in the DiscoveredList,
     // and _prev will be NULL.
-    new_next = _prev;
+    new_next = _prev_discovered;
   } else {
-    new_next = _next;
+    new_next = _next_discovered;
   }
   // Remove Reference object from discovered list. Note that G1 does not need a
   // pre-barrier here because we know the Reference has already been found/marked,
   // that's how it ended up in the discovered list in the first place.
-  RawAccess<>::oop_store(_prev_next, new_next);
+  RawAccess<>::oop_store(_prev_discovered_addr, new_next);
   NOT_PRODUCT(_removed++);
   _refs_list.dec_length(1);
 }
@@ -449,6 +452,19 @@
                              iter.removed(), iter.processed(), p2i(&refs_list));
 }
 
+void ReferenceProcessor::process_phase2(DiscoveredList&    refs_list,
+                                        BoolObjectClosure* is_alive,
+                                        OopClosure*        keep_alive,
+                                        VoidClosure*       complete_gc) {
+  if (discovery_is_atomic()) {
+    // complete_gc is ignored in this case for this phase
+    pp2_work(refs_list, is_alive, keep_alive);
+  } else {
+    assert(complete_gc != NULL, "Error");
+    pp2_work_concurrent_discovery(refs_list, is_alive,
+                                  keep_alive, complete_gc);
+  }
+}
 // Traverse the list and remove any Refs that are not active, or
 // whose referents are either alive or NULL.
 void
@@ -524,15 +540,11 @@
   )
 }
 
-// Traverse the list and process the referents, by either
-// clearing them or keeping them (and their reachable
-// closure) alive.
-void
-ReferenceProcessor::process_phase3(DiscoveredList&    refs_list,
-                                   bool               clear_referent,
-                                   BoolObjectClosure* is_alive,
-                                   OopClosure*        keep_alive,
-                                   VoidClosure*       complete_gc) {
+void ReferenceProcessor::process_phase3(DiscoveredList&    refs_list,
+                                        bool               clear_referent,
+                                        BoolObjectClosure* is_alive,
+                                        OopClosure*        keep_alive,
+                                        VoidClosure*       complete_gc) {
   ResourceMark rm;
   DiscoveredListIterator iter(refs_list, keep_alive, is_alive);
   while (iter.has_next()) {
@@ -568,8 +580,8 @@
 
 void ReferenceProcessor::abandon_partial_discovery() {
   // loop over the lists
-  for (uint i = 0; i < _max_num_q * number_of_subclasses_of_ref(); i++) {
-    if ((i % _max_num_q) == 0) {
+  for (uint i = 0; i < _max_num_queues * number_of_subclasses_of_ref(); i++) {
+    if ((i % _max_num_queues) == 0) {
       log_develop_trace(gc, ref)("Abandoning %s discovered list", list_name(i));
     }
     clear_discovered_references(_discovered_refs[i]);
@@ -677,7 +689,7 @@
   }
   log_develop_trace(gc, ref)("%s= " SIZE_FORMAT, st.as_string(), total_refs);
 #ifdef ASSERT
-  for (uint i = active_length; i < _max_num_q; i++) {
+  for (uint i = active_length; i < _max_num_queues; i++) {
     assert(ref_lists[i].length() == 0, SIZE_FORMAT " unexpected References in %u",
            ref_lists[i].length(), i);
   }
@@ -686,7 +698,7 @@
 #endif
 
 void ReferenceProcessor::set_active_mt_degree(uint v) {
-  _num_q = v;
+  _num_queues = v;
   _next_id = 0;
 }
 
@@ -700,20 +712,20 @@
   size_t total_refs = 0;
   log_develop_trace(gc, ref)("Balance ref_lists ");
 
-  for (uint i = 0; i < _max_num_q; ++i) {
+  for (uint i = 0; i < _max_num_queues; ++i) {
     total_refs += ref_lists[i].length();
   }
-  log_reflist_counts(ref_lists, _max_num_q, total_refs);
-  size_t avg_refs = total_refs / _num_q + 1;
+  log_reflist_counts(ref_lists, _max_num_queues, total_refs);
+  size_t avg_refs = total_refs / _num_queues + 1;
   uint to_idx = 0;
-  for (uint from_idx = 0; from_idx < _max_num_q; from_idx++) {
+  for (uint from_idx = 0; from_idx < _max_num_queues; from_idx++) {
     bool move_all = false;
-    if (from_idx >= _num_q) {
+    if (from_idx >= _num_queues) {
       move_all = ref_lists[from_idx].length() > 0;
     }
     while ((ref_lists[from_idx].length() > avg_refs) ||
            move_all) {
-      assert(to_idx < _num_q, "Sanity Check!");
+      assert(to_idx < _num_queues, "Sanity Check!");
       if (ref_lists[to_idx].length() < avg_refs) {
         // move superfluous refs
         size_t refs_to_move;
@@ -759,16 +771,16 @@
           break;
         }
       } else {
-        to_idx = (to_idx + 1) % _num_q;
+        to_idx = (to_idx + 1) % _num_queues;
       }
     }
   }
 #ifdef ASSERT
   size_t balanced_total_refs = 0;
-  for (uint i = 0; i < _num_q; ++i) {
+  for (uint i = 0; i < _num_queues; ++i) {
     balanced_total_refs += ref_lists[i].length();
   }
-  log_reflist_counts(ref_lists, _num_q, balanced_total_refs);
+  log_reflist_counts(ref_lists, _num_queues, balanced_total_refs);
   assert(total_refs == balanced_total_refs, "Balancing was incomplete");
 #endif
 }
@@ -811,7 +823,7 @@
       RefProcPhase1Task phase1(*this, refs_lists, policy, true /*marks_oops_alive*/, phase_times);
       task_executor->execute(phase1);
     } else {
-      for (uint i = 0; i < _max_num_q; i++) {
+      for (uint i = 0; i < _max_num_queues; i++) {
         process_phase1(refs_lists[i], policy,
                        is_alive, keep_alive, complete_gc);
       }
@@ -830,7 +842,7 @@
       RefProcPhase2Task phase2(*this, refs_lists, !discovery_is_atomic() /*marks_oops_alive*/, phase_times);
       task_executor->execute(phase2);
     } else {
-      for (uint i = 0; i < _max_num_q; i++) {
+      for (uint i = 0; i < _max_num_queues; i++) {
         process_phase2(refs_lists[i], is_alive, keep_alive, complete_gc);
       }
     }
@@ -845,7 +857,7 @@
       RefProcPhase3Task phase3(*this, refs_lists, clear_referent, true /*marks_oops_alive*/, phase_times);
       task_executor->execute(phase3);
     } else {
-      for (uint i = 0; i < _max_num_q; i++) {
+      for (uint i = 0; i < _max_num_queues; i++) {
         process_phase3(refs_lists[i], clear_referent,
                        is_alive, keep_alive, complete_gc);
       }
@@ -868,7 +880,7 @@
       id = next_id();
     }
   }
-  assert(id < _max_num_q, "Id is out-of-bounds id %u and max id %u)", id, _max_num_q);
+  assert(id < _max_num_queues, "Id is out-of-bounds id %u and max id %u)", id, _max_num_queues);
 
   // Get the discovered queue to which we will add
   DiscoveredList* list = NULL;
@@ -941,6 +953,10 @@
 }
 #endif
 
+bool ReferenceProcessor::is_subject_to_discovery(oop const obj) const {
+  return _is_subject_to_discovery->do_object_b(obj);
+}
+
 // We mention two of several possible choices here:
 // #0: if the reference object is not in the "originating generation"
 //     (or part of the heap being collected, indicated by our "span"
@@ -978,9 +994,8 @@
     return false;
   }
 
-  HeapWord* obj_addr = (HeapWord*)obj;
   if (RefDiscoveryPolicy == ReferenceBasedDiscovery &&
-      !_span.contains(obj_addr)) {
+      !is_subject_to_discovery(obj)) {
     // Reference is not in the originating generation;
     // don't treat it specially (i.e. we want to scan it as a normal
     // object with strong references).
@@ -1039,16 +1054,15 @@
     // Discover if and only if EITHER:
     // .. reference is in our span, OR
     // .. we are an atomic collector and referent is in our span
-    if (_span.contains(obj_addr) ||
+    if (is_subject_to_discovery(obj) ||
         (discovery_is_atomic() &&
-         _span.contains(java_lang_ref_Reference::referent(obj)))) {
-      // should_enqueue = true;
+         is_subject_to_discovery(java_lang_ref_Reference::referent(obj)))) {
     } else {
       return false;
     }
   } else {
     assert(RefDiscoveryPolicy == ReferenceBasedDiscovery &&
-           _span.contains(obj_addr), "code inconsistency");
+           is_subject_to_discovery(obj), "code inconsistency");
   }
 
   // Get the right type of discovered queue head.
@@ -1079,7 +1093,7 @@
 }
 
 bool ReferenceProcessor::has_discovered_references() {
-  for (uint i = 0; i < _max_num_q * number_of_subclasses_of_ref(); i++) {
+  for (uint i = 0; i < _max_num_queues * number_of_subclasses_of_ref(); i++) {
     if (!_discovered_refs[i].is_empty()) {
       return true;
     }
@@ -1101,7 +1115,7 @@
   // Soft references
   {
     GCTraceTime(Debug, gc, ref) tm("Preclean SoftReferences", gc_timer);
-    for (uint i = 0; i < _max_num_q; i++) {
+    for (uint i = 0; i < _max_num_queues; i++) {
       if (yield->should_return()) {
         return;
       }
@@ -1113,7 +1127,7 @@
   // Weak references
   {
     GCTraceTime(Debug, gc, ref) tm("Preclean WeakReferences", gc_timer);
-    for (uint i = 0; i < _max_num_q; i++) {
+    for (uint i = 0; i < _max_num_queues; i++) {
       if (yield->should_return()) {
         return;
       }
@@ -1125,7 +1139,7 @@
   // Final references
   {
     GCTraceTime(Debug, gc, ref) tm("Preclean FinalReferences", gc_timer);
-    for (uint i = 0; i < _max_num_q; i++) {
+    for (uint i = 0; i < _max_num_queues; i++) {
       if (yield->should_return()) {
         return;
       }
@@ -1137,7 +1151,7 @@
   // Phantom references
   {
     GCTraceTime(Debug, gc, ref) tm("Preclean PhantomReferences", gc_timer);
-    for (uint i = 0; i < _max_num_q; i++) {
+    for (uint i = 0; i < _max_num_queues; i++) {
       if (yield->should_return()) {
         return;
       }
@@ -1200,10 +1214,10 @@
 }
 
 const char* ReferenceProcessor::list_name(uint i) {
-   assert(i <= _max_num_q * number_of_subclasses_of_ref(),
+   assert(i <= _max_num_queues * number_of_subclasses_of_ref(),
           "Out of bounds index");
 
-   int j = i / _max_num_q;
+   int j = i / _max_num_queues;
    switch (j) {
      case 0: return "SoftRef";
      case 1: return "WeakRef";
--- a/src/hotspot/share/gc/shared/referenceProcessor.hpp	Wed May 02 22:11:35 2018 -0700
+++ b/src/hotspot/share/gc/shared/referenceProcessor.hpp	Fri May 04 08:50:01 2018 -0700
@@ -38,18 +38,13 @@
 // of java.lang.Reference objects for GC. The interface is useful for supporting
 // a generational abstraction, in particular when there are multiple
 // generations that are being independently collected -- possibly
-// concurrently and/or incrementally.  Note, however, that the
+// concurrently and/or incrementally.
 // ReferenceProcessor class abstracts away from a generational setting
-// by using only a heap interval (called "span" below), thus allowing
-// its use in a straightforward manner in a general, non-generational
-// setting.
+// by using a closure that determines whether a given reference or referent are
+// subject to this ReferenceProcessor's discovery, thus allowing its use in a
+// straightforward manner in a general, non-generational, non-contiguous generation
+// (or heap) setting.
 //
-// The basic idea is that each ReferenceProcessor object concerns
-// itself with ("weak") reference processing in a specific "span"
-// of the heap of interest to a specific collector. Currently,
-// the span is a convex interval of the heap, but, efficiency
-// apart, there seems to be no reason it couldn't be extended
-// (with appropriate modifications) to any "non-convex interval".
 
 // forward references
 class ReferencePolicy;
@@ -82,13 +77,15 @@
 class DiscoveredListIterator {
 private:
   DiscoveredList&    _refs_list;
-  HeapWord*          _prev_next;
-  oop                _prev;
-  oop                _ref;
-  HeapWord*          _discovered_addr;
-  oop                _next;
+  HeapWord*          _prev_discovered_addr;
+  oop                _prev_discovered;
+  oop                _current_discovered;
+  HeapWord*          _current_discovered_addr;
+  oop                _next_discovered;
+
   HeapWord*          _referent_addr;
   oop                _referent;
+
   OopClosure*        _keep_alive;
   BoolObjectClosure* _is_alive;
 
@@ -107,10 +104,10 @@
                                 BoolObjectClosure* is_alive);
 
   // End Of List.
-  inline bool has_next() const { return _ref != NULL; }
+  inline bool has_next() const { return _current_discovered != NULL; }
 
   // Get oop to the Reference object.
-  inline oop obj() const { return _ref; }
+  inline oop obj() const { return _current_discovered; }
 
   // Get oop to the referent object.
   inline oop referent() const { return _referent; }
@@ -129,8 +126,8 @@
 
   // Move to the next discovered reference.
   inline void next() {
-    _prev_next = _discovered_addr;
-    _prev = _ref;
+    _prev_discovered_addr = _current_discovered_addr;
+    _prev_discovered = _current_discovered;
     move_to_next();
   }
 
@@ -156,28 +153,26 @@
   )
 
   inline void move_to_next() {
-    if (_ref == _next) {
+    if (_current_discovered == _next_discovered) {
       // End of the list.
-      _ref = NULL;
+      _current_discovered = NULL;
     } else {
-      _ref = _next;
+      _current_discovered = _next_discovered;
     }
-    assert(_ref != _first_seen, "cyclic ref_list found");
+    assert(_current_discovered != _first_seen, "cyclic ref_list found");
     NOT_PRODUCT(_processed++);
   }
 };
 
 class ReferenceProcessor : public ReferenceDiscoverer {
-
- private:
   size_t total_count(DiscoveredList lists[]) const;
 
- protected:
   // The SoftReference master timestamp clock
   static jlong _soft_ref_timestamp_clock;
 
-  MemRegion   _span;                    // (right-open) interval of heap
-                                        // subject to wkref discovery
+  BoolObjectClosure* _is_subject_to_discovery; // determines whether a given oop is subject
+                                               // to this ReferenceProcessor's discovery
+                                               // (and further processing).
 
   bool        _discovering_refs;        // true when discovery enabled
   bool        _discovery_is_atomic;     // if discovery is atomic wrt
@@ -187,7 +182,7 @@
   bool        _enqueuing_is_done;       // true if all weak references enqueued
   bool        _processing_is_mt;        // true during phases when
                                         // reference processing is MT.
-  uint        _next_id;                 // round-robin mod _num_q counter in
+  uint        _next_id;                 // round-robin mod _num_queues counter in
                                         // support of work distribution
 
   // For collectors that do not keep GC liveness information
@@ -208,9 +203,9 @@
   // The discovered ref lists themselves
 
   // The active MT'ness degree of the queues below
-  uint             _num_q;
+  uint            _num_queues;
   // The maximum MT'ness degree of the queues below
-  uint             _max_num_q;
+  uint            _max_num_queues;
 
   // Master array of discovered oops
   DiscoveredList* _discovered_refs;
@@ -224,8 +219,8 @@
  public:
   static int number_of_subclasses_of_ref() { return (REF_PHANTOM - REF_OTHER); }
 
-  uint num_q()                             { return _num_q; }
-  uint max_num_q()                         { return _max_num_q; }
+  uint num_queues() const                  { return _num_queues; }
+  uint max_num_queues() const              { return _max_num_queues; }
   void set_active_mt_degree(uint v);
 
   DiscoveredList* discovered_refs()        { return _discovered_refs; }
@@ -257,19 +252,10 @@
                       VoidClosure*        complete_gc);
   // Phase2: remove all those references whose referents are
   // reachable.
-  inline void process_phase2(DiscoveredList&    refs_list,
-                             BoolObjectClosure* is_alive,
-                             OopClosure*        keep_alive,
-                             VoidClosure*       complete_gc) {
-    if (discovery_is_atomic()) {
-      // complete_gc is ignored in this case for this phase
-      pp2_work(refs_list, is_alive, keep_alive);
-    } else {
-      assert(complete_gc != NULL, "Error");
-      pp2_work_concurrent_discovery(refs_list, is_alive,
-                                    keep_alive, complete_gc);
-    }
-  }
+  void process_phase2(DiscoveredList&    refs_list,
+                      BoolObjectClosure* is_alive,
+                      OopClosure*        keep_alive,
+                      VoidClosure*       complete_gc);
   // Work methods in support of process_phase2
   void pp2_work(DiscoveredList&    refs_list,
                 BoolObjectClosure* is_alive,
@@ -280,7 +266,7 @@
                 OopClosure*        keep_alive,
                 VoidClosure*       complete_gc);
   // Phase3: process the referents by either clearing them
-  // or keeping them alive (and their closure)
+  // or keeping them alive (and their closure), and enqueuing them.
   void process_phase3(DiscoveredList&    refs_list,
                       bool               clear_referent,
                       BoolObjectClosure* is_alive,
@@ -306,13 +292,12 @@
                                       GCTimer*           gc_timer);
 
   // Returns the name of the discovered reference list
-  // occupying the i / _num_q slot.
+  // occupying the i / _num_queues slot.
   const char* list_name(uint i);
 
   void enqueue_discovered_reflists(AbstractRefProcTaskExecutor* task_executor,
                                    ReferenceProcessorPhaseTimes* phase_times);
 
- protected:
   // "Preclean" the given discovered reference list
   // by removing references with strongly reachable referents.
   // Currently used in support of CMS only.
@@ -321,15 +306,15 @@
                                    OopClosure*        keep_alive,
                                    VoidClosure*       complete_gc,
                                    YieldClosure*      yield);
-
-  // round-robin mod _num_q (not: _not_ mode _max_num_q)
+private:
+  // round-robin mod _num_queues (not: _not_ mod _max_num_queues)
   uint next_id() {
     uint id = _next_id;
     assert(!_discovery_is_mt, "Round robin should only be used in serial discovery");
-    if (++_next_id == _num_q) {
+    if (++_next_id == _num_queues) {
       _next_id = 0;
     }
-    assert(_next_id < _num_q, "_next_id %u _num_q %u _max_num_q %u", _next_id, _num_q, _max_num_q);
+    assert(_next_id < _num_queues, "_next_id %u _num_queues %u _max_num_queues %u", _next_id, _num_queues, _max_num_queues);
     return id;
   }
   DiscoveredList* get_discovered_list(ReferenceType rt);
@@ -346,9 +331,11 @@
   // Update (advance) the soft ref master clock field.
   void update_soft_ref_master_clock();
 
- public:
+  bool is_subject_to_discovery(oop const obj) const;
+
+public:
   // Default parameters give you a vanilla reference processor.
-  ReferenceProcessor(MemRegion span,
+  ReferenceProcessor(BoolObjectClosure* is_subject_to_discovery,
                      bool mt_processing = false, uint mt_processing_degree = 1,
                      bool mt_discovery  = false, uint mt_discovery_degree  = 1,
                      bool atomic_discovery = true,
@@ -373,9 +360,8 @@
     _is_alive_non_header = is_alive_non_header;
   }
 
-  // get and set span
-  MemRegion span()                   { return _span; }
-  void      set_span(MemRegion span) { _span = span; }
+  BoolObjectClosure* is_subject_to_discovery_closure() const { return _is_subject_to_discovery; }
+  void set_is_subject_to_discovery_closure(BoolObjectClosure* cl) { _is_subject_to_discovery = cl; }
 
   // start and stop weak ref discovery
   void enable_discovery(bool check_no_refs = true);
@@ -435,6 +421,26 @@
   void verify_referent(oop obj)        PRODUCT_RETURN;
 };
 
+// A subject-to-discovery closure that uses a single memory span to determine the area that
+// is subject to discovery. Useful for collectors which have contiguous generations.
+class SpanSubjectToDiscoveryClosure : public BoolObjectClosure {
+  MemRegion _span;
+
+public:
+  SpanSubjectToDiscoveryClosure() : BoolObjectClosure(), _span() { }
+  SpanSubjectToDiscoveryClosure(MemRegion span) : BoolObjectClosure(), _span(span) { }
+
+  MemRegion span() const { return _span; }
+
+  void set_span(MemRegion mr) {
+    _span = mr;
+  }
+
+  virtual bool do_object_b(oop obj) {
+    return _span.contains(obj);
+  }
+};
+
 // A utility class to disable reference discovery in
 // the scope which contains it, for given ReferenceProcessor.
 class NoRefDiscovery: StackObj {
@@ -456,24 +462,43 @@
   }
 };
 
+// A utility class to temporarily mutate the subject discovery closure of the
+// given ReferenceProcessor in the scope that contains it.
+class ReferenceProcessorSubjectToDiscoveryMutator : StackObj {
+  ReferenceProcessor* _rp;
+  BoolObjectClosure* _saved_cl;
+
+public:
+  ReferenceProcessorSubjectToDiscoveryMutator(ReferenceProcessor* rp, BoolObjectClosure* cl):
+    _rp(rp) {
+    _saved_cl = _rp->is_subject_to_discovery_closure();
+    _rp->set_is_subject_to_discovery_closure(cl);
+  }
+
+  ~ReferenceProcessorSubjectToDiscoveryMutator() {
+    _rp->set_is_subject_to_discovery_closure(_saved_cl);
+  }
+};
 
 // A utility class to temporarily mutate the span of the
 // given ReferenceProcessor in the scope that contains it.
-class ReferenceProcessorSpanMutator: StackObj {
- private:
+class ReferenceProcessorSpanMutator : StackObj {
   ReferenceProcessor* _rp;
-  MemRegion           _saved_span;
+  SpanSubjectToDiscoveryClosure _discoverer;
+  BoolObjectClosure* _old_discoverer;
 
- public:
+public:
   ReferenceProcessorSpanMutator(ReferenceProcessor* rp,
                                 MemRegion span):
-    _rp(rp) {
-    _saved_span = _rp->span();
-    _rp->set_span(span);
+    _rp(rp),
+    _discoverer(span),
+    _old_discoverer(rp->is_subject_to_discovery_closure()) {
+
+    rp->set_is_subject_to_discovery_closure(&_discoverer);
   }
 
   ~ReferenceProcessorSpanMutator() {
-    _rp->set_span(_saved_span);
+    _rp->set_is_subject_to_discovery_closure(_old_discoverer);
   }
 };
 
@@ -498,7 +523,6 @@
   }
 };
 
-
 // A utility class to temporarily change the disposition
 // of the "is_alive_non_header" closure field of the
 // given ReferenceProcessor in the scope that contains it.
--- a/src/hotspot/share/gc/shared/referenceProcessor.inline.hpp	Wed May 02 22:11:35 2018 -0700
+++ b/src/hotspot/share/gc/shared/referenceProcessor.inline.hpp	Fri May 04 08:50:01 2018 -0700
@@ -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
@@ -51,9 +51,9 @@
                                                OopClosure*        keep_alive,
                                                BoolObjectClosure* is_alive):
   _refs_list(refs_list),
-  _prev_next(refs_list.adr_head()),
-  _prev(NULL),
-  _ref(refs_list.head()),
+  _prev_discovered_addr(refs_list.adr_head()),
+  _prev_discovered(NULL),
+  _current_discovered(refs_list.head()),
 #ifdef ASSERT
   _first_seen(refs_list.head()),
 #endif
@@ -61,7 +61,7 @@
   _processed(0),
   _removed(0),
 #endif
-  _next(NULL),
+  _next_discovered(NULL),
   _keep_alive(keep_alive),
   _is_alive(is_alive) {
 }
--- a/src/hotspot/share/gc/shared/space.cpp	Wed May 02 22:11:35 2018 -0700
+++ b/src/hotspot/share/gc/shared/space.cpp	Fri May 04 08:50:01 2018 -0700
@@ -25,7 +25,6 @@
 #include "precompiled.hpp"
 #include "classfile/systemDictionary.hpp"
 #include "classfile/vmSymbols.hpp"
-#include "gc/serial/defNewGeneration.hpp"
 #include "gc/shared/blockOffsetTable.inline.hpp"
 #include "gc/shared/collectedHeap.inline.hpp"
 #include "gc/shared/genCollectedHeap.hpp"
@@ -44,6 +43,9 @@
 #include "utilities/copy.hpp"
 #include "utilities/globalDefinitions.hpp"
 #include "utilities/macros.hpp"
+#if INCLUDE_SERIALGC
+#include "gc/serial/defNewGeneration.hpp"
+#endif
 
 HeapWord* DirtyCardToOopClosure::get_actual_top(HeapWord* top,
                                                 HeapWord* top_obj) {
@@ -412,6 +414,8 @@
   return compact_top;
 }
 
+#if INCLUDE_SERIALGC
+
 void ContiguousSpace::prepare_for_compaction(CompactPoint* cp) {
   scan_and_forward(this, cp);
 }
@@ -429,6 +433,8 @@
   scan_and_compact(this);
 }
 
+#endif // INCLUDE_SERIALGC
+
 void Space::print_short() const { print_short_on(tty); }
 
 void Space::print_short_on(outputStream* st) const {
@@ -484,7 +490,7 @@
   return true;
 }
 
-#if INCLUDE_ALL_GCS
+#if INCLUDE_CMSGC
 #define ContigSpace_PAR_OOP_ITERATE_DEFN(OopClosureType, nv_suffix)         \
                                                                             \
   void ContiguousSpace::par_oop_iterate(MemRegion mr, OopClosureType* blk) {\
@@ -499,7 +505,7 @@
   ALL_PAR_OOP_ITERATE_CLOSURES(ContigSpace_PAR_OOP_ITERATE_DEFN)
 
 #undef ContigSpace_PAR_OOP_ITERATE_DEFN
-#endif // INCLUDE_ALL_GCS
+#endif // INCLUDE_CMSGC
 
 void ContiguousSpace::oop_iterate(ExtendedOopClosure* blk) {
   if (is_empty()) return;
--- a/src/hotspot/share/gc/shared/space.hpp	Wed May 02 22:11:35 2018 -0700
+++ b/src/hotspot/share/gc/shared/space.hpp	Fri May 04 08:50:01 2018 -0700
@@ -220,9 +220,11 @@
   // Allocation (return NULL if full).  Enforces mutual exclusion internally.
   virtual HeapWord* par_allocate(size_t word_size) = 0;
 
+#if INCLUDE_SERIALGC
   // Mark-sweep-compact support: all spaces can update pointers to objects
   // moving as a part of compaction.
   virtual void adjust_pointers() = 0;
+#endif
 
   virtual void print() const;
   virtual void print_on(outputStream* st) const;
@@ -405,6 +407,7 @@
     _next_compaction_space = csp;
   }
 
+#if INCLUDE_SERIALGC
   // MarkSweep support phase2
 
   // Start the process of compaction of the current space: compute
@@ -420,6 +423,7 @@
   virtual void adjust_pointers();
   // MarkSweep support phase4
   virtual void compact();
+#endif // INCLUDE_SERIALGC
 
   // The maximum percentage of objects that can be dead in the compacted
   // live part of a compacted space ("deadwood" support.)
@@ -474,9 +478,11 @@
   // and possibly also overriding obj_size(), and adjust_obj_size().
   // These functions should avoid virtual calls whenever possible.
 
+#if INCLUDE_SERIALGC
   // Frequently calls adjust_obj_size().
   template <class SpaceType>
   static inline void scan_and_adjust_pointers(SpaceType* space);
+#endif
 
   // Frequently calls obj_size().
   template <class SpaceType>
@@ -603,14 +609,14 @@
   }
 
 
-#if INCLUDE_ALL_GCS
+#if INCLUDE_CMSGC
   // In support of parallel oop_iterate.
   #define ContigSpace_PAR_OOP_ITERATE_DECL(OopClosureType, nv_suffix)  \
     void par_oop_iterate(MemRegion mr, OopClosureType* blk);
 
     ALL_PAR_OOP_ITERATE_CLOSURES(ContigSpace_PAR_OOP_ITERATE_DECL)
   #undef ContigSpace_PAR_OOP_ITERATE_DECL
-#endif // INCLUDE_ALL_GCS
+#endif // INCLUDE_CMSGC
 
   // Compaction support
   virtual void reset_after_compaction() {
@@ -654,8 +660,10 @@
   HeapWord** top_addr() { return &_top; }
   HeapWord** end_addr() { return &_end; }
 
+#if INCLUDE_SERIALGC
   // Overrides for more efficient compaction support.
   void prepare_for_compaction(CompactPoint* cp);
+#endif
 
   virtual void print_on(outputStream* st) const;
 
--- a/src/hotspot/share/gc/shared/space.inline.hpp	Wed May 02 22:11:35 2018 -0700
+++ b/src/hotspot/share/gc/shared/space.inline.hpp	Fri May 04 08:50:01 2018 -0700
@@ -25,7 +25,6 @@
 #ifndef SHARE_VM_GC_SHARED_SPACE_INLINE_HPP
 #define SHARE_VM_GC_SHARED_SPACE_INLINE_HPP
 
-#include "gc/serial/markSweep.inline.hpp"
 #include "gc/shared/collectedHeap.hpp"
 #include "gc/shared/generation.hpp"
 #include "gc/shared/space.hpp"
@@ -35,6 +34,9 @@
 #include "oops/oop.inline.hpp"
 #include "runtime/prefetch.inline.hpp"
 #include "runtime/safepoint.hpp"
+#if INCLUDE_SERIALGC
+#include "gc/serial/markSweep.inline.hpp"
+#endif
 
 inline HeapWord* Space::block_start(const void* p) {
   return block_start_const(p);
@@ -77,6 +79,8 @@
   return oop(addr)->size();
 }
 
+#if INCLUDE_SERIALGC
+
 class DeadSpacer : StackObj {
   size_t _allowed_deadspace_words;
   bool _active;
@@ -347,6 +351,8 @@
   clear_empty_region(space);
 }
 
+#endif // INCLUDE_SERIALGC
+
 size_t ContiguousSpace::scanned_block_size(const HeapWord* addr) const {
   return oop(addr)->size();
 }
--- a/src/hotspot/share/gc/shared/specialized_oop_closures.hpp	Wed May 02 22:11:35 2018 -0700
+++ b/src/hotspot/share/gc/shared/specialized_oop_closures.hpp	Fri May 04 08:50:01 2018 -0700
@@ -25,12 +25,16 @@
 #ifndef SHARE_VM_GC_SHARED_SPECIALIZED_OOP_CLOSURES_HPP
 #define SHARE_VM_GC_SHARED_SPECIALIZED_OOP_CLOSURES_HPP
 
+#include "utilities/macros.hpp"
+#if INCLUDE_CMSGC
+#include "gc/cms/cms_specialized_oop_closures.hpp"
+#endif
+#if INCLUDE_G1GC
+#include "gc/g1/g1_specialized_oop_closures.hpp"
+#endif
+#if INCLUDE_SERIALGC
 #include "gc/serial/serial_specialized_oop_closures.hpp"
-#include "utilities/macros.hpp"
-#if INCLUDE_ALL_GCS
-#include "gc/cms/cms_specialized_oop_closures.hpp"
-#include "gc/g1/g1_specialized_oop_closures.hpp"
-#endif // INCLUDE_ALL_GCS
+#endif
 
 // The following OopClosure types get specialized versions of
 // "oop_oop_iterate" that invoke the closures' do_oop methods
@@ -56,14 +60,14 @@
 
 #define SPECIALIZED_OOP_OOP_ITERATE_CLOSURES_1(f)                 \
   f(NoHeaderExtendedOopClosure,_nv)                               \
-               SPECIALIZED_OOP_OOP_ITERATE_CLOSURES_S(f)          \
-  ALL_GCS_ONLY(SPECIALIZED_OOP_OOP_ITERATE_CLOSURES_P(f))
+  SERIALGC_ONLY(SPECIALIZED_OOP_OOP_ITERATE_CLOSURES_S(f))        \
+     CMSGC_ONLY(SPECIALIZED_OOP_OOP_ITERATE_CLOSURES_P(f))
 
 #define SPECIALIZED_OOP_OOP_ITERATE_CLOSURES_2(f)                 \
-               SPECIALIZED_OOP_OOP_ITERATE_CLOSURES_MS(f)         \
-  ALL_GCS_ONLY(SPECIALIZED_OOP_OOP_ITERATE_CLOSURES_CMS(f))       \
-  ALL_GCS_ONLY(SPECIALIZED_OOP_OOP_ITERATE_CLOSURES_G1(f))        \
-  ALL_GCS_ONLY(SPECIALIZED_OOP_OOP_ITERATE_CLOSURES_G1FULL(f))
+  SERIALGC_ONLY(SPECIALIZED_OOP_OOP_ITERATE_CLOSURES_MS(f))       \
+     CMSGC_ONLY(SPECIALIZED_OOP_OOP_ITERATE_CLOSURES_CMS(f))      \
+      G1GC_ONLY(SPECIALIZED_OOP_OOP_ITERATE_CLOSURES_G1(f))       \
+      G1GC_ONLY(SPECIALIZED_OOP_OOP_ITERATE_CLOSURES_G1FULL(f))
 
 // We separate these out, because sometime the general one has
 // a different definition from the specialized ones, and sometimes it
@@ -85,7 +89,7 @@
 
 #define ALL_PAR_OOP_ITERATE_CLOSURES(f)                           \
   f(ExtendedOopClosure,_v)                                        \
-  ALL_GCS_ONLY(SPECIALIZED_PAR_OOP_ITERATE_CLOSURES(f))
+  CMSGC_ONLY(SPECIALIZED_PAR_OOP_ITERATE_CLOSURES(f))
 
 // This macro applies an argument macro to all OopClosures for which we
 // want specialized bodies of a family of methods related to
@@ -94,8 +98,8 @@
 // "OopClosure" in some applications and "OopsInGenClosure" in others.
 
 #define SPECIALIZED_SINCE_SAVE_MARKS_CLOSURES_YOUNG(f)  \
-               SPECIALIZED_SINCE_SAVE_MARKS_CLOSURES_YOUNG_S(f)   \
-  ALL_GCS_ONLY(SPECIALIZED_SINCE_SAVE_MARKS_CLOSURES_YOUNG_P(f))
+  SERIALGC_ONLY(SPECIALIZED_SINCE_SAVE_MARKS_CLOSURES_YOUNG_S(f))   \
+     CMSGC_ONLY(SPECIALIZED_SINCE_SAVE_MARKS_CLOSURES_YOUNG_P(f))
 
 #define SPECIALIZED_SINCE_SAVE_MARKS_CLOSURES(f)                  \
   SPECIALIZED_SINCE_SAVE_MARKS_CLOSURES_YOUNG(f)
--- a/src/hotspot/share/gc/shared/vmGCOperations.cpp	Wed May 02 22:11:35 2018 -0700
+++ b/src/hotspot/share/gc/shared/vmGCOperations.cpp	Fri May 04 08:50:01 2018 -0700
@@ -38,10 +38,10 @@
 #include "utilities/dtrace.hpp"
 #include "utilities/macros.hpp"
 #include "utilities/preserveException.hpp"
-#if INCLUDE_ALL_GCS
+#if INCLUDE_G1GC
 #include "gc/g1/g1CollectedHeap.inline.hpp"
 #include "gc/g1/g1Policy.hpp"
-#endif // INCLUDE_ALL_GCS
+#endif // INCLUDE_G1GC
 
 VM_GC_Operation::~VM_GC_Operation() {
   CollectedHeap* ch = Universe::heap();
@@ -193,12 +193,14 @@
 
 // Returns true iff concurrent GCs unloads metadata.
 bool VM_CollectForMetadataAllocation::initiate_concurrent_GC() {
-#if INCLUDE_ALL_GCS
+#if INCLUDE_CMSGC
   if (UseConcMarkSweepGC && CMSClassUnloadingEnabled) {
     MetaspaceGC::set_should_concurrent_collect(true);
     return true;
   }
+#endif
 
+#if INCLUDE_G1GC
   if (UseG1GC && ClassUnloadingWithConcurrentMark) {
     G1CollectedHeap* g1h = G1CollectedHeap::heap();
     g1h->g1_policy()->collector_state()->set_initiate_conc_mark_if_possible(true);
--- a/src/hotspot/share/gc/shared/vmStructs_gc.hpp	Wed May 02 22:11:35 2018 -0700
+++ b/src/hotspot/share/gc/shared/vmStructs_gc.hpp	Fri May 04 08:50:01 2018 -0700
@@ -25,6 +25,7 @@
 #ifndef SHARE_GC_SHARED_VMSTRUCTS_GC_HPP
 #define SHARE_GC_SHARED_VMSTRUCTS_GC_HPP
 
+#include "gc/shared/ageTable.hpp"
 #include "gc/shared/cardGeneration.hpp"
 #include "gc/shared/cardTableRS.hpp"
 #include "gc/shared/collectedHeap.hpp"
@@ -33,30 +34,36 @@
 #include "gc/shared/generationSpec.hpp"
 #include "gc/shared/oopStorage.hpp"
 #include "gc/shared/space.hpp"
+#if INCLUDE_CMSGC
+#include "gc/cms/vmStructs_cms.hpp"
+#endif
+#if INCLUDE_G1GC
+#include "gc/g1/vmStructs_g1.hpp"
+#endif
+#if INCLUDE_PARALLELGC
+#include "gc/parallel/vmStructs_parallelgc.hpp"
+#endif
+#if INCLUDE_SERIALGC
 #include "gc/serial/defNewGeneration.hpp"
 #include "gc/serial/vmStructs_serial.hpp"
-#if INCLUDE_ALL_GCS
-#include "gc/cms/vmStructs_cms.hpp"
-#include "gc/g1/vmStructs_g1.hpp"
-#include "gc/parallel/vmStructs_parallelgc.hpp"
 #endif
 
 #define VM_STRUCTS_GC(nonstatic_field,                                                                                               \
                       volatile_nonstatic_field,                                                                                      \
                       static_field,                                                                                                  \
                       unchecked_nonstatic_field)                                                                                     \
-  ALL_GCS_ONLY(VM_STRUCTS_CMSGC(nonstatic_field,                                                                                     \
-                                volatile_nonstatic_field,                                                                            \
-                                static_field))                                                                                       \
-  ALL_GCS_ONLY(VM_STRUCTS_G1GC(nonstatic_field,                                                                                      \
-                               volatile_nonstatic_field,                                                                             \
-                               static_field))                                                                                        \
-  ALL_GCS_ONLY(VM_STRUCTS_PARALLELGC(nonstatic_field,                                                                                \
-                                     volatile_nonstatic_field,                                                                       \
-                                     static_field))                                                                                  \
-  VM_STRUCTS_SERIALGC(nonstatic_field,                                                                                               \
-                      volatile_nonstatic_field,                                                                                      \
-                      static_field)