diff --git a/.hgtags b/.hgtags index f43637f7385..94e3649928c 100644 --- a/.hgtags +++ b/.hgtags @@ -551,3 +551,4 @@ b67884871b5fff79c5ef3eb8ac74dd48d71ea9b1 jdk-12+33 1d7aec80147a6d92b101a76aef92f3ddc88bedf4 jdk-13+12 b67884871b5fff79c5ef3eb8ac74dd48d71ea9b1 jdk-12-ga 83cace4142c8563b6a921787db02388e1bc48d01 jdk-13+13 +46cf212cdccaf4fb064d913b12004007d3322b67 jdk-13+14 diff --git a/doc/testing.html b/doc/testing.html index c35ee54b849..5f821df39e0 100644 --- a/doc/testing.html +++ b/doc/testing.html @@ -39,7 +39,7 @@
This new way of running tests is developer-centric. It assumes that you have built a JDK locally and want to test it. Running common test targets is simple, and more complex ad-hoc combination of tests is possible. The user interface is forgiving, and clearly report errors it cannot resolve.
The main target test uses the jdk-image as the tested product. There is also an alternate target exploded-test that uses the exploded image instead. Not all tests will run successfully on the exploded image, but using this target can greatly improve rebuild times for certain workflows.
Previously, make test was used invoke an old system for running test, and make run-test was used for the new test framework. For backward compatibility with scripts and muscle memory, run-test (and variants like exploded-run-test or run-test-tier1) are kept as aliases. The old system can still be accessed for some time using cd test && make.
Previously, make test was used to invoke an old system for running tests, and make run-test was used for the new test framework. For backward compatibility with scripts and muscle memory, run-test (and variants like exploded-run-test or run-test-tier1) are kept as aliases.
Some example command-lines:
$ make test-tier1
$ make test-jdk_lang JTREG="JOBS=8"
diff --git a/doc/testing.md b/doc/testing.md
index 669cf9c6a16..61302e23b8f 100644
--- a/doc/testing.md
+++ b/doc/testing.md
@@ -12,11 +12,10 @@ also an alternate target `exploded-test` that uses the exploded image
instead. Not all tests will run successfully on the exploded image, but using
this target can greatly improve rebuild times for certain workflows.
-Previously, `make test` was used invoke an old system for running test, and
+Previously, `make test` was used to invoke an old system for running tests, and
`make run-test` was used for the new test framework. For backward compatibility
with scripts and muscle memory, `run-test` (and variants like
-`exploded-run-test` or `run-test-tier1`) are kept as aliases. The old system
-can still be accessed for some time using `cd test && make`.
+`exploded-run-test` or `run-test-tier1`) are kept as aliases.
Some example command-lines:
diff --git a/make/Bundles.gmk b/make/Bundles.gmk
index 5ccace6a6d1..7d85b504429 100644
--- a/make/Bundles.gmk
+++ b/make/Bundles.gmk
@@ -1,5 +1,5 @@
#
-# Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2016, 2019, Oracle and/or its affiliates. All rights reserved.
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
#
# This code is free software; you can redistribute it and/or modify it
@@ -29,6 +29,7 @@ include $(SPEC)
include MakeBase.gmk
PRODUCT_TARGETS :=
+LEGACY_TARGETS :=
TEST_TARGETS :=
DOCS_TARGETS :=
@@ -146,19 +147,25 @@ endef
# correct base directories.
ifeq ($(call isTargetOs, macosx)+$(DEBUG_LEVEL), true+release)
JDK_IMAGE_DIR := $(JDK_MACOSX_BUNDLE_DIR)
+ JRE_IMAGE_DIR := $(JRE_MACOSX_BUNDLE_DIR)
JDK_IMAGE_HOMEDIR := $(JDK_MACOSX_CONTENTS_DIR)/Home
+ JRE_IMAGE_HOMEDIR := $(JRE_MACOSX_CONTENTS_DIR)/Home
JDK_BUNDLE_SUBDIR :=
+ JRE_BUNDLE_SUBDIR :=
else
JDK_IMAGE_HOMEDIR := $(JDK_IMAGE_DIR)
+ JRE_IMAGE_HOMEDIR := $(JRE_IMAGE_DIR)
JDK_BUNDLE_SUBDIR := jdk-$(VERSION_NUMBER)
+ JRE_BUNDLE_SUBDIR := jre-$(VERSION_NUMBER)
ifneq ($(DEBUG_LEVEL), release)
JDK_BUNDLE_SUBDIR := $(JDK_BUNDLE_SUBDIR)/$(DEBUG_LEVEL)
+ JRE_BUNDLE_SUBDIR := $(JRE_BUNDLE_SUBDIR)/$(DEBUG_LEVEL)
endif
endif
################################################################################
-ifneq ($(filter product-bundles, $(MAKECMDGOALS)), )
+ifneq ($(filter product-bundles legacy-bundles, $(MAKECMDGOALS)), )
$(eval $(call FillCacheFind, $(IMAGES_OUTPUTDIR)))
SYMBOLS_EXCLUDE_PATTERN := %.debuginfo %.diz %.pdb %.map
@@ -198,6 +205,22 @@ ifneq ($(filter product-bundles, $(MAKECMDGOALS)), )
TEST_DEMOS_BUNDLE_FILES := $(filter $(JDK_IMAGE_HOMEDIR)/demo/%, $(ALL_JDK_FILES))
+ ALL_JRE_FILES := $(call CacheFind, $(JRE_IMAGE_DIR))
+
+ # Create special filter rules when dealing with unzipped .dSYM directories on
+ # macosx
+ ifeq ($(OPENJDK_TARGET_OS), macosx)
+ ifeq ($(ZIP_EXTERNAL_DEBUG_SYMBOLS), false)
+ JRE_SYMBOLS_EXCLUDE_PATTERN := $(addprefix %, \
+ $(call containing, .dSYM/, $(patsubst $(JRE_IMAGE_DIR)/%, %, $(ALL_JRE_FILES))))
+ endif
+ endif
+
+ JRE_BUNDLE_FILES := $(filter-out \
+ $(JRE_SYMBOLS_EXCLUDE_PATTERN) \
+ $(SYMBOLS_EXCLUDE_PATTERN), \
+ $(ALL_JRE_FILES))
+
$(eval $(call SetupBundleFile, BUILD_JDK_BUNDLE, \
BUNDLE_NAME := $(JDK_BUNDLE_NAME), \
FILES := $(JDK_BUNDLE_FILES), \
@@ -208,6 +231,15 @@ ifneq ($(filter product-bundles, $(MAKECMDGOALS)), )
PRODUCT_TARGETS += $(BUILD_JDK_BUNDLE)
+ $(eval $(call SetupBundleFile, BUILD_JRE_BUNDLE, \
+ BUNDLE_NAME := $(JRE_BUNDLE_NAME), \
+ FILES := $(JRE_BUNDLE_FILES), \
+ BASE_DIRS := $(JRE_IMAGE_DIR), \
+ SUBDIR := $(JRE_BUNDLE_SUBDIR), \
+ ))
+
+ LEGACY_TARGETS += $(BUILD_JRE_BUNDLE)
+
$(eval $(call SetupBundleFile, BUILD_JDK_SYMBOLS_BUNDLE, \
BUNDLE_NAME := $(JDK_SYMBOLS_BUNDLE_NAME), \
FILES := $(JDK_SYMBOLS_BUNDLE_FILES), \
@@ -283,6 +315,7 @@ $(eval $(call IncludeCustomExtension, Bundles.gmk))
################################################################################
product-bundles: $(PRODUCT_TARGETS)
+legacy-bundles: $(LEGACY_TARGETS)
test-bundles: $(TEST_TARGETS)
docs-bundles: $(DOCS_TARGETS)
jcov-bundles: $(JCOV_TARGETS)
diff --git a/make/Main.gmk b/make/Main.gmk
index 2bb646f4280..0e5ff72b2a6 100644
--- a/make/Main.gmk
+++ b/make/Main.gmk
@@ -581,6 +581,9 @@ ALL_TARGETS += test exploded-test jcov-test
product-bundles:
+($(CD) $(TOPDIR)/make && $(MAKE) $(MAKE_ARGS) -f Bundles.gmk product-bundles)
+legacy-bundles:
+ +($(CD) $(TOPDIR)/make && $(MAKE) $(MAKE_ARGS) -f Bundles.gmk legacy-bundles)
+
test-bundles:
+($(CD) $(TOPDIR)/make && $(MAKE) $(MAKE_ARGS) -f Bundles.gmk test-bundles)
@@ -592,7 +595,7 @@ ifeq ($(JCOV_ENABLED), true)
+($(CD) $(TOPDIR)/make && $(MAKE) $(MAKE_ARGS) -f Bundles.gmk jcov-bundles)
endif
-ALL_TARGETS += product-bundles test-bundles docs-bundles jcov-bundles
+ALL_TARGETS += product-bundles legacy-bundles test-bundles docs-bundles jcov-bundles
################################################################################
# Install targets
@@ -918,6 +921,8 @@ else
product-bundles: product-images
+ legacy-bundles: legacy-images
+
test-bundles: test-image
docs-bundles: docs-image
@@ -1020,6 +1025,9 @@ mac-bundles: mac-jdk-bundle
# (and possibly other, more specific versions)
product-images: jdk-image symbols-image exploded-image
+# This target builds the legacy images, e.g. the legacy JRE image
+legacy-images: legacy-jre-image
+
# zip-security is actually a bundle, but for now it needs to be considered
# an image until this can be cleaned up properly.
product-images: zip-security
@@ -1036,6 +1044,8 @@ endif
ifeq ($(call isTargetOs, macosx), true)
product-images: mac-jdk-bundle
+
+ legacy-images: mac-legacy-jre-bundle
endif
# This target builds the documentation image
@@ -1070,7 +1080,7 @@ ALL_TARGETS += buildtools hotspot hotspot-libs hotspot-gensrc gensrc gendata \
jdk.jdwp.agent-gensrc $(ALL_MODULES) demos \
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 \
+ docs-javase docs-reference docs-javadoc mac-bundles product-images legacy-images \
docs-image test-image all-images \
all-bundles
diff --git a/make/autoconf/jdk-version.m4 b/make/autoconf/jdk-version.m4
index 3cbd0ecd6f9..48a5e079091 100644
--- a/make/autoconf/jdk-version.m4
+++ b/make/autoconf/jdk-version.m4
@@ -460,6 +460,7 @@ AC_DEFUN_ONCE([JDKVER_SETUP_JDK_VERSION_NUMBERS],
# We could define --with flags for these, if really needed
VERSION_CLASSFILE_MAJOR="$DEFAULT_VERSION_CLASSFILE_MAJOR"
VERSION_CLASSFILE_MINOR="$DEFAULT_VERSION_CLASSFILE_MINOR"
+ JDK_SOURCE_TARGET_VERSION="$DEFAULT_JDK_SOURCE_TARGET_VERSION"
AC_MSG_CHECKING([for version string])
AC_MSG_RESULT([$VERSION_STRING])
@@ -483,5 +484,5 @@ AC_DEFUN_ONCE([JDKVER_SETUP_JDK_VERSION_NUMBERS],
AC_SUBST(VENDOR_VERSION_STRING)
AC_SUBST(VERSION_CLASSFILE_MAJOR)
AC_SUBST(VERSION_CLASSFILE_MINOR)
-
+ AC_SUBST(JDK_SOURCE_TARGET_VERSION)
])
diff --git a/make/autoconf/lib-x11.m4 b/make/autoconf/lib-x11.m4
index dca12ed8a03..7883698bdd5 100644
--- a/make/autoconf/lib-x11.m4
+++ b/make/autoconf/lib-x11.m4
@@ -119,7 +119,7 @@ AC_DEFUN_ONCE([LIB_SETUP_X11],
if test "x$X11_HEADERS_OK" = xno; then
HELP_MSG_MISSING_DEPENDENCY([x11])
- AC_MSG_ERROR([Could not find all X11 headers (shape.h Xrender.h Xrander.h XTest.h Intrinsic.h). $HELP_MSG])
+ AC_MSG_ERROR([Could not find all X11 headers (shape.h Xrender.h Xrandr.h XTest.h Intrinsic.h). $HELP_MSG])
fi
# If XLinearGradient isn't available in Xrender.h, signal that it needs to be
diff --git a/make/autoconf/spec.gmk.in b/make/autoconf/spec.gmk.in
index a8f80a8d2c0..bdb628e120e 100644
--- a/make/autoconf/spec.gmk.in
+++ b/make/autoconf/spec.gmk.in
@@ -208,6 +208,8 @@ VENDOR_VERSION_STRING := @VENDOR_VERSION_STRING@
VERSION_CLASSFILE_MAJOR := @VERSION_CLASSFILE_MAJOR@
VERSION_CLASSFILE_MINOR := @VERSION_CLASSFILE_MINOR@
+JDK_SOURCE_TARGET_VERSION := @JDK_SOURCE_TARGET_VERSION@
+
# Convenience CFLAGS settings for passing version information into native programs.
VERSION_CFLAGS := \
-DVERSION_FEATURE=$(VERSION_FEATURE) \
@@ -904,6 +906,7 @@ else
JDK_BUNDLE_EXTENSION := tar.gz
endif
JDK_BUNDLE_NAME := jdk-$(BASE_NAME)_bin$(DEBUG_PART).$(JDK_BUNDLE_EXTENSION)
+JRE_BUNDLE_NAME := jre-$(BASE_NAME)_bin$(DEBUG_PART).$(JDK_BUNDLE_EXTENSION)
JDK_SYMBOLS_BUNDLE_NAME := jdk-$(BASE_NAME)_bin$(DEBUG_PART)-symbols.tar.gz
TEST_DEMOS_BUNDLE_NAME := jdk-$(BASE_NAME)_bin-tests-demos$(DEBUG_PART).tar.gz
TEST_BUNDLE_NAME := jdk-$(BASE_NAME)_bin-tests$(DEBUG_PART).tar.gz
@@ -911,6 +914,7 @@ DOCS_BUNDLE_NAME := jdk-$(BASE_NAME)_doc-api-spec$(DEBUG_PART).tar.gz
JCOV_BUNDLE_NAME := jdk-jcov-$(BASE_NAME)_bin$(DEBUG_PART).$(JDK_BUNDLE_EXTENSION)
JDK_BUNDLE := $(BUNDLES_OUTPUTDIR)/$(JDK_BUNDLE_NAME)
+JRE_BUNDLE := $(BUNDLES_OUTPUTDIR)/$(JRE_BUNDLE_NAME)
JDK_SYMBOLS_BUNDLE := $(BUNDLES_OUTPUTDIR)/$(JDK_SYMBOLS_BUNDLE_NAME)
TEST_DEMOS_BUNDLE := $(BUNDLES_OUTPUTDIR)/$(TEST_DEMOS_BUNDLE_NAME)
TEST_BUNDLE := $(BUNDLES_OUTPUTDIR)/$(TEST_BUNDLE_NAME)
diff --git a/make/autoconf/toolchain_windows.m4 b/make/autoconf/toolchain_windows.m4
index 4969dffb270..4c533f52161 100644
--- a/make/autoconf/toolchain_windows.m4
+++ b/make/autoconf/toolchain_windows.m4
@@ -87,6 +87,7 @@ VS_SDK_INSTALLDIR_2017=
VS_VS_PLATFORM_NAME_2017="v141"
VS_SDK_PLATFORM_NAME_2017=
VS_SUPPORTED_2017=true
+VS_TOOLSET_SUPPORTED_2017=true
################################################################################
@@ -177,6 +178,15 @@ AC_DEFUN([TOOLCHAIN_CHECK_POSSIBLE_WIN_SDK_ROOT],
# build environment and assigns it to VS_ENV_CMD
AC_DEFUN([TOOLCHAIN_FIND_VISUAL_STUDIO_BAT_FILE],
[
+ # VS2017 provides the option to install previous minor versions of the MSVC
+ # toolsets. It is not possible to directly download earlier minor versions of
+ # VS2017 and in order to build with a previous minor compiler toolset version,
+ # it is now possible to compile with earlier minor versions by passing
+ # -vcvars_ver= argument to vcvarsall.bat.
+ AC_ARG_WITH(msvc-toolset-version, [AS_HELP_STRING([--with-msvc-toolset-version],
+ [specific MSVC toolset version to use, passed as -vcvars_ver argument to
+ pass to vcvarsall.bat (Windows only)])])
+
VS_VERSION="$1"
eval VS_COMNTOOLS_VAR="\${VS_ENVVAR_${VS_VERSION}}"
eval VS_COMNTOOLS="\$${VS_COMNTOOLS_VAR}"
@@ -184,6 +194,7 @@ AC_DEFUN([TOOLCHAIN_FIND_VISUAL_STUDIO_BAT_FILE],
eval VS_EDITIONS="\${VS_EDITIONS_${VS_VERSION}}"
eval SDK_INSTALL_DIR="\${VS_SDK_INSTALLDIR_${VS_VERSION}}"
eval VS_ENV_ARGS="\${VS_ENV_ARGS_${VS_VERSION}}"
+ eval VS_TOOLSET_SUPPORTED="\${VS_TOOLSET_SUPPORTED_${VS_VERSION}}"
# When using --with-tools-dir, assume it points to the correct and default
# version of Visual Studio or that --with-toolchain-version was also set.
@@ -240,6 +251,12 @@ AC_DEFUN([TOOLCHAIN_FIND_VISUAL_STUDIO_BAT_FILE],
TOOLCHAIN_CHECK_POSSIBLE_WIN_SDK_ROOT([${VS_VERSION}],
[C:/Program Files (x86)/$SDK_INSTALL_DIR], [well-known name])
fi
+
+ if test "x$VS_TOOLSET_SUPPORTED" != x; then
+ if test "x$with_msvc_toolset_version" != x; then
+ VS_ENV_ARGS="$VS_ENV_ARGS -vcvars_ver=$with_msvc_toolset_version"
+ fi
+ fi
])
################################################################################
@@ -423,6 +440,8 @@ AC_DEFUN([TOOLCHAIN_SETUP_VISUAL_STUDIO_ENV],
>> $EXTRACT_VC_ENV_BAT_FILE
$ECHO 'echo VCINSTALLDIR="%VCINSTALLDIR% " >> set-vs-env.sh' \
>> $EXTRACT_VC_ENV_BAT_FILE
+ $ECHO 'echo VCToolsRedistDir="%VCToolsRedistDir% " >> set-vs-env.sh' \
+ >> $EXTRACT_VC_ENV_BAT_FILE
$ECHO 'echo WindowsSdkDir="%WindowsSdkDir% " >> set-vs-env.sh' \
>> $EXTRACT_VC_ENV_BAT_FILE
$ECHO 'echo WINDOWSSDKDIR="%WINDOWSSDKDIR% " >> set-vs-env.sh' \
@@ -440,6 +459,8 @@ AC_DEFUN([TOOLCHAIN_SETUP_VISUAL_STUDIO_ENV],
>> $EXTRACT_VC_ENV_BAT_FILE
$ECHO "$WINPATH_BASH -c 'echo VCINSTALLDIR="'\"$VCINSTALLDIR \" >> set-vs-env.sh' \
>> $EXTRACT_VC_ENV_BAT_FILE
+ $ECHO "$WINPATH_BASH -c 'echo VCToolsRedistDir="'\"$VCToolsRedistDir \" >> set-vs-env.sh' \
+ >> $EXTRACT_VC_ENV_BAT_FILE
$ECHO "$WINPATH_BASH -c 'echo WindowsSdkDir="'\"$WindowsSdkDir \" >> set-vs-env.sh' \
>> $EXTRACT_VC_ENV_BAT_FILE
$ECHO "$WINPATH_BASH -c 'echo WINDOWSSDKDIR="'\"$WINDOWSSDKDIR \" >> set-vs-env.sh' \
@@ -517,6 +538,7 @@ AC_DEFUN([TOOLCHAIN_SETUP_VISUAL_STUDIO_ENV],
VS_INCLUDE=`$ECHO "$VS_INCLUDE" | $SED -e 's/\\\\*;* *$//'`
VS_LIB=`$ECHO "$VS_LIB" | $SED 's/\\\\*;* *$//'`
VCINSTALLDIR=`$ECHO "$VCINSTALLDIR" | $SED 's/\\\\* *$//'`
+ VCToolsRedistDir=`$ECHO "$VCToolsRedistDir" | $SED 's/\\\\* *$//'`
WindowsSdkDir=`$ECHO "$WindowsSdkDir" | $SED 's/\\\\* *$//'`
WINDOWSSDKDIR=`$ECHO "$WINDOWSSDKDIR" | $SED 's/\\\\* *$//'`
if test -z "$WINDOWSSDKDIR"; then
@@ -638,11 +660,13 @@ AC_DEFUN([TOOLCHAIN_SETUP_MSVC_DLL],
POSSIBLE_MSVC_DLL="$CYGWIN_VC_INSTALL_DIR/redist/x86/Microsoft.VC${VS_VERSION_INTERNAL}.CRT/$DLL_NAME"
fi
else
+ CYGWIN_VC_TOOLS_REDIST_DIR="$VCToolsRedistDir"
+ BASIC_FIXUP_PATH(CYGWIN_VC_TOOLS_REDIST_DIR)
# Probe: Using well-known location from VS 2017
if test "x$OPENJDK_TARGET_CPU_BITS" = x64; then
- POSSIBLE_MSVC_DLL="`ls $CYGWIN_VC_INSTALL_DIR/Redist/MSVC/*/x64/Microsoft.VC${VS_VERSION_INTERNAL}.CRT/$DLL_NAME`"
+ POSSIBLE_MSVC_DLL="`ls $CYGWIN_VC_TOOLS_REDIST_DIR/x64/Microsoft.VC${VS_VERSION_INTERNAL}.CRT/$DLL_NAME`"
else
- POSSIBLE_MSVC_DLL="`ls $CYGWIN_VC_INSTALL_DIR/Redist/MSVC/*/x86/Microsoft.VC${VS_VERSION_INTERNAL}.CRT/$DLL_NAME`"
+ POSSIBLE_MSVC_DLL="`ls $CYGWIN_VC_TOOLS_REDIST_DIR/x86/Microsoft.VC${VS_VERSION_INTERNAL}.CRT/$DLL_NAME`"
fi
fi
# In case any of the above finds more than one file, loop over them.
diff --git a/make/autoconf/version-numbers b/make/autoconf/version-numbers
index 762c5528635..8e875a97d4b 100644
--- a/make/autoconf/version-numbers
+++ b/make/autoconf/version-numbers
@@ -35,7 +35,8 @@ DEFAULT_VERSION_EXTRA3=0
DEFAULT_VERSION_DATE=2019-09-17
DEFAULT_VERSION_CLASSFILE_MAJOR=57 # "`$EXPR $DEFAULT_VERSION_FEATURE + 44`"
DEFAULT_VERSION_CLASSFILE_MINOR=0
-DEFAULT_ACCEPTABLE_BOOT_VERSIONS="11 12 13"
+DEFAULT_ACCEPTABLE_BOOT_VERSIONS="12 13"
+DEFAULT_JDK_SOURCE_TARGET_VERSION=13
LAUNCHER_NAME=openjdk
PRODUCT_NAME=OpenJDK
diff --git a/make/common/FindTests.gmk b/make/common/FindTests.gmk
index 1c7eeb6b18b..acfdfb22d14 100644
--- a/make/common/FindTests.gmk
+++ b/make/common/FindTests.gmk
@@ -53,6 +53,7 @@ define FindJtregGroupsBody
-e 's/^groups\w*=//p' $1/TEST.ROOT)
$1_JTREG_GROUP_FILES := $$(addprefix $1/, $$($1_JTREG_GROUP_FILENAMES))
$1_JTREG_TEST_GROUPS := $$(strip $$(shell $$(SED) -n \
+ -e 's/^\#.*//g' \
-e 's/\([^ ]*\)\w*=.*/\1/gp' $$(wildcard $$($1_JTREG_GROUP_FILES)) \
| $$(SORT) -u))
endif
diff --git a/make/common/RMICompilation.gmk b/make/common/RMICompilation.gmk
index 6668f680ab2..1020af88b99 100644
--- a/make/common/RMICompilation.gmk
+++ b/make/common/RMICompilation.gmk
@@ -35,6 +35,7 @@
# RUN_V11:=Set to run rmic with -v1.1
# RUN_V12:=Set to run rmic with -v1.2
# KEEP_GENERATED:=Set to keep generated sources around
+# STUB_SOURCES_DIR:=Directory to put generated sources in
SetupRMICompilation = $(NamedParamsMacroTemplate)
define SetupRMICompilationBody
@@ -58,9 +59,16 @@ define SetupRMICompilationBody
$1_TIE_FILES := $$(addprefix $$($1_STUB_CLASSES_DIR)/org/omg/stub/,$$(addsuffix _Tie.class,$$($1_TIE_BASE_FILES)))
$1_TIE_STDPKG_FILES := $$(addprefix $$($1_STUB_CLASSES_DIR)/,$$(addsuffix _Tie.class,$$($1_TIE_BASE_FILES)))
- ifneq (,$$($1_KEEP_GENERATED))
+ ifneq ($$($1_KEEP_GENERATED), )
$1_ARGS += -keepgenerated
- $1_TARGETS += $$(subst .class,.java,$$($1_TARGETS))
+ $1_JAVA_TARGETS := $$(subst .class,.java,$$($1_TARGETS))
+ ifneq ($$($1_STUB_SOURCES_DIR), )
+ # This is where the java files are created by rmic
+ $1_JAVA_TARGETS_REL := $$(subst $$($1_STUB_CLASSES_DIR),, $$($1_JAVA_TARGETS))
+ # This is where the caller wants the java files
+ $1_JAVA_TARGETS := $$(addprefix $$($1_STUB_SOURCES_DIR), $$($1_JAVA_TARGETS_REL))
+ endif
+ $1_TARGETS += $$($1_JAVA_TARGETS)
endif
$1_DOLLAR_SAFE_CLASSES := $$(subst $$$$,\$$$$,$$($1_CLASSES))
@@ -72,11 +80,12 @@ define SetupRMICompilationBody
$$(call MakeDir, $$($1_STUB_CLASSES_DIR))
$(RMIC) $$($1_ARGS) -classpath "$$($1_CLASSES_DIR)" \
-d $$($1_STUB_CLASSES_DIR) $$($1_DOLLAR_SAFE_CLASSES); \
- if [ "x$$($1_ARGS2)" != "x" ]; then \
- $(ECHO) $(LOG_INFO) Running rmic $$($1_ARGS2) for $$($1_DOLLAR_SAFE_CLASSES) && \
- $(RMIC) $$($1_ARGS2) -classpath "$$($1_CLASSES_DIR)" \
- -d $$($1_STUB_CLASSES_DIR) $$($1_DOLLAR_SAFE_CLASSES); \
- fi; \
+ $$(if $$($1_STUB_SOURCES_DIR), \
+ $$(foreach f, $$($1_JAVA_TARGETS_REL), \
+ $(MKDIR) -p $$(dir $$($1_STUB_SOURCES_DIR)/$$f) ; \
+ $(MV) $$($1_STUB_CLASSES_DIR)/$$f $$($1_STUB_SOURCES_DIR)/$$f ; \
+ ) \
+ ) \
$(TOUCH) $$@
diff --git a/make/common/SetupJavaCompilers.gmk b/make/common/SetupJavaCompilers.gmk
index 7c85408cfb3..63d8ee8af01 100644
--- a/make/common/SetupJavaCompilers.gmk
+++ b/make/common/SetupJavaCompilers.gmk
@@ -33,6 +33,9 @@ include JavaCompilation.gmk
DISABLE_WARNINGS ?= -Xlint:all,-deprecation,-removal,-unchecked,-rawtypes,-cast,-serial,-dep-ann,-static,-fallthrough,-try,-varargs,-empty,-finally
+JDK_SOURCE_TARGET_FLAGS := -source $(JDK_SOURCE_TARGET_VERSION) \
+ -target $(JDK_SOURCE_TARGET_VERSION)
+
# If warnings needs to be non-fatal for testing purposes use a command like:
# make JAVAC_WARNINGS="-Xlint:all -Xmaxwarns 10000"
JAVAC_WARNINGS ?= -Xlint:all -Werror
@@ -72,7 +75,7 @@ $(eval $(call SetupJavaCompiler,GENERATE_OLDBYTECODE, \
$(eval $(call SetupJavaCompiler,GENERATE_JDKBYTECODE, \
JVM := $(JAVA_JAVAC), \
JAVAC := $(NEW_JAVAC), \
- FLAGS := -source 13 -target 13 --doclint-format html5 \
+ FLAGS := $(JDK_SOURCE_TARGET_FLAGS) --doclint-format html5 \
-encoding ascii -XDignore.symbol.file=true $(JAVAC_WARNINGS), \
SERVER_DIR := $(SJAVAC_SERVER_DIR), \
SERVER_JVM := $(SJAVAC_SERVER_JAVA)))
@@ -82,7 +85,7 @@ $(eval $(call SetupJavaCompiler,GENERATE_JDKBYTECODE, \
$(eval $(call SetupJavaCompiler,GENERATE_JDKBYTECODE_NOWARNINGS, \
JVM := $(JAVA_JAVAC), \
JAVAC := $(NEW_JAVAC), \
- FLAGS := -source 13 -target 13 \
+ FLAGS := $(JDK_SOURCE_TARGET_FLAGS) \
-encoding ascii -XDignore.symbol.file=true $(DISABLE_WARNINGS), \
SERVER_DIR := $(SJAVAC_SERVER_DIR), \
SERVER_JVM := $(SJAVAC_SERVER_JAVA)))
diff --git a/make/conf/jib-profiles.js b/make/conf/jib-profiles.js
index 6be256045e1..7761de7275f 100644
--- a/make/conf/jib-profiles.js
+++ b/make/conf/jib-profiles.js
@@ -365,7 +365,8 @@ var getJibProfilesCommon = function (input, data) {
};
};
- common.boot_jdk_version = "11";
+ common.boot_jdk_version = "12";
+ common.boot_jdk_build_number = "33";
common.boot_jdk_home = input.get("boot_jdk", "install_path") + "/jdk-"
+ common.boot_jdk_version
+ (input.build_os == "macosx" ? ".jdk/Contents/Home" : "");
@@ -754,7 +755,11 @@ var getJibProfilesProfiles = function (input, common, data) {
profiles[cmpBaselineName] = clone(profiles[name + suffix]);
// Only compare the images target. This should pressumably be expanded
// to include more build targets when possible.
- profiles[cmpBaselineName].default_make_targets = [ "images" ];
+ profiles[cmpBaselineName].default_make_targets = [ "images", "test-image" ];
+ if (name == "linux-x64") {
+ profiles[cmpBaselineName].default_make_targets
+ = concat(profiles[cmpBaselineName].default_make_targets, "docs");
+ }
profiles[cmpBaselineName].make_args = [ "COMPARE_BUILD=CONF=" ];
// Do not inherit artifact definitions from base profile
delete profiles[cmpBaselineName].artifacts;
@@ -980,7 +985,7 @@ var getJibProfilesDependencies = function (input, common) {
server: "jpg",
product: "jdk",
version: common.boot_jdk_version,
- build_number: "28",
+ build_number: common.boot_jdk_build_number,
file: "bundles/" + boot_jdk_platform + "/jdk-" + common.boot_jdk_version + "_"
+ boot_jdk_platform + "_bin" + boot_jdk_ext,
configure_args: "--with-boot-jdk=" + common.boot_jdk_home,
diff --git a/make/data/cldr/common/main/ja.xml b/make/data/cldr/common/main/ja.xml
index b0979680807..f9fc872e421 100644
--- a/make/data/cldr/common/main/ja.xml
+++ b/make/data/cldr/common/main/ja.xml
@@ -3633,7 +3633,7 @@ Warnings: All cp values have U+FE0F characters removed. See /annotationsDerived/
大正
昭和
平成
- 元号
+ 令和
大化
@@ -3872,7 +3872,7 @@ Warnings: All cp values have U+FE0F characters removed. See /annotationsDerived/
T
S
H
- N
+ R
diff --git a/make/data/cldr/common/main/root.xml b/make/data/cldr/common/main/root.xml
index dcc712acfe0..b9b41b6d64e 100644
--- a/make/data/cldr/common/main/root.xml
+++ b/make/data/cldr/common/main/root.xml
@@ -2030,7 +2030,7 @@ Warnings: All cp values have U+FE0F characters removed. See /annotationsDerived/
Taishō
Shōwa
Heisei
- NewEra
+ Reiwa
Taika (645–650)
@@ -2269,7 +2269,7 @@ Warnings: All cp values have U+FE0F characters removed. See /annotationsDerived/
T
S
H
- N
+ R
diff --git a/make/data/publicsuffixlist/VERSION b/make/data/publicsuffixlist/VERSION
index 44a3e1d5757..ada46687846 100644
--- a/make/data/publicsuffixlist/VERSION
+++ b/make/data/publicsuffixlist/VERSION
@@ -1,2 +1,2 @@
-Github: https://raw.githubusercontent.com/publicsuffix/list/2225db8d9f4a2a27ec697c883360632fa0c16261/public_suffix_list.dat
-Date: 2018-05-24
+Github: https://raw.githubusercontent.com/publicsuffix/list/ce0d1a5fba657e55adea3abde4b7f1e50636ff10/public_suffix_list.dat
+Date: 2019-01-28
diff --git a/make/data/publicsuffixlist/public_suffix_list.dat b/make/data/publicsuffixlist/public_suffix_list.dat
index 82e0f93ef3d..fbe8c246f0d 100644
--- a/make/data/publicsuffixlist/public_suffix_list.dat
+++ b/make/data/publicsuffixlist/public_suffix_list.dat
@@ -381,8 +381,13 @@ gov.bm
net.bm
org.bm
-// bn : https://en.wikipedia.org/wiki/.bn
-*.bn
+// bn : http://www.bnnic.bn/faqs
+bn
+com.bn
+edu.bn
+gov.bn
+net.bn
+org.bn
// bo : https://nic.bo/delegacion2015.php#h-1.10
bo
@@ -546,6 +551,7 @@ niteroi.br
not.br
ntr.br
odo.br
+ong.br
org.br
osasco.br
palmas.br
@@ -1239,7 +1245,7 @@ tozsde.hu
utazas.hu
video.hu
-// id : https://register.pandi.or.id/
+// id : https://pandi.id/en/domain/registration-requirements/
id
ac.id
biz.id
@@ -1250,6 +1256,7 @@ mil.id
my.id
net.id
or.id
+ponpes.id
sch.id
web.id
@@ -1407,9 +1414,9 @@ taa.it
tos.it
toscana.it
trentin-sud-tirol.it
-trentin-süd-tirol.it
+trentin-süd-tirol.it
trentin-sudtirol.it
-trentin-südtirol.it
+trentin-südtirol.it
trentin-sued-tirol.it
trentin-suedtirol.it
trentino-a-adige.it
@@ -1419,9 +1426,9 @@ trentino-altoadige.it
trentino-s-tirol.it
trentino-stirol.it
trentino-sud-tirol.it
-trentino-süd-tirol.it
+trentino-süd-tirol.it
trentino-sudtirol.it
-trentino-südtirol.it
+trentino-südtirol.it
trentino-sued-tirol.it
trentino-suedtirol.it
trentino.it
@@ -1432,15 +1439,15 @@ trentinoaltoadige.it
trentinos-tirol.it
trentinostirol.it
trentinosud-tirol.it
-trentinosüd-tirol.it
+trentinosüd-tirol.it
trentinosudtirol.it
-trentinosüdtirol.it
+trentinosüdtirol.it
trentinosued-tirol.it
trentinosuedtirol.it
trentinsud-tirol.it
-trentinsüd-tirol.it
+trentinsüd-tirol.it
trentinsudtirol.it
-trentinsüdtirol.it
+trentinsüdtirol.it
trentinsued-tirol.it
trentinsuedtirol.it
tuscany.it
@@ -1457,13 +1464,13 @@ valleaosta.it
valled-aosta.it
valledaosta.it
vallee-aoste.it
-vallée-aoste.it
+vallée-aoste.it
vallee-d-aoste.it
-vallée-d-aoste.it
+vallée-d-aoste.it
valleeaoste.it
-valléeaoste.it
+valléeaoste.it
valleedaoste.it
-valléedaoste.it
+valléedaoste.it
vao.it
vda.it
ven.it
@@ -1497,7 +1504,7 @@ av.it
avellino.it
ba.it
balsan-sudtirol.it
-balsan-südtirol.it
+balsan-südtirol.it
balsan-suedtirol.it
balsan.it
bari.it
@@ -1516,7 +1523,7 @@ bologna.it
bolzano-altoadige.it
bolzano.it
bozen-sudtirol.it
-bozen-südtirol.it
+bozen-südtirol.it
bozen-suedtirol.it
bozen.it
br.it
@@ -1525,7 +1532,7 @@ brindisi.it
bs.it
bt.it
bulsan-sudtirol.it
-bulsan-südtirol.it
+bulsan-südtirol.it
bulsan-suedtirol.it
bulsan.it
bz.it
@@ -1545,9 +1552,9 @@ catanzaro.it
cb.it
ce.it
cesena-forli.it
-cesena-forlì.it
+cesena-forlì.it
cesenaforli.it
-cesenaforlì.it
+cesenaforlì.it
ch.it
chieti.it
ci.it
@@ -1578,9 +1585,9 @@ florence.it
fm.it
foggia.it
forli-cesena.it
-forlì-cesena.it
+forlì-cesena.it
forlicesena.it
-forlìcesena.it
+forlìcesena.it
fr.it
frosinone.it
ge.it
@@ -1711,7 +1718,7 @@ sp.it
sr.it
ss.it
suedtirol.it
-südtirol.it
+südtirol.it
sv.it
ta.it
taranto.it
@@ -3692,8 +3699,16 @@ jeonnam.kr
seoul.kr
ulsan.kr
-// kw : https://en.wikipedia.org/wiki/.kw
-*.kw
+// kw : https://www.nic.kw/policies/
+// Confirmed by registry
+kw
+com.kw
+edu.kw
+emb.kw
+gov.kw
+ind.kw
+net.kw
+org.kw
// ky : http://www.icta.ky/da_ky_reg_dom.php
// Confirmed by registry 2008-06-17
@@ -3775,10 +3790,18 @@ gov.lr
org.lr
net.lr
-// ls : https://en.wikipedia.org/wiki/.ls
+// ls : http://www.nic.ls/
+// Confirmed by registry
ls
+ac.ls
+biz.ls
co.ls
+edu.ls
+gov.ls
+info.ls
+net.ls
org.ls
+sc.ls
// lt : https://en.wikipedia.org/wiki/.lt
lt
@@ -4636,9 +4659,6 @@ web.ni
// ccTLD for the Netherlands
nl
-// BV.nl will be a registry for dutch BV's (besloten vennootschap)
-bv.nl
-
// no : http://www.norid.no/regelverk/index.en.html
// The Norwegian registry has declined to notify us of updates. The web pages
// referenced below are the official source of the data. There is also an
@@ -8329,9 +8349,6 @@ golf
// goo : 2014-12-18 NTT Resonant Inc.
goo
-// goodhands : 2015-07-31 Allstate Fire and Casualty Insurance Company
-goodhands
-
// goodyear : 2015-07-02 The Goodyear Tire & Rubber Company
goodyear
@@ -8608,9 +8625,6 @@ itv
// iveco : 2015-09-03 CNH Industrial N.V.
iveco
-// iwc : 2014-06-23 Richemont DNS Inc.
-iwc
-
// jaguar : 2014-11-13 Jaguar Land Rover Ltd
jaguar
@@ -8635,9 +8649,6 @@ jewelry
// jio : 2015-04-02 Reliance Industries Limited
jio
-// jlc : 2014-12-04 Richemont DNS Inc.
-jlc
-
// jll : 2015-04-02 Jones Lang LaSalle Incorporated
jll
@@ -8989,9 +9000,6 @@ men
// menu : 2013-09-11 Wedding TLD2, LLC
menu
-// meo : 2014-11-07 MEO Servicos de Comunicacoes e Multimedia, S.A.
-meo
-
// merckmsd : 2016-07-14 MSD Registry Holdings, Inc.
merckmsd
@@ -9283,9 +9291,6 @@ page
// panasonic : 2015-07-30 Panasonic Corporation
panasonic
-// panerai : 2014-11-07 Richemont DNS Inc.
-panerai
-
// paris : 2014-01-30 City of Paris
paris
@@ -9634,9 +9639,6 @@ sanofi
// sap : 2014-03-27 SAP AG
sap
-// sapo : 2014-11-07 MEO Servicos de Comunicacoes e Multimedia, S.A.
-sapo
-
// sarl : 2014-07-03 Binky Moon, LLC
sarl
@@ -9877,9 +9879,6 @@ statebank
// statefarm : 2015-07-30 State Farm Mutual Automobile Insurance Company
statefarm
-// statoil : 2014-12-04 Statoil ASA
-statoil
-
// stc : 2014-10-09 Saudi Telecom Company
stc
@@ -9991,9 +9990,6 @@ tech
// technology : 2013-09-13 Binky Moon, LLC
technology
-// telecity : 2015-02-19 TelecityGroup International Limited
-telecity
-
// telefonica : 2014-10-16 Telefónica S.A.
telefonica
@@ -10201,9 +10197,6 @@ visa
// vision : 2013-12-05 Binky Moon, LLC
vision
-// vista : 2014-09-18 Vistaprint Limited
-vista
-
// vistaprint : 2014-09-18 Vistaprint Limited
vistaprint
@@ -10642,9 +10635,6 @@ vermögensberatung
// xn--zfr164b : 2013-11-08 China Organizational Name Administration Center
政务
-// xperia : 2015-05-14 Sony Mobile Communications AB
-xperia
-
// xyz : 2013-12-05 XYZ.COM LLC
xyz
@@ -10737,6 +10727,7 @@ us-east-1.amazonaws.com
// Amazon Elastic Beanstalk : https://aws.amazon.com/elasticbeanstalk/
// Submitted by Luke Wells
cn-north-1.eb.amazonaws.com.cn
+cn-northwest-1.eb.amazonaws.com.cn
elasticbeanstalk.com
ap-northeast-1.elasticbeanstalk.com
ap-northeast-2.elasticbeanstalk.com
@@ -10823,6 +10814,10 @@ s3-website.us-east-2.amazonaws.com
t3l3p0rt.net
tele.amune.org
+// Apigee : https://apigee.com/
+// Submitted by Apigee Security Team
+apigee.io
+
// Aptible : https://www.aptible.com/
// Submitted by Thomas Orozco
on-aptible.com
@@ -10842,6 +10837,11 @@ sweetpepper.org
// Submitted by Vincent Tseng
myasustor.com
+// Automattic Inc. : https://automattic.com/
+// Submitted by Alex Concha
+go-vip.co
+wpcomstaging.com
+
// AVM : https://avm.de
// Submitted by Andreas Weise
myfritz.net
@@ -10888,6 +10888,11 @@ square7.net
// Submitted by Dave Tharp
browsersafetymark.io
+// Bytemark Hosting : https://www.bytemark.co.uk
+// Submitted by Paul Cammish
+dh.bytemark.co.uk
+vm.bytemark.co.uk
+
// callidomus : https://www.callidomus.com/
// Submitted by Marcus Popp
mycd.eu
@@ -11080,6 +11085,11 @@ firm.dk
reg.dk
store.dk
+// dapps.earth : https://dapps.earth/
+// Submitted by Daniil Burdakov
+*.dapps.earth
+*.bzz.dapps.earth
+
// Debian : https://www.debian.org/
// Submitted by Peter Palfrader / Debian Sysadmin Team
debian.net
@@ -11092,6 +11102,11 @@ dedyn.io
// Submitted by Norbert Auler
dnshome.de
+// DotArai : https://www.dotarai.com/
+// Submitted by Atsadawat Netcharadsang
+online.th
+shop.th
+
// DrayTek Corp. : https://www.draytek.com/
// Submitted by Paul Fang
drayddns.com
@@ -11648,6 +11663,10 @@ cloud.fedoraproject.org
app.os.fedoraproject.org
app.os.stg.fedoraproject.org
+// Fermax : https://fermax.com/
+// submitted by Koen Van Isterdael
+mydobiss.com
+
// Filegear Inc. : https://www.filegear.com
// Submitted by Jason Zhu
filegear.me
@@ -11713,6 +11732,8 @@ goip.de
// Google, Inc.
// Submitted by Eduardo Vela
+run.app
+a.run.app
*.0emm.com
appspot.com
blogspot.ae
@@ -11918,6 +11939,12 @@ git-repos.de
lcube-server.de
svn-repos.de
+// Leadpages : https://www.leadpages.net
+// Submitted by Greg Dallavalle
+leadpages.co
+lpages.co
+lpusercontent.com
+
// Lightmaker Property Manager, Inc. : https://app.lmpm.com/
// Submitted by Greg Holland
app.lmpm.com
@@ -11935,6 +11962,15 @@ linkyard-cloud.ch
// Submitted by Victor Velchev
we.bs
+// LubMAN UMCS Sp. z o.o : https://lubman.pl/
+// Submitted by Ireneusz Maliszewski
+krasnik.pl
+leczna.pl
+lubartow.pl
+lublin.pl
+poniatowa.pl
+swidnik.pl
+
// Lug.org.uk : https://lug.org.uk
// Submitted by Jon Spriggs
uklugs.org
@@ -12322,6 +12358,10 @@ protonet.io
chirurgiens-dentistes-en-france.fr
byen.site
+// Redstar Consultants : https://www.redstarconsultants.com/
+// Submitted by Jons Slemmer
+instantcloud.cn
+
// Russian Academy of Sciences
// Submitted by Tech Support
ras.ru
@@ -12350,6 +12390,10 @@ vaporcloud.io
rackmaze.com
rackmaze.net
+// Read The Docs, Inc : https://www.readthedocs.org
+// Submitted by David Fischer
+readthedocs.io
+
// Red Hat, Inc. OpenShift : https://openshift.redhat.com/
// Submitted by Tim Kramer
rhcloud.com
@@ -12426,6 +12470,10 @@ applinzi.com
sinaapp.com
vipsinaapp.com
+// Siteleaf : https://www.siteleaf.com/
+// Submitted by Skylar Challand
+siteleaf.net
+
// Skyhat : http://www.skyhat.io
// Submitted by Shante Adam
bounty-full.com
@@ -12451,10 +12499,6 @@ spacekit.io
// Submitted by Stefan Neufeind
customer.speedpartner.de
-// Stackspace : https://www.stackspace.io/
-// Submitted by Lina He
-stackspace.space
-
// Storj Labs Inc. : https://storj.io/
// Submitted by Philip Hutchins
storj.farm
@@ -12495,6 +12539,12 @@ gdynia.pl
med.pl
sopot.pl
+// Telebit : https://telebit.cloud
+// Submitted by AJ ONeal
+telebit.app
+telebit.io
+*.telebit.xyz
+
// The Gwiddle Foundation : https://gwiddlefoundation.org.uk
// Submitted by Joshua Bayfield
gwiddle.co.uk
@@ -12533,7 +12583,7 @@ lima-city.rocks
webspace.rocks
lima.zone
-// TransIP : htts://www.transip.nl
+// TransIP : https://www.transip.nl
// Submitted by Rory Breuk
*.transurl.be
*.transurl.eu
diff --git a/make/data/unicodedata/UnicodeData.txt b/make/data/unicodedata/UnicodeData.txt
index 03cf481f342..72b902a3d7f 100644
--- a/make/data/unicodedata/UnicodeData.txt
+++ b/make/data/unicodedata/UnicodeData.txt
@@ -11836,7 +11836,7 @@
32FC;CIRCLED KATAKANA WI;So;0;L; 30F0;;;;N;;;;;
32FD;CIRCLED KATAKANA WE;So;0;L; 30F1;;;;N;;;;;
32FE;CIRCLED KATAKANA WO;So;0;L; 30F2;;;;N;;;;;
-32FF;SQUARE ERA NAME NEWERA;So;0;L; 5143 53F7;;;;N;SQUARED TWO IDEOGRAPHS ERA NAME NEWERA;;;;
+32FF;SQUARE ERA NAME REIWA;So;0;L; 4EE4 548C;;;;N;SQUARED TWO IDEOGRAPHS ERA NAME REIWA;;;;
3300;SQUARE APAATO;So;0;L; 30A2 30D1 30FC 30C8;;;;N;SQUARED APAATO;;;;
3301;SQUARE ARUHUA;So;0;L; 30A2 30EB 30D5 30A1;;;;N;SQUARED ARUHUA;;;;
3302;SQUARE ANPEA;So;0;L; 30A2 30F3 30DA 30A2;;;;N;SQUARED ANPEA;;;;
diff --git a/make/hotspot/lib/JvmFeatures.gmk b/make/hotspot/lib/JvmFeatures.gmk
index 5575234adff..7c855492e53 100644
--- a/make/hotspot/lib/JvmFeatures.gmk
+++ b/make/hotspot/lib/JvmFeatures.gmk
@@ -1,5 +1,5 @@
#
-# Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2013, 2019, Oracle and/or its affiliates. All rights reserved.
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
#
# This code is free software; you can redistribute it and/or modify it
@@ -47,6 +47,9 @@ endif
ifeq ($(call check-jvm-feature, zero), true)
JVM_CFLAGS_FEATURES += -DZERO -DCC_INTERP -DZERO_LIBARCH='"$(OPENJDK_TARGET_CPU_LEGACY_LIB)"' $(LIBFFI_CFLAGS)
JVM_LIBS_FEATURES += $(LIBFFI_LIBS)
+ ifeq ($(ENABLE_LIBFFI_BUNDLING), true)
+ JVM_LDFLAGS_FEATURES += $(call SET_EXECUTABLE_ORIGIN,/..)
+ endif
ifeq ($(call isTargetCpu, sparcv9), true)
BUILD_LIBJVM_EXTRA_FILES := $(TOPDIR)/src/hotspot/cpu/sparc/memset_with_concurrent_readers_sparc.cpp
endif
@@ -123,7 +126,7 @@ ifneq ($(call check-jvm-feature, nmt), true)
JVM_CFLAGS_FEATURES += -DINCLUDE_NMT=0
JVM_EXCLUDE_FILES += \
memBaseline.cpp memReporter.cpp mallocTracker.cpp virtualMemoryTracker.cpp nmtCommon.cpp \
- memTracker.cpp nmtDCmd.cpp mallocSiteTable.cpp
+ memTracker.cpp nmtDCmd.cpp mallocSiteTable.cpp threadStackTracker.cpp
endif
ifneq ($(call check-jvm-feature, aot), true)
diff --git a/make/rmic/Rmic-java.management.rmi.gmk b/make/rmic/Rmic-java.management.rmi.gmk
index e734224dd57..642bea69f2a 100644
--- a/make/rmic/Rmic-java.management.rmi.gmk
+++ b/make/rmic/Rmic-java.management.rmi.gmk
@@ -40,23 +40,14 @@ JMX_RMI_CLASSES := javax.management.remote.rmi.RMIConnectionImpl \
$(eval $(call SetupRMICompilation,RMI_GEN, \
CLASSES := $(JMX_RMI_CLASSES), \
CLASSES_DIR := $(CLASSES_DIR)/java.management.rmi, \
- STUB_CLASSES_DIR := $(RMIC_GENSRC_DIR)/java.management.rmi, \
+ STUB_CLASSES_DIR := $(STUB_CLASSES_DIR)/java.management.rmi, \
RUN_V12 := true, \
KEEP_GENERATED := true, \
+ STUB_SOURCES_DIR := $(RMIC_GENSRC_DIR)/java.management.rmi, \
))
-# Find all classes generated and move them from the gensrc dir to the stub classes dir
-$(RMIC_GENSRC_DIR)/_classes.moved: $(RMI_GEN)
- $(eval classfiles := $(shell $(FIND) $(RMIC_GENSRC_DIR) -name "*.class"))
- $(foreach src, $(classfiles), \
- $(eval target := $(patsubst $(RMIC_GENSRC_DIR)/%, \
- $(STUB_CLASSES_DIR)/%, $(src))) \
- $(call MakeDir, $(dir $(target))) \
- $(MV) $(src) $(target) $(NEWLINE))
- $(TOUCH) $@
-
##########################################################################################
-all: $(RMIC_GENSRC_DIR)/_classes.moved $(RMI_GEN)
+all: $(RMI_GEN)
.PHONY: all
diff --git a/make/scripts/compare.sh b/make/scripts/compare.sh
index 86f036f5fd4..42394f84f7c 100644
--- a/make/scripts/compare.sh
+++ b/make/scripts/compare.sh
@@ -202,15 +202,20 @@ diff_text() {
$SED -e '/[<>].*[0-9]\{4\}-[0-9]\{2\}-[0-9]\{2\}-[0-9]\{6\}.*/d')
fi
if test "x$SUFFIX" = "xhtml"; then
- # Some javadoc versions do not put quotes around font size
- HTML_FILTER="$SED \
+ # Some javadoc versions do not put quotes around font size
+ HTML_FILTER="$SED \
-e 's///g'"
- $CAT $THIS_FILE | eval "$HTML_FILTER" > $THIS_FILE.filtered
- $CAT $OTHER_FILE | eval "$HTML_FILTER" > $OTHER_FILE.filtered
+ $CAT $THIS_FILE | eval "$HTML_FILTER" > $THIS_FILE.filtered
+ $CAT $OTHER_FILE | eval "$HTML_FILTER" > $OTHER_FILE.filtered
TMP=$(LC_ALL=C $DIFF $OTHER_FILE.filtered $THIS_FILE.filtered | \
$GREP '^[<>]' | \
$SED -e '/[<>] /d' \
- -e '/[<>] /d' )
+ -e '/[<>] /d' )
+ fi
+ if test "$NAME" = "BenchmarkList"; then
+ $SORT $THIS_FILE > $THIS_FILE.sorted
+ $SORT $OTHER_FILE > $OTHER_FILE.sorted
+ TMP=$($DIFF $THIS_FILE.sorted $OTHER_FILE.sorted)
fi
if test -n "$TMP"; then
echo Files $OTHER_FILE and $THIS_FILE differ
@@ -382,17 +387,19 @@ compare_general_files() {
! -name "*.zip" ! -name "*.debuginfo" ! -name "*.dylib" ! -name "jexec" \
! -name "modules" ! -name "ct.sym" ! -name "*.diz" ! -name "*.dll" \
! -name "*.cpl" ! -name "*.pdb" ! -name "*.exp" ! -name "*.ilk" \
- ! -name "*.lib" ! -name "*.war" ! -name "JavaControlPanel" ! -name "*.jmod" \
- ! -name "*.obj" ! -name "*.o" ! -name "JavaControlPanelHelper" \
- ! -name "JavaUpdater" ! -name "JavaWSApplicationStub" \
- ! -name "jspawnhelper" ! -name "JavawsLauncher" ! -name "*.a" \
- ! -name "finish_installation" ! -name "Sparkle" ! -name "*.tar.gz" \
- ! -name "classes.jsa" \
+ ! -name "*.lib" ! -name "*.war" ! -name "*.jmod" ! -name "*.exe" \
+ ! -name "*.obj" ! -name "*.o" ! -name "jspawnhelper" ! -name "*.a" \
+ ! -name "*.tar.gz" ! -name "classes.jsa" ! -name "gtestLauncher" \
+ ! -name "*.map" \
| $GREP -v "./bin/" | $SORT | $FILTER)
echo Other files with binary differences...
for f in $GENERAL_FILES
do
+ # Skip all files in test/*/native
+ if [[ "$f" == */native/* ]]; then
+ continue
+ fi
if [ -e $OTHER_DIR/$f ]; then
SUFFIX="${f##*.}"
if [ "$(basename $f)" = "release" ]; then
@@ -431,7 +438,7 @@ compare_general_files() {
$CAT $OTHER_DIR/$f | eval "$HTML_FILTER" > $OTHER_FILE &
$CAT $THIS_DIR/$f | eval "$HTML_FILTER" > $THIS_FILE &
wait
- elif [[ "$f" = *"/lib/classlist" ]]; then
+ elif [[ "$f" = *"/lib/classlist" ]] || [ "$SUFFIX" = "jar_contents" ]; then
# The classlist files may have some lines in random order
OTHER_FILE=$WORK_DIR/$f.other
THIS_FILE=$WORK_DIR/$f.this
@@ -792,14 +799,14 @@ compare_bin_file() {
export _NT_SYMBOL_PATH="$(echo $PDB_DIRS | tr ' ' ';')"
fi
- if [ -z "$SKIP_BIN_DIFF" ]; then
- if cmp $OTHER_FILE $THIS_FILE > /dev/null; then
+ if cmp $OTHER_FILE $THIS_FILE > /dev/null; then
# The files were bytewise identical.
- if [ -n "$VERBOSE" ]; then
- echo " : : : : : : $BIN_FILE"
- fi
- return 0
+ if [ -n "$VERBOSE" ]; then
+ echo " : : : : : : $BIN_FILE"
fi
+ return 0
+ fi
+ if [ -z "$SKIP_BIN_DIFF" ]; then
BIN_MSG=" diff "
if [[ "$ACCEPTED_BIN_DIFF" != *"$BIN_FILE"* ]]; then
DIFF_BIN=true
@@ -826,7 +833,8 @@ compare_bin_file() {
DIFF_SIZE_NUM=$($EXPR $THIS_SIZE - $OTHER_SIZE)
DIFF_SIZE_REL=$($EXPR $THIS_SIZE \* 100 / $OTHER_SIZE)
SIZE_MSG=$($PRINTF "%3d%% %4d" $DIFF_SIZE_REL $DIFF_SIZE_NUM)
- if [[ "$ACCEPTED_SMALL_SIZE_DIFF" = *"$BIN_FILE"* ]] && [ "$DIFF_SIZE_REL" -gt 98 ] \
+ if [[ "$ACCEPTED_SMALL_SIZE_DIFF" = *"$BIN_FILE"* || "$ACCEPTED_SMALL_SIZE_DIFF" = "true" ]] \
+ && [ "$DIFF_SIZE_REL" -gt 98 ] \
&& [ "$DIFF_SIZE_REL" -lt 102 ]; then
SIZE_MSG="($SIZE_MSG)"
DIFF_SIZE=
@@ -1440,13 +1448,8 @@ if [ "$SKIP_DEFAULT" != "true" ]; then
echo
fi
-
# Find the common images to compare, prioritizing later build stages
- if [ -d "$THIS/install/jdk" ] && [ -d "$OTHER/install/jdk" ]; then
- THIS_JDK="$THIS/install/jdk"
- OTHER_JDK="$OTHER/install/jdk"
- echo "Selecting install images for JDK compare"
- elif [ -d "$THIS/images/jdk" ] && [ -d "$OTHER/images/jdk" ]; then
+ if [ -d "$THIS/images/jdk" ] && [ -d "$OTHER/images/jdk" ]; then
THIS_JDK="$THIS/images/jdk"
OTHER_JDK="$OTHER/images/jdk"
echo "Selecting normal images for JDK compare"
@@ -1475,63 +1478,22 @@ if [ "$SKIP_DEFAULT" != "true" ]; then
echo " $OTHER_JDK"
if [ -d "$THIS/images/jdk-bundle" -o -d "$THIS/deploy/images/jdk-bundle" ] \
- && [ -d "$OTHER/images/jdk-bundle" -o -d "$OTHER/deploy/images/jdk-bundle" ]; then
- if [ -d "$THIS/deploy/images/jdk-bundle" ]; then
+ && [ -d "$OTHER/images/jdk-bundle" -o -d "$OTHER/deploy/images/jdk-bundle" ]; then
+ if [ -d "$THIS/deploy/images/jdk-bundle" ]; then
THIS_JDK_BUNDLE="$THIS/deploy/images/jdk-bundle"
- else
+ else
THIS_JDK_BUNDLE="$THIS/images/jdk-bundle"
- fi
- if [ -d "$OTHER/deploy/images/jdk-bundle" ]; then
+ fi
+ if [ -d "$OTHER/deploy/images/jdk-bundle" ]; then
OTHER_JDK_BUNDLE="$OTHER/deploy/images/jdk-bundle"
- else
+ else
OTHER_JDK_BUNDLE="$OTHER/images/jdk-bundle"
- fi
+ fi
echo "Also comparing jdk macosx bundles"
echo " $THIS_JDK_BUNDLE"
echo " $OTHER_JDK_BUNDLE"
fi
- if [ -d "$THIS/deploy/bundles" -o -d "$THIS/deploy/images/bundles" ] \
- && [ -d "$OTHER/deploy/bundles" -o -d "$OTHER/deploy/images/bundles" ]; then
- if [ -d "$THIS/deploy/images/bundles" ]; then
- THIS_DEPLOY_BUNDLE_DIR="$THIS/deploy/images/bundles"
- else
- THIS_DEPLOY_BUNDLE_DIR="$THIS/deploy/bundles"
- fi
- if [ -d "$OTHER/deploy/images/bundles" ]; then
- OTHER_DEPLOY_BUNDLE_DIR="$OTHER/deploy/images/bundles"
- else
- OTHER_DEPLOY_BUNDLE_DIR="$OTHER/deploy/bundles"
- fi
- echo "Also comparing deploy javadoc bundles"
- fi
-
- if [ -d "$THIS/images/JavaAppletPlugin.plugin" ] \
- && [ -d "$OTHER/images/JavaAppletPlugin.plugin" -o -d "$OTHER/deploy/images/JavaAppletPlugin.plugin" ]; then
- if [ -d "$THIS/images/JavaAppletPlugin.plugin" ]; then
- THIS_DEPLOY_APPLET_PLUGIN_DIR="$THIS/images/JavaAppletPlugin.plugin"
- else
- THIS_DEPLOY_APPLET_PLUGIN_DIR="$THIS/deploy/images/JavaAppletPlugin.plugin"
- fi
- if [ -d "$OTHER/images/JavaAppletPlugin.plugin" ]; then
- OTHER_DEPLOY_APPLET_PLUGIN_DIR="$OTHER/images/JavaAppletPlugin.plugin"
- else
- OTHER_DEPLOY_APPLET_PLUGIN_DIR="$OTHER/deploy/images/JavaAppletPlugin.plugin"
- fi
- echo "Also comparing deploy applet image"
- echo " $THIS_DEPLOY_APPLET_PLUGIN_DIR"
- echo " $OTHER_DEPLOY_APPLET_PLUGIN_DIR"
- fi
-
- if [ -d "$THIS/install/sparkle/Sparkle.framework" ] \
- && [ -d "$OTHER/install/sparkle/Sparkle.framework" ]; then
- THIS_SPARKLE_DIR="$THIS/install/sparkle/Sparkle.framework"
- OTHER_SPARKLE_DIR="$OTHER/install/sparkle/Sparkle.framework"
- echo "Also comparing install sparkle framework"
- echo " $THIS_SPARKLE_DIR"
- echo " $OTHER_SPARKLE_DIR"
- fi
-
THIS_SEC_DIR="$THIS/images"
OTHER_SEC_DIR="$OTHER/images"
if [ -f "$THIS_SEC_DIR/sec-bin.zip" ] && [ -f "$OTHER_SEC_DIR/sec-bin.zip" ]; then
@@ -1557,6 +1519,14 @@ if [ "$SKIP_DEFAULT" != "true" ]; then
else
echo "WARNING! Docs haven't been built and won't be compared."
fi
+
+ if [ -d "$THIS/images/test" ] && [ -d "$OTHER/images/test" ]; then
+ THIS_TEST="$THIS/images/test"
+ OTHER_TEST="$OTHER/images/test"
+ echo "Also comparing test image"
+ else
+ echo "WARNING! Test haven't been built and won't be compared."
+ fi
fi
################################################################################
@@ -1582,22 +1552,16 @@ if [ "$CMP_NAMES" = "true" ]; then
echo -n "Docs "
compare_files $THIS_DOCS $OTHER_DOCS $COMPARE_ROOT/docs
fi
+ if [ -n "$THIS_TEST" ] && [ -n "$OTHER_TEST" ]; then
+ echo -n "Test "
+ compare_dirs $THIS_TEST $OTHER_TEST $COMPARE_ROOT/test
+ echo -n "Test "
+ compare_files $THIS_TEST $OTHER_TEST $COMPARE_ROOT/test
+ fi
if [ -n "$THIS_BASE_DIR" ] && [ -n "$OTHER_BASE_DIR" ]; then
compare_dirs $THIS_BASE_DIR $OTHER_BASE_DIR $COMPARE_ROOT/base_dir
compare_files $THIS_BASE_DIR $OTHER_BASE_DIR $COMPARE_ROOT/base_dir
fi
- if [ -n "$THIS_DEPLOY_APPLET_PLUGIN_DIR" ] && [ -n "$OTHER_DEPLOY_APPLET_PLUGIN_DIR" ]; then
- echo -n "JavaAppletPlugin "
- compare_dirs $THIS_DEPLOY_APPLET_PLUGIN_DIR $OTHER_DEPLOY_APPLET_PLUGIN_DIR $COMPARE_ROOT/plugin
- echo -n "JavaAppletPlugin "
- compare_files $THIS_DEPLOY_APPLET_PLUGIN_DIR $OTHER_DEPLOY_APPLET_PLUGIN_DIR $COMPARE_ROOT/plugin
- fi
- if [ -n "$THIS_SPARKLE_DIR" ] && [ -n "$OTHER_SPARKLE_DIR" ]; then
- echo -n "Sparkle.framework "
- compare_dirs $THIS_SPARKLE_DIR $OTHER_SPARKLE_DIR $COMPARE_ROOT/sparkle
- echo -n "Sparkle.framework "
- compare_files $THIS_SPARKLE_DIR $OTHER_SPARKLE_DIR $COMPARE_ROOT/sparkle
- fi
fi
if [ "$CMP_LIBS" = "true" ]; then
@@ -1605,34 +1569,38 @@ if [ "$CMP_LIBS" = "true" ]; then
echo -n "JDK "
compare_all_libs $THIS_JDK $OTHER_JDK $COMPARE_ROOT/jdk
fi
+ if [ -n "$THIS_TEST" ] && [ -n "$OTHER_TEST" ]; then
+ echo -n "Test "
+ # Test native libs are never stripped so will not compare well.
+ SKIP_BIN_DIFF="true"
+ ACCEPTED_SMALL_SIZE_DIFF_bak="$ACCEPTED_SMALL_SIZE_DIFF"
+ if [ "$OPENJDK_TARGET_OS" = "solaris" ]; then
+ ACCEPTED_SMALL_SIZE_DIFF="true"
+ fi
+ compare_all_libs $THIS_TEST $OTHER_TEST $COMPARE_ROOT/test
+ SKIP_BIN_DIFF="false"
+ ACCEPTED_SMALL_SIZE_DIFF="$ACCEPTED_SMALL_SIZE_DIFF_bak"
+ fi
if [ -n "$THIS_BASE_DIR" ] && [ -n "$OTHER_BASE_DIR" ]; then
compare_all_libs $THIS_BASE_DIR $OTHER_BASE_DIR $COMPARE_ROOT/base_dir
fi
- if [ -n "$THIS_DEPLOY_APPLET_PLUGIN_DIR" ] && [ -n "$OTHER_DEPLOY_APPLET_PLUGIN_DIR" ]; then
- echo -n "JavaAppletPlugin "
- compare_all_libs $THIS_DEPLOY_APPLET_PLUGIN_DIR $OTHER_DEPLOY_APPLET_PLUGIN_DIR $COMPARE_ROOT/plugin
- fi
- if [ -n "$THIS_SPARKLE_DIR" ] && [ -n "$OTHER_SPARKLE_DIR" ]; then
- echo -n "Sparkle.framework "
- compare_all_libs $THIS_SPARKLE_DIR $OTHER_SPARKLE_DIR $COMPARE_ROOT/sparkle
- fi
fi
if [ "$CMP_EXECS" = "true" ]; then
if [ -n "$THIS_JDK" ] && [ -n "$OTHER_JDK" ]; then
+ echo -n "JDK "
compare_all_execs $THIS_JDK $OTHER_JDK $COMPARE_ROOT/jdk
fi
+ if [ -n "$THIS_TEST" ] && [ -n "$OTHER_TEST" ]; then
+ echo -n "Test "
+ # Test native executables are never stripped so will not compare well.
+ SKIP_BIN_DIFF="true"
+ compare_all_execs $THIS_TEST $OTHER_TEST $COMPARE_ROOT/test
+ SKIP_BIN_DIFF="false"
+ fi
if [ -n "$THIS_BASE_DIR" ] && [ -n "$OTHER_BASE_DIR" ]; then
compare_all_execs $THIS_BASE_DIR $OTHER_BASE_DIR $COMPARE_ROOT/base_dir
fi
- if [ -n "$THIS_DEPLOY_APPLET_PLUGIN_DIR" ] && [ -n "$OTHER_DEPLOY_APPLET_PLUGIN_DIR" ]; then
- echo -n "JavaAppletPlugin "
- compare_all_execs $THIS_DEPLOY_APPLET_PLUGIN_DIR $OTHER_DEPLOY_APPLET_PLUGIN_DIR $COMPARE_ROOT/plugin
- fi
- if [ -n "$THIS_SPARKLE_DIR" ] && [ -n "$OTHER_SPARKLE_DIR" ]; then
- echo -n "Sparkle.framework "
- compare_all_execs $THIS_SPARKLE_DIR $OTHER_SPARKLE_DIR $COMPARE_ROOT/sparkle
- fi
fi
if [ "$CMP_GENERAL" = "true" ]; then
@@ -1648,23 +1616,24 @@ if [ "$CMP_GENERAL" = "true" ]; then
echo -n "Docs "
compare_general_files $THIS_DOCS $OTHER_DOCS $COMPARE_ROOT/docs
fi
+ if [ -n "$THIS_TEST" ] && [ -n "$OTHER_TEST" ]; then
+ echo -n "Test "
+ compare_general_files $THIS_TEST $OTHER_TEST $COMPARE_ROOT/test
+ fi
if [ -n "$THIS_BASE_DIR" ] && [ -n "$OTHER_BASE_DIR" ]; then
compare_general_files $THIS_BASE_DIR $OTHER_BASE_DIR $COMPARE_ROOT/base_dir
fi
- if [ -n "$THIS_DEPLOY_APPLET_PLUGIN_DIR" ] && [ -n "$OTHER_DEPLOY_APPLET_PLUGIN_DIR" ]; then
- echo -n "JavaAppletPlugin "
- compare_general_files $THIS_DEPLOY_APPLET_PLUGIN_DIR $OTHER_DEPLOY_APPLET_PLUGIN_DIR $COMPARE_ROOT/plugin
- fi
- if [ -n "$THIS_SPARKLE_DIR" ] && [ -n "$OTHER_SPARKLE_DIR" ]; then
- echo -n "Sparkle.framework "
- compare_general_files $THIS_SPARKLE_DIR $OTHER_SPARKLE_DIR $COMPARE_ROOT/sparkle
- fi
fi
if [ "$CMP_ZIPS" = "true" ]; then
if [ -n "$THIS_JDK" ] && [ -n "$OTHER_JDK" ]; then
+ echo -n "JDK "
compare_all_zip_files $THIS_JDK $OTHER_JDK $COMPARE_ROOT/jdk
fi
+ if [ -n "$THIS_TEST" ] && [ -n "$OTHER_TEST" ]; then
+ echo -n "Test "
+ compare_all_zip_files $THIS_TEST $OTHER_TEST $COMPARE_ROOT/test
+ fi
if [ -n "$THIS_SEC_BIN" ] && [ -n "$OTHER_SEC_BIN" ]; then
if [ -n "$(echo $THIS_SEC_BIN | $FILTER)" ]; then
echo "sec-bin.zip..."
@@ -1686,24 +1655,20 @@ if [ "$CMP_ZIPS" = "true" ]; then
if [ -n "$THIS_BASE_DIR" ] && [ -n "$OTHER_BASE_DIR" ]; then
compare_all_zip_files $THIS_BASE_DIR $OTHER_BASE_DIR $COMPARE_ROOT/base_dir
fi
- if [ -n "$THIS_DEPLOY_BUNDLE_DIR" ] && [ -n "$OTHER_DEPLOY_BUNDLE_DIR" ]; then
- compare_all_zip_files $THIS_DEPLOY_BUNDLE_DIR $OTHER_DEPLOY_BUNDLE_DIR $COMPARE_ROOT/deploy-bundle
- fi
- if [ -n "$THIS_DEPLOY_APPLET_PLUGIN_DIR" ] && [ -n "$OTHER_DEPLOY_APPLET_PLUGIN_DIR" ]; then
- compare_all_zip_files $THIS_DEPLOY_APPLET_PLUGIN_DIR $OTHER_DEPLOY_APPLET_PLUGIN_DIR $COMPARE_ROOT/plugin
- fi
fi
if [ "$CMP_JARS" = "true" ]; then
if [ -n "$THIS_JDK" ] && [ -n "$OTHER_JDK" ]; then
+ echo -n "JDK "
compare_all_jar_files $THIS_JDK $OTHER_JDK $COMPARE_ROOT/jdk
fi
+ if [ -n "$THIS_TEST" ] && [ -n "$OTHER_TEST" ]; then
+ echo -n "Test "
+ compare_all_jar_files $THIS_TEST $OTHER_TEST $COMPARE_ROOT/test
+ fi
if [ -n "$THIS_BASE_DIR" ] && [ -n "$OTHER_BASE_DIR" ]; then
compare_all_jar_files $THIS_BASE_DIR $OTHER_BASE_DIR $COMPARE_ROOT/base_dir
fi
- if [ -n "$THIS_DEPLOY_APPLET_PLUGIN_DIR" ] && [ -n "$OTHER_DEPLOY_APPLET_PLUGIN_DIR" ]; then
- compare_all_jar_files $THIS_DEPLOY_APPLET_PLUGIN_DIR $OTHER_DEPLOY_APPLET_PLUGIN_DIR $COMPARE_ROOT/plugin
- fi
fi
if [ "$CMP_JMODS" = "true" ]; then
@@ -1723,14 +1688,6 @@ if [ "$CMP_PERMS" = "true" ]; then
if [ -n "$THIS_BASE_DIR" ] && [ -n "$OTHER_BASE_DIR" ]; then
compare_permissions $THIS_BASE_DIR $OTHER_BASE_DIR $COMPARE_ROOT/base_dir
fi
- if [ -n "$THIS_DEPLOY_APPLET_PLUGIN_DIR" ] && [ -n "$OTHER_DEPLOY_APPLET_PLUGIN_DIR" ]; then
- echo -n "JavaAppletPlugin "
- compare_permissions $THIS_DEPLOY_APPLET_PLUGIN_DIR $OTHER_DEPLOY_APPLET_PLUGIN_DIR $COMPARE_ROOT/plugin
- fi
- if [ -n "$THIS_SPARKLE_DIR" ] && [ -n "$OTHER_SPARKLE_DIR" ]; then
- echo -n "Sparkle.framework "
- compare_permissions $THIS_SPARKLE_DIR $OTHER_SPARKLE_DIR $COMPARE_ROOT/sparkle
- fi
fi
if [ "$CMP_TYPES" = "true" ]; then
@@ -1742,17 +1699,13 @@ if [ "$CMP_TYPES" = "true" ]; then
echo -n "JDK Bundle "
compare_file_types $THIS_JDK_BUNDLE $OTHER_JDK_BUNDLE $COMPARE_ROOT/jdk-bundle
fi
+ if [ -n "$THIS_TEST" ] && [ -n "$OTHER_TEST" ]; then
+ echo -n "Test "
+ compare_file_types $THIS_JDK $OTHER_JDK $COMPARE_ROOT/jdk
+ fi
if [ -n "$THIS_BASE_DIR" ] && [ -n "$OTHER_BASE_DIR" ]; then
compare_file_types $THIS_BASE_DIR $OTHER_BASE_DIR $COMPARE_ROOT/base_dir
fi
- if [ -n "$THIS_DEPLOY_APPLET_PLUGIN_DIR" ] && [ -n "$OTHER_DEPLOY_APPLET_PLUGIN_DIR" ]; then
- echo -n "JavaAppletPlugin "
- compare_file_types $THIS_DEPLOY_APPLET_PLUGIN_DIR $OTHER_DEPLOY_APPLET_PLUGIN_DIR $COMPARE_ROOT/plugin
- fi
- if [ -n "$THIS_SPARKLE_DIR" ] && [ -n "$OTHER_SPARKLE_DIR" ]; then
- echo -n "Sparkle.framework "
- compare_file_types $THIS_SPARKLE_DIR $OTHER_SPARKLE_DIR $COMPARE_ROOT/sparkle
- fi
fi
echo
diff --git a/make/scripts/compare_exceptions.sh.incl b/make/scripts/compare_exceptions.sh.incl
index cd4ceae6374..7732706bc68 100644
--- a/make/scripts/compare_exceptions.sh.incl
+++ b/make/scripts/compare_exceptions.sh.incl
@@ -38,6 +38,7 @@ fi
if [ "$OPENJDK_TARGET_OS" = "linux" ]; then
ACCEPTED_BIN_DIFF="
./lib/server/libjvm.so
+ ./hotspot/gtest/server/libjvm.so
"
elif [ "$OPENJDK_TARGET_OS" = "solaris" ]; then
SKIP_BIN_DIFF="true"
@@ -49,6 +50,7 @@ elif [ "$OPENJDK_TARGET_OS" = "solaris" ]; then
./lib/libunpack.so
./lib/server/libjvm.so
./bin/unpack200
+ ./hotspot/gtest/server/libjvm.so
"
KNOWN_DIS_DIFF="
./lib/libfontmanager.so
@@ -68,5 +70,6 @@ elif [ "$OPENJDK_TARGET_OS" = "macosx" ]; then
./lib/libosxapp.dylib
./lib/libosxui.dylib
./lib/server/libjvm.dylib
+ ./hotspot/gtest/server/libjvm.dylib
"
fi
diff --git a/src/hotspot/cpu/aarch64/aarch64.ad b/src/hotspot/cpu/aarch64/aarch64.ad
index 01787bd58a4..d4bb3b2d28f 100644
--- a/src/hotspot/cpu/aarch64/aarch64.ad
+++ b/src/hotspot/cpu/aarch64/aarch64.ad
@@ -3445,7 +3445,7 @@ encode %{
// markOop of object (disp_hdr) with the stack pointer.
__ mov(rscratch1, sp);
__ sub(disp_hdr, disp_hdr, rscratch1);
- __ mov(tmp, (address) (~(os::vm_page_size()-1) | markOopDesc::lock_mask_in_place));
+ __ mov(tmp, (address) (~(os::vm_page_size()-1) | (uintptr_t)markOopDesc::lock_mask_in_place));
// If condition is true we are cont and hence we can store 0 as the
// displaced header in the box, which indicates that it is a recursive lock.
__ ands(tmp/*==0?*/, disp_hdr, tmp); // Sets flags for result
diff --git a/src/hotspot/cpu/aarch64/gc/g1/g1BarrierSetAssembler_aarch64.cpp b/src/hotspot/cpu/aarch64/gc/g1/g1BarrierSetAssembler_aarch64.cpp
index c9fcc118ddb..3efc47399e0 100644
--- a/src/hotspot/cpu/aarch64/gc/g1/g1BarrierSetAssembler_aarch64.cpp
+++ b/src/hotspot/cpu/aarch64/gc/g1/g1BarrierSetAssembler_aarch64.cpp
@@ -72,15 +72,12 @@ void G1BarrierSetAssembler::gen_write_ref_array_pre_barrier(MacroAssembler* masm
}
void G1BarrierSetAssembler::gen_write_ref_array_post_barrier(MacroAssembler* masm, DecoratorSet decorators,
- Register start, Register end, Register scratch, RegSet saved_regs) {
+ Register start, Register count, Register scratch, RegSet saved_regs) {
__ push(saved_regs, sp);
- // must compute element count unless barrier set interface is changed (other platforms supply count)
- assert_different_registers(start, end, scratch);
- __ lea(scratch, Address(end, BytesPerHeapOop));
- __ sub(scratch, scratch, start); // subtract start to get #bytes
- __ lsr(scratch, scratch, LogBytesPerHeapOop); // convert to element count
+ assert_different_registers(start, count, scratch);
+ assert_different_registers(c_rarg0, count);
__ mov(c_rarg0, start);
- __ mov(c_rarg1, scratch);
+ __ mov(c_rarg1, count);
__ call_VM_leaf(CAST_FROM_FN_PTR(address, G1BarrierSetRuntime::write_ref_array_post_entry), 2);
__ pop(saved_regs, sp);
}
diff --git a/src/hotspot/cpu/aarch64/gc/g1/g1BarrierSetAssembler_aarch64.hpp b/src/hotspot/cpu/aarch64/gc/g1/g1BarrierSetAssembler_aarch64.hpp
index 965fd06b517..e38746f4f9e 100644
--- a/src/hotspot/cpu/aarch64/gc/g1/g1BarrierSetAssembler_aarch64.hpp
+++ b/src/hotspot/cpu/aarch64/gc/g1/g1BarrierSetAssembler_aarch64.hpp
@@ -39,7 +39,7 @@ protected:
void gen_write_ref_array_pre_barrier(MacroAssembler* masm, DecoratorSet decorators,
Register addr, Register count, RegSet saved_regs);
void gen_write_ref_array_post_barrier(MacroAssembler* masm, DecoratorSet decorators,
- Register start, Register end, Register tmp, RegSet saved_regs);
+ Register start, Register count, Register tmp, RegSet saved_regs);
void g1_write_barrier_pre(MacroAssembler* masm,
Register obj,
diff --git a/src/hotspot/cpu/aarch64/gc/shared/cardTableBarrierSetAssembler_aarch64.cpp b/src/hotspot/cpu/aarch64/gc/shared/cardTableBarrierSetAssembler_aarch64.cpp
index 29892504d31..30dfa5df55c 100644
--- a/src/hotspot/cpu/aarch64/gc/shared/cardTableBarrierSetAssembler_aarch64.cpp
+++ b/src/hotspot/cpu/aarch64/gc/shared/cardTableBarrierSetAssembler_aarch64.cpp
@@ -62,18 +62,22 @@ void CardTableBarrierSetAssembler::store_check(MacroAssembler* masm, Register ob
}
void CardTableBarrierSetAssembler::gen_write_ref_array_post_barrier(MacroAssembler* masm, DecoratorSet decorators,
- Register start, Register end, Register scratch, RegSet saved_regs) {
+ Register start, Register count, Register scratch, RegSet saved_regs) {
BarrierSet* bs = BarrierSet::barrier_set();
CardTableBarrierSet* ctbs = barrier_set_cast(bs);
CardTable* ct = ctbs->card_table();
- Label L_loop;
+ Label L_loop, L_done;
+ const Register end = count;
+ __ cbz(count, L_done); // zero count - nothing to do
+
+ __ lea(end, Address(start, count, Address::lsl(LogBytesPerHeapOop))); // end = start + count << LogBytesPerHeapOop
+ __ sub(end, end, BytesPerHeapOop); // last element address to make inclusive
__ lsr(start, start, CardTable::card_shift);
__ lsr(end, end, CardTable::card_shift);
- __ sub(end, end, start); // number of bytes to copy
+ __ sub(count, end, start); // number of bytes to copy
- const Register count = end; // 'end' register contains bytes count now
__ load_byte_map_base(scratch);
__ add(start, start, scratch);
if (ct->scanned_concurrently()) {
@@ -83,6 +87,7 @@ void CardTableBarrierSetAssembler::gen_write_ref_array_post_barrier(MacroAssembl
__ strb(zr, Address(start, count));
__ subs(count, count, 1);
__ br(Assembler::GE, L_loop);
+ __ bind(L_done);
}
void CardTableBarrierSetAssembler::oop_store_at(MacroAssembler* masm, DecoratorSet decorators, BasicType type,
diff --git a/src/hotspot/cpu/aarch64/gc/shared/cardTableBarrierSetAssembler_aarch64.hpp b/src/hotspot/cpu/aarch64/gc/shared/cardTableBarrierSetAssembler_aarch64.hpp
index f58904430ca..844a9595797 100644
--- a/src/hotspot/cpu/aarch64/gc/shared/cardTableBarrierSetAssembler_aarch64.hpp
+++ b/src/hotspot/cpu/aarch64/gc/shared/cardTableBarrierSetAssembler_aarch64.hpp
@@ -33,7 +33,7 @@ protected:
void store_check(MacroAssembler* masm, Register obj, Address dst);
virtual void gen_write_ref_array_post_barrier(MacroAssembler* masm, DecoratorSet decorators,
- Register start, Register end, Register tmp, RegSet saved_regs);
+ Register start, Register count, Register tmp, RegSet saved_regs);
virtual void oop_store_at(MacroAssembler* masm, DecoratorSet decorators, BasicType type,
Address dst, Register val, Register tmp1, Register tmp2);
diff --git a/src/hotspot/cpu/aarch64/gc/shared/modRefBarrierSetAssembler_aarch64.cpp b/src/hotspot/cpu/aarch64/gc/shared/modRefBarrierSetAssembler_aarch64.cpp
index 7693e0b4bf3..a28c50169d8 100644
--- a/src/hotspot/cpu/aarch64/gc/shared/modRefBarrierSetAssembler_aarch64.cpp
+++ b/src/hotspot/cpu/aarch64/gc/shared/modRefBarrierSetAssembler_aarch64.cpp
@@ -37,10 +37,10 @@ void ModRefBarrierSetAssembler::arraycopy_prologue(MacroAssembler* masm, Decorat
}
void ModRefBarrierSetAssembler::arraycopy_epilogue(MacroAssembler* masm, DecoratorSet decorators, bool is_oop,
- Register start, Register end, Register tmp,
+ Register start, Register count, Register tmp,
RegSet saved_regs) {
if (is_oop) {
- gen_write_ref_array_post_barrier(masm, decorators, start, end, tmp, saved_regs);
+ gen_write_ref_array_post_barrier(masm, decorators, start, count, tmp, saved_regs);
}
}
diff --git a/src/hotspot/cpu/aarch64/gc/shared/modRefBarrierSetAssembler_aarch64.hpp b/src/hotspot/cpu/aarch64/gc/shared/modRefBarrierSetAssembler_aarch64.hpp
index f0de0957047..e145b5d74f1 100644
--- a/src/hotspot/cpu/aarch64/gc/shared/modRefBarrierSetAssembler_aarch64.hpp
+++ b/src/hotspot/cpu/aarch64/gc/shared/modRefBarrierSetAssembler_aarch64.hpp
@@ -37,7 +37,7 @@ protected:
virtual void gen_write_ref_array_pre_barrier(MacroAssembler* masm, DecoratorSet decorators,
Register addr, Register count, RegSet saved_regs) {}
virtual void gen_write_ref_array_post_barrier(MacroAssembler* masm, DecoratorSet decorators,
- Register start, Register end, Register tmp, RegSet saved_regs) {}
+ Register start, Register count, Register tmp, RegSet saved_regs) {}
virtual void oop_store_at(MacroAssembler* masm, DecoratorSet decorators, BasicType type,
Address dst, Register val, Register tmp1, Register tmp2) = 0;
@@ -46,7 +46,7 @@ public:
virtual void arraycopy_prologue(MacroAssembler* masm, DecoratorSet decorators, bool is_oop,
Register addr, Register count, RegSet saved_regs);
virtual void arraycopy_epilogue(MacroAssembler* masm, DecoratorSet decorators, bool is_oop,
- Register start, Register end, Register tmp, RegSet saved_regs);
+ Register start, Register count, Register tmp, RegSet saved_regs);
virtual void store_at(MacroAssembler* masm, DecoratorSet decorators, BasicType type,
Address dst, Register val, Register tmp1, Register tmp2);
};
diff --git a/src/hotspot/cpu/aarch64/gc/shenandoah/shenandoahBarrierSetAssembler_aarch64.cpp b/src/hotspot/cpu/aarch64/gc/shenandoah/shenandoahBarrierSetAssembler_aarch64.cpp
index cca1b4d304d..e4d4d7e6c8a 100644
--- a/src/hotspot/cpu/aarch64/gc/shenandoah/shenandoahBarrierSetAssembler_aarch64.cpp
+++ b/src/hotspot/cpu/aarch64/gc/shenandoah/shenandoahBarrierSetAssembler_aarch64.cpp
@@ -73,16 +73,13 @@ void ShenandoahBarrierSetAssembler::arraycopy_prologue(MacroAssembler* masm, Dec
}
void ShenandoahBarrierSetAssembler::arraycopy_epilogue(MacroAssembler* masm, DecoratorSet decorators, bool is_oop,
- Register start, Register end, Register scratch, RegSet saved_regs) {
+ Register start, Register count, Register scratch, RegSet saved_regs) {
if (is_oop) {
__ push(saved_regs, sp);
- // must compute element count unless barrier set interface is changed (other platforms supply count)
- assert_different_registers(start, end, scratch);
- __ lea(scratch, Address(end, BytesPerHeapOop));
- __ sub(scratch, scratch, start); // subtract start to get #bytes
- __ lsr(scratch, scratch, LogBytesPerHeapOop); // convert to element count
+ assert_different_registers(start, count, scratch);
+ assert_different_registers(c_rarg0, count);
__ mov(c_rarg0, start);
- __ mov(c_rarg1, scratch);
+ __ mov(c_rarg1, count);
__ call_VM_leaf(CAST_FROM_FN_PTR(address, ShenandoahRuntime::write_ref_array_post_entry), 2);
__ pop(saved_regs, sp);
}
diff --git a/src/hotspot/cpu/aarch64/gc/shenandoah/shenandoahBarrierSetAssembler_aarch64.hpp b/src/hotspot/cpu/aarch64/gc/shenandoah/shenandoahBarrierSetAssembler_aarch64.hpp
index 68cf6dce06b..69e0782cf44 100644
--- a/src/hotspot/cpu/aarch64/gc/shenandoah/shenandoahBarrierSetAssembler_aarch64.hpp
+++ b/src/hotspot/cpu/aarch64/gc/shenandoah/shenandoahBarrierSetAssembler_aarch64.hpp
@@ -78,7 +78,7 @@ public:
virtual void arraycopy_prologue(MacroAssembler* masm, DecoratorSet decorators, bool is_oop,
Register addr, Register count, RegSet saved_regs);
virtual void arraycopy_epilogue(MacroAssembler* masm, DecoratorSet decorators, bool is_oop,
- Register start, Register end, Register tmp, RegSet saved_regs);
+ Register start, Register count, Register tmp, RegSet saved_regs);
virtual void load_at(MacroAssembler* masm, DecoratorSet decorators, BasicType type,
Register dst, Address src, Register tmp1, Register tmp_thread);
virtual void store_at(MacroAssembler* masm, DecoratorSet decorators, BasicType type,
diff --git a/src/hotspot/cpu/aarch64/stubGenerator_aarch64.cpp b/src/hotspot/cpu/aarch64/stubGenerator_aarch64.cpp
index 8115ffcbdd2..ae1efcde37e 100644
--- a/src/hotspot/cpu/aarch64/stubGenerator_aarch64.cpp
+++ b/src/hotspot/cpu/aarch64/stubGenerator_aarch64.cpp
@@ -1375,8 +1375,6 @@ class StubGenerator: public StubCodeGenerator {
__ pop(RegSet::of(d, count), sp);
if (VerifyOops)
verify_oop_array(size, d, count, r16);
- __ sub(count, count, 1); // make an inclusive end pointer
- __ lea(count, Address(d, count, Address::lsl(exact_log2(size))));
}
bs->arraycopy_epilogue(_masm, decorators, is_oop, d, count, rscratch1, RegSet());
@@ -1448,8 +1446,6 @@ class StubGenerator: public StubCodeGenerator {
__ pop(RegSet::of(d, count), sp);
if (VerifyOops)
verify_oop_array(size, d, count, r16);
- __ sub(count, count, 1); // make an inclusive end pointer
- __ lea(count, Address(d, count, Address::lsl(exact_log2(size))));
}
bs->arraycopy_epilogue(_masm, decorators, is_oop, d, count, rscratch1, RegSet());
__ leave();
@@ -1842,8 +1838,7 @@ class StubGenerator: public StubCodeGenerator {
__ br(Assembler::EQ, L_done_pop);
__ BIND(L_do_card_marks);
- __ add(to, to, -heapOopSize); // make an inclusive end pointer
- bs->arraycopy_epilogue(_masm, decorators, is_oop, start_to, to, rscratch1, wb_post_saved_regs);
+ bs->arraycopy_epilogue(_masm, decorators, is_oop, start_to, count_save, rscratch1, wb_post_saved_regs);
__ bind(L_done_pop);
__ pop(RegSet::of(r18, r19, r20, r21), sp);
diff --git a/src/hotspot/cpu/aarch64/templateTable_aarch64.cpp b/src/hotspot/cpu/aarch64/templateTable_aarch64.cpp
index 8cb1c8b5387..52a230d6a03 100644
--- a/src/hotspot/cpu/aarch64/templateTable_aarch64.cpp
+++ b/src/hotspot/cpu/aarch64/templateTable_aarch64.cpp
@@ -2885,7 +2885,7 @@ void TemplateTable::putfield_or_static(int byte_no, bool is_static, RewriteContr
{
Label notVolatile;
__ tbz(r5, ConstantPoolCacheEntry::is_volatile_shift, notVolatile);
- __ membar(MacroAssembler::StoreLoad);
+ __ membar(MacroAssembler::StoreLoad | MacroAssembler::StoreStore);
__ bind(notVolatile);
}
}
@@ -3029,7 +3029,7 @@ void TemplateTable::fast_storefield(TosState state)
{
Label notVolatile;
__ tbz(r3, ConstantPoolCacheEntry::is_volatile_shift, notVolatile);
- __ membar(MacroAssembler::StoreLoad);
+ __ membar(MacroAssembler::StoreLoad | MacroAssembler::StoreStore);
__ bind(notVolatile);
}
}
diff --git a/src/hotspot/cpu/ppc/c1_LIRAssembler_ppc.cpp b/src/hotspot/cpu/ppc/c1_LIRAssembler_ppc.cpp
index 3c17e1aa8f8..e83f0274797 100644
--- a/src/hotspot/cpu/ppc/c1_LIRAssembler_ppc.cpp
+++ b/src/hotspot/cpu/ppc/c1_LIRAssembler_ppc.cpp
@@ -1455,13 +1455,11 @@ void LIR_Assembler::comp_op(LIR_Condition condition, LIR_Opr opr1, LIR_Opr opr2,
break;
}
} else {
- if (opr2->is_address()) {
- DEBUG_ONLY( Unimplemented(); ) // Seems to be unused at the moment.
- LIR_Address *addr = opr2->as_address_ptr();
- BasicType type = addr->type();
- if (type == T_OBJECT) { __ ld(R0, index_or_disp(addr), addr->base()->as_register()); }
- else { __ lwa(R0, index_or_disp(addr), addr->base()->as_register()); }
- __ cmpd(BOOL_RESULT, opr1->as_register(), R0);
+ assert(opr1->type() != T_ADDRESS && opr2->type() != T_ADDRESS, "currently unsupported");
+ if (opr1->type() == T_OBJECT || opr1->type() == T_ARRAY) {
+ // There are only equal/notequal comparisons on objects.
+ assert(condition == lir_cond_equal || condition == lir_cond_notEqual, "oops");
+ __ cmpd(BOOL_RESULT, opr1->as_register(), opr2->as_register());
} else {
if (unsigned_comp) {
__ cmplw(BOOL_RESULT, opr1->as_register(), opr2->as_register());
@@ -1497,14 +1495,6 @@ void LIR_Assembler::comp_op(LIR_Condition condition, LIR_Opr opr1, LIR_Opr opr2,
} else {
ShouldNotReachHere();
}
- } else if (opr1->is_address()) {
- DEBUG_ONLY( Unimplemented(); ) // Seems to be unused at the moment.
- LIR_Address * addr = opr1->as_address_ptr();
- BasicType type = addr->type();
- assert (opr2->is_constant(), "Checking");
- if (type == T_OBJECT) { __ ld(R0, index_or_disp(addr), addr->base()->as_register()); }
- else { __ lwa(R0, index_or_disp(addr), addr->base()->as_register()); }
- __ cmpdi(BOOL_RESULT, R0, opr2->as_constant_ptr()->as_jint());
} else {
ShouldNotReachHere();
}
diff --git a/src/hotspot/cpu/ppc/gc/shared/barrierSetAssembler_ppc.cpp b/src/hotspot/cpu/ppc/gc/shared/barrierSetAssembler_ppc.cpp
index 75b3f431165..5c470a7974f 100644
--- a/src/hotspot/cpu/ppc/gc/shared/barrierSetAssembler_ppc.cpp
+++ b/src/hotspot/cpu/ppc/gc/shared/barrierSetAssembler_ppc.cpp
@@ -27,6 +27,7 @@
#include "asm/macroAssembler.inline.hpp"
#include "gc/shared/barrierSetAssembler.hpp"
#include "interpreter/interp_masm.hpp"
+#include "runtime/jniHandles.hpp"
#define __ masm->
diff --git a/src/hotspot/cpu/x86/crc32c.h b/src/hotspot/cpu/x86/crc32c.h
index 83746b42947..dfdbd525e77 100644
--- a/src/hotspot/cpu/x86/crc32c.h
+++ b/src/hotspot/cpu/x86/crc32c.h
@@ -1,5 +1,5 @@
/*
-* Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+* Copyright (c) 2015, 2019, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -22,6 +22,9 @@
*
*/
+#ifndef CPU_X86_CRC32C_H
+#define CPU_X86_CRC32C_H
+
enum {
// S. Gueron / Information Processing Letters 112 (2012) 184
// shows than anything above 6K and below 32K is a good choice
@@ -64,3 +67,5 @@ enum {
// a) constants table generation (hotspot/src/cpu/x86/vm/stubRoutines_x86.cpp)
// b) constant fetch from that table (macroAssembler_x86.cpp)
// c) unrolled for loop (macroAssembler_x86.cpp)
+
+#endif /* !CPU_X86_CRC32C_H */
diff --git a/src/hotspot/cpu/x86/vm_version_x86.cpp b/src/hotspot/cpu/x86/vm_version_x86.cpp
index 1550df75035..7166fae452b 100644
--- a/src/hotspot/cpu/x86/vm_version_x86.cpp
+++ b/src/hotspot/cpu/x86/vm_version_x86.cpp
@@ -901,11 +901,15 @@ void VM_Version::get_processor_features() {
FLAG_SET_DEFAULT(UseSHA256Intrinsics, false);
}
+#ifdef _LP64
+ // These are only supported on 64-bit
if (UseSHA && supports_avx2() && supports_bmi2()) {
if (FLAG_IS_DEFAULT(UseSHA512Intrinsics)) {
FLAG_SET_DEFAULT(UseSHA512Intrinsics, true);
}
- } else if (UseSHA512Intrinsics) {
+ } else
+#endif
+ if (UseSHA512Intrinsics) {
warning("Intrinsics for SHA-384 and SHA-512 crypto hash functions not available on this CPU.");
FLAG_SET_DEFAULT(UseSHA512Intrinsics, false);
}
diff --git a/src/hotspot/os/aix/os_aix.cpp b/src/hotspot/os/aix/os_aix.cpp
index 10f3cd2af4d..a55b9caa7e6 100644
--- a/src/hotspot/os/aix/os_aix.cpp
+++ b/src/hotspot/os/aix/os_aix.cpp
@@ -37,6 +37,7 @@
#include "compiler/compileBroker.hpp"
#include "interpreter/interpreter.hpp"
#include "logging/log.hpp"
+#include "logging/logStream.hpp"
#include "libo4.hpp"
#include "libperfstat_aix.hpp"
#include "libodm_aix.hpp"
@@ -923,6 +924,11 @@ bool os::create_thread(Thread* thread, ThreadType thr_type,
char buf[64];
log_warning(os, thread)("Failed to start thread - pthread_create failed (%d=%s) for attributes: %s.",
ret, os::errno_name(ret), os::Posix::describe_pthread_attr(buf, sizeof(buf), &attr));
+ // Log some OS information which might explain why creating the thread failed.
+ log_info(os, thread)("Number of threads approx. running in the VM: %d", Threads::number_of_threads());
+ LogStream st(Log(os, thread)::info());
+ os::Posix::print_rlimit_info(&st);
+ os::print_memory_info(&st);
}
pthread_attr_destroy(&attr);
diff --git a/src/hotspot/os/bsd/os_bsd.cpp b/src/hotspot/os/bsd/os_bsd.cpp
index b48613a0fe8..30ed4d859ca 100644
--- a/src/hotspot/os/bsd/os_bsd.cpp
+++ b/src/hotspot/os/bsd/os_bsd.cpp
@@ -33,6 +33,7 @@
#include "compiler/disassembler.hpp"
#include "interpreter/interpreter.hpp"
#include "logging/log.hpp"
+#include "logging/logStream.hpp"
#include "memory/allocation.inline.hpp"
#include "memory/filemap.hpp"
#include "oops/oop.inline.hpp"
@@ -743,6 +744,11 @@ bool os::create_thread(Thread* thread, ThreadType thr_type,
} else {
log_warning(os, thread)("Failed to start thread - pthread_create failed (%s) for attributes: %s.",
os::errno_name(ret), os::Posix::describe_pthread_attr(buf, sizeof(buf), &attr));
+ // Log some OS information which might explain why creating the thread failed.
+ log_info(os, thread)("Number of threads approx. running in the VM: %d", Threads::number_of_threads());
+ LogStream st(Log(os, thread)::info());
+ os::Posix::print_rlimit_info(&st);
+ os::print_memory_info(&st);
}
pthread_attr_destroy(&attr);
diff --git a/src/hotspot/os/linux/os_linux.cpp b/src/hotspot/os/linux/os_linux.cpp
index ecbbecc776f..515ce5b48cb 100644
--- a/src/hotspot/os/linux/os_linux.cpp
+++ b/src/hotspot/os/linux/os_linux.cpp
@@ -780,6 +780,13 @@ bool os::create_thread(Thread* thread, ThreadType thr_type,
} else {
log_warning(os, thread)("Failed to start thread - pthread_create failed (%s) for attributes: %s.",
os::errno_name(ret), os::Posix::describe_pthread_attr(buf, sizeof(buf), &attr));
+ // Log some OS information which might explain why creating the thread failed.
+ log_info(os, thread)("Number of threads approx. running in the VM: %d", Threads::number_of_threads());
+ LogStream st(Log(os, thread)::info());
+ os::Posix::print_rlimit_info(&st);
+ os::print_memory_info(&st);
+ os::Linux::print_proc_sys_info(&st);
+ os::Linux::print_container_info(&st);
}
pthread_attr_destroy(&attr);
diff --git a/src/hotspot/os/solaris/os_solaris.cpp b/src/hotspot/os/solaris/os_solaris.cpp
index b866e833474..0150c63bc0a 100644
--- a/src/hotspot/os/solaris/os_solaris.cpp
+++ b/src/hotspot/os/solaris/os_solaris.cpp
@@ -33,6 +33,7 @@
#include "compiler/disassembler.hpp"
#include "interpreter/interpreter.hpp"
#include "logging/log.hpp"
+#include "logging/logStream.hpp"
#include "memory/allocation.inline.hpp"
#include "memory/filemap.hpp"
#include "oops/oop.inline.hpp"
@@ -992,6 +993,11 @@ bool os::create_thread(Thread* thread, ThreadType thr_type,
} else {
log_warning(os, thread)("Failed to start thread - thr_create failed (%s) for attributes: %s.",
os::errno_name(status), describe_thr_create_attributes(buf, sizeof(buf), stack_size, flags));
+ // Log some OS information which might explain why creating the thread failed.
+ log_info(os, thread)("Number of threads approx. running in the VM: %d", Threads::number_of_threads());
+ LogStream st(Log(os, thread)::info());
+ os::Posix::print_rlimit_info(&st);
+ os::print_memory_info(&st);
}
if (status != 0) {
diff --git a/src/hotspot/os/windows/os_windows.cpp b/src/hotspot/os/windows/os_windows.cpp
index 55e250f6879..729521cfc74 100644
--- a/src/hotspot/os/windows/os_windows.cpp
+++ b/src/hotspot/os/windows/os_windows.cpp
@@ -36,6 +36,7 @@
#include "compiler/disassembler.hpp"
#include "interpreter/interpreter.hpp"
#include "logging/log.hpp"
+#include "logging/logStream.hpp"
#include "memory/allocation.inline.hpp"
#include "memory/filemap.hpp"
#include "oops/oop.inline.hpp"
@@ -669,6 +670,10 @@ bool os::create_thread(Thread* thread, ThreadType thr_type,
} else {
log_warning(os, thread)("Failed to start thread - _beginthreadex failed (%s) for attributes: %s.",
os::errno_name(errno), describe_beginthreadex_attributes(buf, sizeof(buf), stack_size, initflag));
+ // Log some OS information which might explain why creating the thread failed.
+ log_info(os, thread)("Number of threads approx. running in the VM: %d", Threads::number_of_threads());
+ LogStream st(Log(os, thread)::info());
+ os::print_memory_info(&st);
}
if (thread_handle == NULL) {
diff --git a/src/hotspot/os_cpu/aix_ppc/orderAccess_aix_ppc.hpp b/src/hotspot/os_cpu/aix_ppc/orderAccess_aix_ppc.hpp
index 1aea4e78d93..8502ed46356 100644
--- a/src/hotspot/os_cpu/aix_ppc/orderAccess_aix_ppc.hpp
+++ b/src/hotspot/os_cpu/aix_ppc/orderAccess_aix_ppc.hpp
@@ -77,6 +77,8 @@ inline void OrderAccess::storeload() { inlasm_sync(); }
inline void OrderAccess::acquire() { inlasm_lwsync(); }
inline void OrderAccess::release() { inlasm_lwsync(); }
inline void OrderAccess::fence() { inlasm_sync(); }
+inline void OrderAccess::cross_modify_fence()
+ { inlasm_isync(); }
template
struct OrderAccess::PlatformOrderedLoad
diff --git a/src/hotspot/os_cpu/bsd_x86/orderAccess_bsd_x86.hpp b/src/hotspot/os_cpu/bsd_x86/orderAccess_bsd_x86.hpp
index 6f54eee501b..ba4837c19c4 100644
--- a/src/hotspot/os_cpu/bsd_x86/orderAccess_bsd_x86.hpp
+++ b/src/hotspot/os_cpu/bsd_x86/orderAccess_bsd_x86.hpp
@@ -59,6 +59,11 @@ inline void OrderAccess::fence() {
compiler_barrier();
}
+inline void OrderAccess::cross_modify_fence() {
+ int idx = 0;
+ __asm__ volatile ("cpuid " : "+a" (idx) : : "ebx", "ecx", "edx", "memory");
+}
+
template<>
struct OrderAccess::PlatformOrderedStore<1, RELEASE_X_FENCE>
{
diff --git a/src/hotspot/os_cpu/bsd_zero/orderAccess_bsd_zero.hpp b/src/hotspot/os_cpu/bsd_zero/orderAccess_bsd_zero.hpp
index 44bcca78579..6130c42255a 100644
--- a/src/hotspot/os_cpu/bsd_zero/orderAccess_bsd_zero.hpp
+++ b/src/hotspot/os_cpu/bsd_zero/orderAccess_bsd_zero.hpp
@@ -73,5 +73,6 @@ inline void OrderAccess::storeload() { FULL_MEM_BARRIER; }
inline void OrderAccess::acquire() { LIGHT_MEM_BARRIER; }
inline void OrderAccess::release() { LIGHT_MEM_BARRIER; }
inline void OrderAccess::fence() { FULL_MEM_BARRIER; }
+inline void OrderAccess::cross_modify_fence() { }
#endif // OS_CPU_BSD_ZERO_ORDERACCESS_BSD_ZERO_HPP
diff --git a/src/hotspot/os_cpu/linux_aarch64/orderAccess_linux_aarch64.hpp b/src/hotspot/os_cpu/linux_aarch64/orderAccess_linux_aarch64.hpp
index 052e66630cc..93430a8c139 100644
--- a/src/hotspot/os_cpu/linux_aarch64/orderAccess_linux_aarch64.hpp
+++ b/src/hotspot/os_cpu/linux_aarch64/orderAccess_linux_aarch64.hpp
@@ -49,6 +49,8 @@ inline void OrderAccess::fence() {
FULL_MEM_BARRIER;
}
+inline void OrderAccess::cross_modify_fence() { }
+
template
struct OrderAccess::PlatformOrderedLoad
{
diff --git a/src/hotspot/os_cpu/linux_arm/orderAccess_linux_arm.hpp b/src/hotspot/os_cpu/linux_arm/orderAccess_linux_arm.hpp
index 6125bd5d040..90f64352da7 100644
--- a/src/hotspot/os_cpu/linux_arm/orderAccess_linux_arm.hpp
+++ b/src/hotspot/os_cpu/linux_arm/orderAccess_linux_arm.hpp
@@ -101,5 +101,6 @@ inline void OrderAccess::storestore() { dmb_st(); }
inline void OrderAccess::storeload() { dmb_sy(); }
inline void OrderAccess::release() { dmb_sy(); }
inline void OrderAccess::fence() { dmb_sy(); }
+inline void OrderAccess::cross_modify_fence() { }
#endif // OS_CPU_LINUX_ARM_ORDERACCESS_LINUX_ARM_HPP
diff --git a/src/hotspot/os_cpu/linux_ppc/orderAccess_linux_ppc.hpp b/src/hotspot/os_cpu/linux_ppc/orderAccess_linux_ppc.hpp
index 928c2d8339b..8dc0100c620 100644
--- a/src/hotspot/os_cpu/linux_ppc/orderAccess_linux_ppc.hpp
+++ b/src/hotspot/os_cpu/linux_ppc/orderAccess_linux_ppc.hpp
@@ -79,7 +79,8 @@ inline void OrderAccess::storeload() { inlasm_sync(); }
inline void OrderAccess::acquire() { inlasm_lwsync(); }
inline void OrderAccess::release() { inlasm_lwsync(); }
inline void OrderAccess::fence() { inlasm_sync(); }
-
+inline void OrderAccess::cross_modify_fence()
+ { inlasm_isync(); }
template
struct OrderAccess::PlatformOrderedLoad
diff --git a/src/hotspot/os_cpu/linux_ppc/os_linux_ppc.cpp b/src/hotspot/os_cpu/linux_ppc/os_linux_ppc.cpp
index fa71b11a84d..dd1790abf46 100644
--- a/src/hotspot/os_cpu/linux_ppc/os_linux_ppc.cpp
+++ b/src/hotspot/os_cpu/linux_ppc/os_linux_ppc.cpp
@@ -132,6 +132,10 @@ intptr_t* os::Linux::ucontext_get_fp(const ucontext_t * uc) {
return NULL;
}
+static unsigned long ucontext_get_trap(const ucontext_t * uc) {
+ return uc->uc_mcontext.regs->trap;
+}
+
ExtendedPC os::fetch_frame_from_context(const void* ucVoid,
intptr_t** ret_sp, intptr_t** ret_fp) {
@@ -304,9 +308,22 @@ JVM_handle_linux_signal(int sig,
// Handle ALL stack overflow variations here
if (sig == SIGSEGV) {
- // Si_addr may not be valid due to a bug in the linux-ppc64 kernel (see
+ // si_addr may not be valid due to a bug in the linux-ppc64 kernel (see
// comment below). Use get_stack_bang_address instead of si_addr.
- address addr = ((NativeInstruction*)pc)->get_stack_bang_address(uc);
+ // If SIGSEGV is caused due to a branch to an invalid address an
+ // "Instruction Storage" interruption is generated and 'pc' (NIP) already
+ // contains the invalid address. Otherwise, the SIGSEGV is caused due to
+ // load/store instruction trying to load/store from/to an invalid address
+ // and causing a "Data Storage" interruption, so we inspect the intruction
+ // in order to extract the faulty data addresss.
+ address addr;
+ if ((ucontext_get_trap(uc) & 0x0F00 /* no IRQ reply bits */) == 0x0400) {
+ // Instruction interruption
+ addr = pc;
+ } else {
+ // Data interruption (0x0300): extract faulty data address
+ addr = ((NativeInstruction*)pc)->get_stack_bang_address(uc);
+ }
// Check if fault address is within thread stack.
if (thread->on_local_stack(addr)) {
diff --git a/src/hotspot/os_cpu/linux_s390/orderAccess_linux_s390.hpp b/src/hotspot/os_cpu/linux_s390/orderAccess_linux_s390.hpp
index d8decefbc97..c5a05ab1cc1 100644
--- a/src/hotspot/os_cpu/linux_s390/orderAccess_linux_s390.hpp
+++ b/src/hotspot/os_cpu/linux_s390/orderAccess_linux_s390.hpp
@@ -74,6 +74,7 @@ inline void OrderAccess::storeload() { inlasm_zarch_sync(); }
inline void OrderAccess::acquire() { inlasm_zarch_acquire(); }
inline void OrderAccess::release() { inlasm_zarch_release(); }
inline void OrderAccess::fence() { inlasm_zarch_sync(); }
+inline void OrderAccess::cross_modify_fence() { inlasm_zarch_sync(); }
template
struct OrderAccess::PlatformOrderedLoad
diff --git a/src/hotspot/os_cpu/linux_s390/thread_linux_s390.cpp b/src/hotspot/os_cpu/linux_s390/thread_linux_s390.cpp
index 836738f197e..c3379f5049e 100644
--- a/src/hotspot/os_cpu/linux_s390/thread_linux_s390.cpp
+++ b/src/hotspot/os_cpu/linux_s390/thread_linux_s390.cpp
@@ -1,6 +1,6 @@
/*
- * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
- * Copyright (c) 2016 SAP SE. All rights reserved.
+ * Copyright (c) 2016, 2019, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2016, 2019 SAP SE. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -63,7 +63,7 @@ bool JavaThread::pd_get_top_frame_for_profiling(frame* fr_addr, void* ucontext,
if (ret_frame.is_interpreted_frame()) {
frame::z_ijava_state* istate = ret_frame.ijava_state_unchecked();
- if (!((Method*)(istate->method))->is_metaspace_object()) {
+ if ((stack_base() >= (address)istate && (address)istate > stack_end()) || !((Method*)(istate->method))->is_metaspace_object()) {
return false;
}
uint64_t reg_bcp = uc->uc_mcontext.gregs[13/*Z_BCP*/];
diff --git a/src/hotspot/os_cpu/linux_sparc/orderAccess_linux_sparc.hpp b/src/hotspot/os_cpu/linux_sparc/orderAccess_linux_sparc.hpp
index 5a456e8b8d1..1d91b5836f0 100644
--- a/src/hotspot/os_cpu/linux_sparc/orderAccess_linux_sparc.hpp
+++ b/src/hotspot/os_cpu/linux_sparc/orderAccess_linux_sparc.hpp
@@ -48,4 +48,6 @@ inline void OrderAccess::fence() {
__asm__ volatile ("membar #StoreLoad" : : : "memory");
}
+inline void OrderAccess::cross_modify_fence() { }
+
#endif // OS_CPU_LINUX_SPARC_ORDERACCESS_LINUX_SPARC_HPP
diff --git a/src/hotspot/os_cpu/linux_x86/orderAccess_linux_x86.hpp b/src/hotspot/os_cpu/linux_x86/orderAccess_linux_x86.hpp
index 768a977946a..f5b108401a4 100644
--- a/src/hotspot/os_cpu/linux_x86/orderAccess_linux_x86.hpp
+++ b/src/hotspot/os_cpu/linux_x86/orderAccess_linux_x86.hpp
@@ -55,6 +55,11 @@ inline void OrderAccess::fence() {
compiler_barrier();
}
+inline void OrderAccess::cross_modify_fence() {
+ int idx = 0;
+ __asm__ volatile ("cpuid " : "+a" (idx) : : "ebx", "ecx", "edx", "memory");
+}
+
template<>
struct OrderAccess::PlatformOrderedStore<1, RELEASE_X_FENCE>
{
diff --git a/src/hotspot/os_cpu/linux_zero/orderAccess_linux_zero.hpp b/src/hotspot/os_cpu/linux_zero/orderAccess_linux_zero.hpp
index 490e76b916a..75476d35152 100644
--- a/src/hotspot/os_cpu/linux_zero/orderAccess_linux_zero.hpp
+++ b/src/hotspot/os_cpu/linux_zero/orderAccess_linux_zero.hpp
@@ -82,5 +82,6 @@ inline void OrderAccess::acquire() { LIGHT_MEM_BARRIER; }
inline void OrderAccess::release() { LIGHT_MEM_BARRIER; }
inline void OrderAccess::fence() { FULL_MEM_BARRIER; }
+inline void OrderAccess::cross_modify_fence() { }
#endif // OS_CPU_LINUX_ZERO_ORDERACCESS_LINUX_ZERO_HPP
diff --git a/src/hotspot/os_cpu/solaris_sparc/orderAccess_solaris_sparc.hpp b/src/hotspot/os_cpu/solaris_sparc/orderAccess_solaris_sparc.hpp
index 189e03c1f90..e5e7f152d5b 100644
--- a/src/hotspot/os_cpu/solaris_sparc/orderAccess_solaris_sparc.hpp
+++ b/src/hotspot/os_cpu/solaris_sparc/orderAccess_solaris_sparc.hpp
@@ -51,4 +51,6 @@ inline void OrderAccess::fence() {
__asm__ volatile ("membar #StoreLoad" : : : "memory");
}
+inline void OrderAccess::cross_modify_fence() { }
+
#endif // OS_CPU_SOLARIS_SPARC_ORDERACCESS_SOLARIS_SPARC_HPP
diff --git a/src/hotspot/os_cpu/solaris_x86/orderAccess_solaris_x86.hpp b/src/hotspot/os_cpu/solaris_x86/orderAccess_solaris_x86.hpp
index 3ee65bd736d..fc5d8bdc7d7 100644
--- a/src/hotspot/os_cpu/solaris_x86/orderAccess_solaris_x86.hpp
+++ b/src/hotspot/os_cpu/solaris_x86/orderAccess_solaris_x86.hpp
@@ -54,4 +54,9 @@ inline void OrderAccess::fence() {
compiler_barrier();
}
+inline void OrderAccess::cross_modify_fence() {
+ int idx = 0;
+ __asm__ volatile ("cpuid " : "+a" (idx) : : "ebx", "ecx", "edx", "memory");
+}
+
#endif // OS_CPU_SOLARIS_X86_ORDERACCESS_SOLARIS_X86_HPP
diff --git a/src/hotspot/os_cpu/windows_x86/orderAccess_windows_x86.hpp b/src/hotspot/os_cpu/windows_x86/orderAccess_windows_x86.hpp
index 94c10e0b008..51d6cb98748 100644
--- a/src/hotspot/os_cpu/windows_x86/orderAccess_windows_x86.hpp
+++ b/src/hotspot/os_cpu/windows_x86/orderAccess_windows_x86.hpp
@@ -69,6 +69,11 @@ inline void OrderAccess::fence() {
compiler_barrier();
}
+inline void OrderAccess::cross_modify_fence() {
+ int regs[4];
+ __cpuid(regs, 0);
+}
+
#ifndef AMD64
template<>
struct OrderAccess::PlatformOrderedStore<1, RELEASE_X_FENCE>
diff --git a/src/hotspot/os_cpu/windows_x86/os_windows_x86.cpp b/src/hotspot/os_cpu/windows_x86/os_windows_x86.cpp
index 07d2ff2b971..cbfec96405a 100644
--- a/src/hotspot/os_cpu/windows_x86/os_windows_x86.cpp
+++ b/src/hotspot/os_cpu/windows_x86/os_windows_x86.cpp
@@ -465,6 +465,9 @@ frame os::get_sender_for_C_frame(frame* fr) {
}
#ifndef AMD64
+// Ignore "C4172: returning address of local variable or temporary" on 32bit
+PRAGMA_DIAG_PUSH
+PRAGMA_DISABLE_MSVC_WARNING(4172)
// Returns an estimate of the current stack pointer. Result must be guaranteed
// to point into the calling threads stack, and be no lower than the current
// stack pointer.
@@ -473,6 +476,7 @@ address os::current_stack_pointer() {
address sp = (address)&dummy;
return sp;
}
+PRAGMA_DIAG_POP
#else
// Returns the current stack pointer. Accurate value needed for
// os::verify_stack_alignment().
diff --git a/src/hotspot/share/aot/aotCompiledMethod.hpp b/src/hotspot/share/aot/aotCompiledMethod.hpp
index c958e1d4e9d..2cc48a082a8 100644
--- a/src/hotspot/share/aot/aotCompiledMethod.hpp
+++ b/src/hotspot/share/aot/aotCompiledMethod.hpp
@@ -206,8 +206,6 @@ private:
// AOT compiled methods do not get into zombie state
virtual bool can_convert_to_zombie() { return false; }
- // Evol dependent methods already marked.
- virtual bool is_evol_dependent() { return false; }
virtual bool is_dependent_on_method(Method* dependee) { return true; }
virtual void clear_inline_caches();
diff --git a/src/hotspot/share/ci/ciReplay.cpp b/src/hotspot/share/ci/ciReplay.cpp
index cb29264d6a8..ce8fce60e80 100644
--- a/src/hotspot/share/ci/ciReplay.cpp
+++ b/src/hotspot/share/ci/ciReplay.cpp
@@ -40,6 +40,7 @@
#include "runtime/handles.inline.hpp"
#include "utilities/copy.hpp"
#include "utilities/macros.hpp"
+#include "utilities/utf8.hpp"
#ifndef PRODUCT
diff --git a/src/hotspot/share/classfile/classFileParser.cpp b/src/hotspot/share/classfile/classFileParser.cpp
index 9a778df0a60..95278447dfc 100644
--- a/src/hotspot/share/classfile/classFileParser.cpp
+++ b/src/hotspot/share/classfile/classFileParser.cpp
@@ -32,6 +32,7 @@
#include "classfile/dictionary.hpp"
#include "classfile/javaClasses.inline.hpp"
#include "classfile/moduleEntry.hpp"
+#include "classfile/packageEntry.hpp"
#include "classfile/symbolTable.hpp"
#include "classfile/systemDictionary.hpp"
#include "classfile/verificationType.hpp"
@@ -77,6 +78,8 @@
#include "utilities/macros.hpp"
#include "utilities/ostream.hpp"
#include "utilities/resourceHash.hpp"
+#include "utilities/utf8.hpp"
+
#if INCLUDE_CDS
#include "classfile/systemDictionaryShared.hpp"
#endif
@@ -312,7 +315,7 @@ void ClassFileParser::parse_constant_pool_entries(const ClassFileStream* const s
const char* const str = java_lang_String::as_utf8_string(patch());
// (could use java_lang_String::as_symbol instead, but might as well batch them)
utf8_buffer = (const u1*) str;
- utf8_length = (int) strlen(str);
+ utf8_length = (u2) strlen(str);
}
unsigned int hash;
@@ -6113,7 +6116,7 @@ void ClassFileParser::parse_stream(const ClassFileStream* const stream,
// For the boot and platform class loaders, skip classes that are not found in the
// java runtime image, such as those found in the --patch-module entries.
// These classes can't be loaded from the archive during runtime.
- if (!ClassLoader::is_modules_image(stream->source()) && strncmp(stream->source(), "jrt:", 4) != 0) {
+ if (!stream->from_boot_loader_modules_image() && strncmp(stream->source(), "jrt:", 4) != 0) {
skip = true;
}
diff --git a/src/hotspot/share/classfile/classFileStream.cpp b/src/hotspot/share/classfile/classFileStream.cpp
index 51e202c2d40..6a625e5350c 100644
--- a/src/hotspot/share/classfile/classFileStream.cpp
+++ b/src/hotspot/share/classfile/classFileStream.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2019, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -38,12 +38,14 @@ void ClassFileStream::truncated_file_error(TRAPS) const {
ClassFileStream::ClassFileStream(const u1* buffer,
int length,
const char* source,
- bool verify_stream) :
+ bool verify_stream,
+ bool from_boot_loader_modules_image) :
_buffer_start(buffer),
_buffer_end(buffer + length),
_current(buffer),
_source(source),
- _need_verify(verify_stream) {}
+ _need_verify(verify_stream),
+ _from_boot_loader_modules_image(from_boot_loader_modules_image) {}
const u1* ClassFileStream::clone_buffer() const {
u1* const new_buffer_start = NEW_RESOURCE_ARRAY(u1, length());
@@ -69,7 +71,8 @@ const ClassFileStream* ClassFileStream::clone() const {
return new ClassFileStream(new_buffer_start,
length(),
clone_source(),
- need_verify());
+ need_verify(),
+ from_boot_loader_modules_image());
}
uint64_t ClassFileStream::compute_fingerprint() const {
diff --git a/src/hotspot/share/classfile/classFileStream.hpp b/src/hotspot/share/classfile/classFileStream.hpp
index 5d7cd41a301..55bcf082940 100644
--- a/src/hotspot/share/classfile/classFileStream.hpp
+++ b/src/hotspot/share/classfile/classFileStream.hpp
@@ -44,7 +44,7 @@ class ClassFileStream: public ResourceObj {
mutable const u1* _current; // Current buffer position
const char* const _source; // Source of stream (directory name, ZIP/JAR archive name)
bool _need_verify; // True if verification is on for the class file
-
+ bool _from_boot_loader_modules_image; // True if this was created by ClassPathImageEntry.
void truncated_file_error(TRAPS) const ;
protected:
@@ -57,7 +57,8 @@ class ClassFileStream: public ResourceObj {
ClassFileStream(const u1* buffer,
int length,
const char* source,
- bool verify_stream = verify); // to be verified by default
+ bool verify_stream = verify, // to be verified by default
+ bool from_boot_loader_modules_image = false);
virtual const ClassFileStream* clone() const;
@@ -77,6 +78,7 @@ class ClassFileStream: public ResourceObj {
const char* source() const { return _source; }
bool need_verify() const { return _need_verify; }
void set_verify(bool flag) { _need_verify = flag; }
+ bool from_boot_loader_modules_image() const { return _from_boot_loader_modules_image; }
void check_truncated_file(bool b, TRAPS) const {
if (b) {
diff --git a/src/hotspot/share/classfile/classLoader.cpp b/src/hotspot/share/classfile/classLoader.cpp
index 099d8ee3a66..7ead766bd2f 100644
--- a/src/hotspot/share/classfile/classLoader.cpp
+++ b/src/hotspot/share/classfile/classLoader.cpp
@@ -361,6 +361,8 @@ void ClassPathZipEntry::contents_do(void f(const char* name, void* context), voi
}
}
+DEBUG_ONLY(ClassPathImageEntry* ClassPathImageEntry::_singleton = NULL;)
+
void ClassPathImageEntry::close_jimage() {
if (_jimage != NULL) {
(*JImageClose)(_jimage);
@@ -373,12 +375,17 @@ ClassPathImageEntry::ClassPathImageEntry(JImageFile* jimage, const char* name) :
_jimage(jimage) {
guarantee(jimage != NULL, "jimage file is null");
guarantee(name != NULL, "jimage file name is null");
+ assert(_singleton == NULL, "VM supports only one jimage");
+ DEBUG_ONLY(_singleton = this);
size_t len = strlen(name) + 1;
_name = NEW_C_HEAP_ARRAY(const char, len, mtClass);
strncpy((char *)_name, name, len);
}
ClassPathImageEntry::~ClassPathImageEntry() {
+ assert(_singleton == this, "must be");
+ DEBUG_ONLY(_singleton = NULL);
+
if (_name != NULL) {
FREE_C_HEAP_ARRAY(const char, _name);
_name = NULL;
@@ -389,6 +396,10 @@ ClassPathImageEntry::~ClassPathImageEntry() {
}
}
+ClassFileStream* ClassPathImageEntry::open_stream(const char* name, TRAPS) {
+ return open_stream_for_loader(name, ClassLoaderData::the_null_class_loader_data(), THREAD);
+}
+
// For a class in a named module, look it up in the jimage file using this syntax:
// ///
//
@@ -396,7 +407,7 @@ ClassPathImageEntry::~ClassPathImageEntry() {
// 1. There are no unnamed modules in the jimage file.
// 2. A package is in at most one module in the jimage file.
//
-ClassFileStream* ClassPathImageEntry::open_stream(const char* name, TRAPS) {
+ClassFileStream* ClassPathImageEntry::open_stream_for_loader(const char* name, ClassLoaderData* loader_data, TRAPS) {
jlong size;
JImageLocationRef location = (*JImageFindResource)(_jimage, "", get_jimage_version_string(), name, &size);
@@ -407,20 +418,8 @@ ClassFileStream* ClassPathImageEntry::open_stream(const char* name, TRAPS) {
if (pkg_name != NULL) {
if (!Universe::is_module_initialized()) {
location = (*JImageFindResource)(_jimage, JAVA_BASE_NAME, get_jimage_version_string(), name, &size);
-#if INCLUDE_CDS
- // CDS uses the boot class loader to load classes whose packages are in
- // modules defined for other class loaders. So, for now, get their module
- // names from the "modules" jimage file.
- if (DumpSharedSpaces && location == 0) {
- const char* module_name = (*JImagePackageToModule)(_jimage, pkg_name);
- if (module_name != NULL) {
- location = (*JImageFindResource)(_jimage, module_name, get_jimage_version_string(), name, &size);
- }
- }
-#endif
-
} else {
- PackageEntry* package_entry = ClassLoader::get_package_entry(name, ClassLoaderData::the_null_class_loader_data(), CHECK_NULL);
+ PackageEntry* package_entry = ClassLoader::get_package_entry(name, loader_data, CHECK_NULL);
if (package_entry != NULL) {
ResourceMark rm;
// Get the module name
@@ -442,10 +441,12 @@ ClassFileStream* ClassPathImageEntry::open_stream(const char* name, TRAPS) {
char* data = NEW_RESOURCE_ARRAY(char, size);
(*JImageGetResource)(_jimage, location, data, size);
// Resource allocated
+ assert(this == (ClassPathImageEntry*)ClassLoader::get_jrt_entry(), "must be");
return new ClassFileStream((u1*)data,
(int)size,
_name,
- ClassFileStream::verify);
+ ClassFileStream::verify,
+ true); // from_boot_loader_modules_image
}
return NULL;
@@ -459,7 +460,9 @@ JImageLocationRef ClassLoader::jimage_find_resource(JImageFile* jf,
}
bool ClassPathImageEntry::is_modules_image() const {
- return ClassLoader::is_modules_image(name());
+ assert(this == _singleton, "VM supports a single jimage");
+ assert(this == (ClassPathImageEntry*)ClassLoader::get_jrt_entry(), "must be used for jrt entry");
+ return true;
}
#if INCLUDE_CDS
@@ -737,8 +740,8 @@ void ClassLoader::setup_boot_search_path(const char *class_path) {
// Check for a jimage
if (Arguments::has_jimage()) {
assert(_jrt_entry == NULL, "should not setup bootstrap class search path twice");
- assert(new_entry != NULL && new_entry->is_modules_image(), "No java runtime image present");
_jrt_entry = new_entry;
+ assert(new_entry != NULL && new_entry->is_modules_image(), "No java runtime image present");
assert(_jrt_entry->jimage() != NULL, "No java runtime image");
}
} else {
@@ -1499,7 +1502,7 @@ void ClassLoader::record_result(InstanceKlass* ik, const ClassFileStream* stream
}
// for index 0 and the stream->source() is the modules image or has the jrt: protocol.
// The class must be from the runtime modules image.
- if (i == 0 && (is_modules_image(src) || string_starts_with(src, "jrt:"))) {
+ if (i == 0 && (stream->from_boot_loader_modules_image() || string_starts_with(src, "jrt:"))) {
classpath_index = i;
break;
}
@@ -1515,7 +1518,7 @@ void ClassLoader::record_result(InstanceKlass* ik, const ClassFileStream* stream
// The shared path table is set up after module system initialization.
// The path table contains no entry before that. Any classes loaded prior
// to the setup of the shared path table must be from the modules image.
- assert(is_modules_image(src), "stream must be from modules image");
+ assert(stream->from_boot_loader_modules_image(), "stream must be loaded by boot loader from modules image");
assert(FileMapInfo::get_number_of_shared_paths() == 0, "shared path table must not have been setup");
classpath_index = 0;
}
diff --git a/src/hotspot/share/classfile/classLoader.hpp b/src/hotspot/share/classfile/classLoader.hpp
index 60f6135a523..f0911839675 100644
--- a/src/hotspot/share/classfile/classLoader.hpp
+++ b/src/hotspot/share/classfile/classLoader.hpp
@@ -61,6 +61,10 @@ public:
// Attempt to locate file_name through this class path entry.
// Returns a class file parsing stream if successfull.
virtual ClassFileStream* open_stream(const char* name, TRAPS) = 0;
+ // Open the stream for a specific class loader
+ virtual ClassFileStream* open_stream_for_loader(const char* name, ClassLoaderData* loader_data, TRAPS) {
+ return open_stream(name, THREAD);
+ }
};
class ClassPathDirEntry: public ClassPathEntry {
@@ -114,6 +118,7 @@ class ClassPathImageEntry: public ClassPathEntry {
private:
JImageFile* _jimage;
const char* _name;
+ DEBUG_ONLY(static ClassPathImageEntry* _singleton;)
public:
bool is_modules_image() const;
bool is_jar_file() const { return false; }
@@ -124,6 +129,7 @@ public:
ClassPathImageEntry(JImageFile* jimage, const char* name);
virtual ~ClassPathImageEntry();
ClassFileStream* open_stream(const char* name, TRAPS);
+ ClassFileStream* open_stream_for_loader(const char* name, ClassLoaderData* loader_data, TRAPS);
};
// ModuleClassPathList contains a linked list of ClassPathEntry's
@@ -439,8 +445,6 @@ class ClassLoader: AllStatic {
// distinguish from a class_name with no package name, as both cases have a NULL return value
static const char* package_from_name(const char* const class_name, bool* bad_class_name = NULL);
- static bool is_modules_image(const char* name) { return string_ends_with(name, MODULES_IMAGE_NAME); }
-
// Debugging
static void verify() PRODUCT_RETURN;
};
diff --git a/src/hotspot/share/classfile/classLoaderData.cpp b/src/hotspot/share/classfile/classLoaderData.cpp
index c177c48b3ef..abcd016e536 100644
--- a/src/hotspot/share/classfile/classLoaderData.cpp
+++ b/src/hotspot/share/classfile/classLoaderData.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2012, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2019, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -288,7 +288,7 @@ bool ClassLoaderData::try_claim(int claim) {
// it is being defined, therefore _keep_alive is not volatile or atomic.
void ClassLoaderData::inc_keep_alive() {
if (is_unsafe_anonymous()) {
- assert(_keep_alive >= 0, "Invalid keep alive increment count");
+ assert(_keep_alive > 0, "Invalid keep alive increment count");
_keep_alive++;
}
}
diff --git a/src/hotspot/share/classfile/classLoaderDataGraph.cpp b/src/hotspot/share/classfile/classLoaderDataGraph.cpp
index 02b8620d838..8575e987156 100644
--- a/src/hotspot/share/classfile/classLoaderDataGraph.cpp
+++ b/src/hotspot/share/classfile/classLoaderDataGraph.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2018, 2019, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -163,7 +163,7 @@ void ClassLoaderDataGraph::walk_metadata_and_clean_metaspaces() {
// TODO: have redefinition clean old methods out of the code cache. They still exist in some places.
bool walk_all_metadata = InstanceKlass::has_previous_versions_and_reset();
- MetadataOnStackMark md_on_stack(walk_all_metadata);
+ MetadataOnStackMark md_on_stack(walk_all_metadata, /*redefinition_walk*/false);
clean_deallocate_lists(walk_all_metadata);
}
diff --git a/src/hotspot/share/classfile/javaClasses.cpp b/src/hotspot/share/classfile/javaClasses.cpp
index 66263bc387e..d76751f1bef 100644
--- a/src/hotspot/share/classfile/javaClasses.cpp
+++ b/src/hotspot/share/classfile/javaClasses.cpp
@@ -65,6 +65,7 @@
#include "runtime/vframe.inline.hpp"
#include "utilities/align.hpp"
#include "utilities/preserveException.hpp"
+#include "utilities/utf8.hpp"
#if INCLUDE_JVMCI
#include "jvmci/jvmciJavaClasses.hpp"
#endif
diff --git a/src/hotspot/share/classfile/javaClasses.hpp b/src/hotspot/share/classfile/javaClasses.hpp
index d57b4b1ab70..df164ce4f9c 100644
--- a/src/hotspot/share/classfile/javaClasses.hpp
+++ b/src/hotspot/share/classfile/javaClasses.hpp
@@ -29,7 +29,6 @@
#include "jvmtifiles/jvmti.h"
#include "oops/oop.hpp"
#include "runtime/os.hpp"
-#include "utilities/utf8.hpp"
// Interface for manipulating the basic Java classes.
//
diff --git a/src/hotspot/share/classfile/klassFactory.cpp b/src/hotspot/share/classfile/klassFactory.cpp
index 50a3d9d1b66..b80802e85f4 100644
--- a/src/hotspot/share/classfile/klassFactory.cpp
+++ b/src/hotspot/share/classfile/klassFactory.cpp
@@ -58,7 +58,7 @@ InstanceKlass* KlassFactory::check_shared_class_file_load_hook(
// Post the CFLH
JvmtiCachedClassFileData* cached_class_file = NULL;
if (cfs == NULL) {
- cfs = FileMapInfo::open_stream_for_jvmti(ik, CHECK_NULL);
+ cfs = FileMapInfo::open_stream_for_jvmti(ik, class_loader, CHECK_NULL);
}
unsigned char* ptr = (unsigned char*)cfs->buffer();
unsigned char* end_ptr = ptr + cfs->length();
diff --git a/src/hotspot/share/classfile/metadataOnStackMark.cpp b/src/hotspot/share/classfile/metadataOnStackMark.cpp
index 7e7d36d8b11..05555906d5f 100644
--- a/src/hotspot/share/classfile/metadataOnStackMark.cpp
+++ b/src/hotspot/share/classfile/metadataOnStackMark.cpp
@@ -50,18 +50,25 @@ class MetadataOnStackClosure : public MetadataClosure {
// it. Class unloading only deletes in-error class files, methods created by
// the relocator and dummy constant pools. None of these appear anywhere except
// in metadata Handles.
-MetadataOnStackMark::MetadataOnStackMark(bool redefinition_walk) {
+MetadataOnStackMark::MetadataOnStackMark(bool walk_all_metadata, bool redefinition_walk) {
assert(SafepointSynchronize::is_at_safepoint(), "sanity check");
assert(_used_buffers == NULL, "sanity check");
assert(!_is_active, "MetadataOnStackMarks do not nest");
+ assert(!redefinition_walk || walk_all_metadata,
+ "walk_all_metadata must be true for redefinition_walk");
NOT_PRODUCT(_is_active = true;)
Threads::metadata_handles_do(Metadata::mark_on_stack);
- if (redefinition_walk) {
+ if (walk_all_metadata) {
MetadataOnStackClosure md_on_stack;
Threads::metadata_do(&md_on_stack);
- CodeCache::metadata_do(&md_on_stack);
+ if (redefinition_walk) {
+ // We have to walk the whole code cache during redefinition.
+ CodeCache::metadata_do(&md_on_stack);
+ } else {
+ CodeCache::old_nmethods_do(&md_on_stack);
+ }
CompileBroker::mark_on_stack();
JvmtiCurrentBreakpoints::metadata_do(Metadata::mark_on_stack);
ThreadService::metadata_do(Metadata::mark_on_stack);
diff --git a/src/hotspot/share/classfile/metadataOnStackMark.hpp b/src/hotspot/share/classfile/metadataOnStackMark.hpp
index ba00839f832..f6da74a0826 100644
--- a/src/hotspot/share/classfile/metadataOnStackMark.hpp
+++ b/src/hotspot/share/classfile/metadataOnStackMark.hpp
@@ -48,7 +48,7 @@ class MetadataOnStackMark : public StackObj {
static void retire_buffer(MetadataOnStackBuffer* buffer);
public:
- MetadataOnStackMark(bool redefinition_walk);
+ MetadataOnStackMark(bool walk_all_metadata, bool redefinition_walk);
~MetadataOnStackMark();
static void record(Metadata* m);
diff --git a/src/hotspot/share/classfile/moduleEntry.cpp b/src/hotspot/share/classfile/moduleEntry.cpp
index f2d3891b612..a2fc8270d63 100644
--- a/src/hotspot/share/classfile/moduleEntry.cpp
+++ b/src/hotspot/share/classfile/moduleEntry.cpp
@@ -24,6 +24,7 @@
#include "precompiled.hpp"
#include "jni.h"
+#include "classfile/classLoader.hpp"
#include "classfile/classLoaderData.inline.hpp"
#include "classfile/javaClasses.inline.hpp"
#include "classfile/moduleEntry.hpp"
diff --git a/src/hotspot/share/classfile/stringTable.cpp b/src/hotspot/share/classfile/stringTable.cpp
index c0356b8db59..dd38a149673 100644
--- a/src/hotspot/share/classfile/stringTable.cpp
+++ b/src/hotspot/share/classfile/stringTable.cpp
@@ -52,6 +52,7 @@
#include "utilities/concurrentHashTable.inline.hpp"
#include "utilities/concurrentHashTableTasks.inline.hpp"
#include "utilities/macros.hpp"
+#include "utilities/utf8.hpp"
// We prefer short chains of avg 2
const double PREF_AVG_LIST_LEN = 2.0;
diff --git a/src/hotspot/share/classfile/symbolTable.cpp b/src/hotspot/share/classfile/symbolTable.cpp
index 9876a017416..ce536c8f9ca 100644
--- a/src/hotspot/share/classfile/symbolTable.cpp
+++ b/src/hotspot/share/classfile/symbolTable.cpp
@@ -38,6 +38,7 @@
#include "services/diagnosticCommand.hpp"
#include "utilities/concurrentHashTable.inline.hpp"
#include "utilities/concurrentHashTableTasks.inline.hpp"
+#include "utilities/utf8.hpp"
// We used to not resize at all, so let's be conservative
// and not set it too short before we decide to resize,
diff --git a/src/hotspot/share/classfile/systemDictionary.hpp b/src/hotspot/share/classfile/systemDictionary.hpp
index a7206fadfa4..e62752fe1ed 100644
--- a/src/hotspot/share/classfile/systemDictionary.hpp
+++ b/src/hotspot/share/classfile/systemDictionary.hpp
@@ -25,11 +25,12 @@
#ifndef SHARE_CLASSFILE_SYSTEMDICTIONARY_HPP
#define SHARE_CLASSFILE_SYSTEMDICTIONARY_HPP
-#include "classfile/classLoader.hpp"
+#include "classfile/classLoaderData.hpp"
#include "jvmci/systemDictionary_jvmci.hpp"
#include "oops/objArrayOop.hpp"
#include "oops/symbol.hpp"
#include "runtime/java.hpp"
+#include "runtime/mutexLocker.hpp"
#include "runtime/reflectionUtils.hpp"
#include "runtime/signature.hpp"
#include "utilities/hashtable.hpp"
diff --git a/src/hotspot/share/classfile/systemDictionaryShared.hpp b/src/hotspot/share/classfile/systemDictionaryShared.hpp
index eda58447c32..427aa283037 100644
--- a/src/hotspot/share/classfile/systemDictionaryShared.hpp
+++ b/src/hotspot/share/classfile/systemDictionaryShared.hpp
@@ -27,6 +27,7 @@
#include "oops/klass.hpp"
#include "classfile/dictionary.hpp"
+#include "classfile/packageEntry.hpp"
#include "classfile/systemDictionary.hpp"
#include "memory/filemap.hpp"
diff --git a/src/hotspot/share/classfile/verifier.cpp b/src/hotspot/share/classfile/verifier.cpp
index 69897151f3b..ad9644b48b8 100644
--- a/src/hotspot/share/classfile/verifier.cpp
+++ b/src/hotspot/share/classfile/verifier.cpp
@@ -25,6 +25,7 @@
#include "precompiled.hpp"
#include "jvm.h"
#include "classfile/classFileStream.hpp"
+#include "classfile/classLoader.hpp"
#include "classfile/javaClasses.hpp"
#include "classfile/stackMapTable.hpp"
#include "classfile/stackMapFrame.hpp"
@@ -574,7 +575,7 @@ void ErrorContext::stackmap_details(outputStream* ss, const Method* method) cons
ClassVerifier::ClassVerifier(
InstanceKlass* klass, TRAPS)
: _thread(THREAD), _previous_symbol(NULL), _symbols(NULL), _exception_type(NULL),
- _message(NULL), _klass(klass) {
+ _message(NULL), _method_signatures_table(NULL), _klass(klass) {
_this_type = VerificationType::reference_type(klass->name());
}
@@ -601,6 +602,13 @@ TypeOrigin ClassVerifier::ref_ctx(const char* sig, TRAPS) {
void ClassVerifier::verify_class(TRAPS) {
log_info(verification)("Verifying class %s with new format", _klass->external_name());
+ // Either verifying both local and remote classes or just remote classes.
+ assert(BytecodeVerificationRemote, "Should not be here");
+
+ // Create hash table containing method signatures.
+ method_signatures_table_type method_signatures_table;
+ set_method_signatures_table(&method_signatures_table);
+
Array* methods = _klass->methods();
int num_methods = methods->length();
@@ -625,6 +633,55 @@ void ClassVerifier::verify_class(TRAPS) {
}
}
+// Translate the signature entries into verification types and save them in
+// the growable array. Also, save the count of arguments.
+void ClassVerifier::translate_signature(Symbol* const method_sig,
+ sig_as_verification_types* sig_verif_types,
+ TRAPS) {
+ SignatureStream sig_stream(method_sig);
+ VerificationType sig_type[2];
+ int sig_i = 0;
+ GrowableArray* verif_types = sig_verif_types->sig_verif_types();
+
+ // Translate the signature arguments into verification types.
+ while (!sig_stream.at_return_type()) {
+ int n = change_sig_to_verificationType(&sig_stream, sig_type, CHECK_VERIFY(this));
+ assert(n <= 2, "Unexpected signature type");
+
+ // Store verification type(s). Longs and Doubles each have two verificationTypes.
+ for (int x = 0; x < n; x++) {
+ verif_types->push(sig_type[x]);
+ }
+ sig_i += n;
+ sig_stream.next();
+ }
+
+ // Set final arg count, not including the return type. The final arg count will
+ // be compared with sig_verify_types' length to see if there is a return type.
+ sig_verif_types->set_num_args(sig_i);
+
+ // Store verification type(s) for the return type, if there is one.
+ if (sig_stream.type() != T_VOID) {
+ int n = change_sig_to_verificationType(&sig_stream, sig_type, CHECK_VERIFY(this));
+ assert(n <= 2, "Unexpected signature return type");
+ for (int y = 0; y < n; y++) {
+ verif_types->push(sig_type[y]);
+ }
+ }
+}
+
+void ClassVerifier::create_method_sig_entry(sig_as_verification_types* sig_verif_types,
+ int sig_index, TRAPS) {
+ // Translate the signature into verification types.
+ ConstantPool* cp = _klass->constants();
+ Symbol* const method_sig = cp->symbol_at(sig_index);
+ translate_signature(method_sig, sig_verif_types, CHECK_VERIFY(this));
+
+ // Add the list of this signature's verification types to the table.
+ bool is_unique = method_signatures_table()->put(sig_index, sig_verif_types);
+ assert(is_unique, "Duplicate entries in method_signature_table");
+}
+
void ClassVerifier::verify_method(const methodHandle& m, TRAPS) {
HandleMark hm(THREAD);
_method = m; // initialize _method
@@ -2734,44 +2791,28 @@ void ClassVerifier::verify_invoke_instructions(
ref_class_type = cp_ref_index_to_type(index, cp, CHECK_VERIFY(this));
}
- // For a small signature length, we just allocate 128 bytes instead
- // of parsing the signature once to find its size.
- // -3 is for '(', ')' and return descriptor; multiply by 2 is for
- // longs/doubles to be consertive.
assert(sizeof(VerificationType) == sizeof(uintptr_t),
"buffer type must match VerificationType size");
- uintptr_t on_stack_sig_types_buffer[128];
- // If we make a VerificationType[128] array directly, the compiler calls
- // to the c-runtime library to do the allocation instead of just
- // stack allocating it. Plus it would run constructors. This shows up
- // in performance profiles.
- VerificationType* sig_types;
- int size = (method_sig->utf8_length() - 3) * 2;
- if (size > 128) {
- // Long and double occupies two slots here.
- ArgumentSizeComputer size_it(method_sig);
- size = size_it.size();
- sig_types = NEW_RESOURCE_ARRAY_IN_THREAD(THREAD, VerificationType, size);
- } else{
- sig_types = (VerificationType*)on_stack_sig_types_buffer;
- }
- SignatureStream sig_stream(method_sig);
- int sig_i = 0;
- while (!sig_stream.at_return_type()) {
- sig_i += change_sig_to_verificationType(
- &sig_stream, &sig_types[sig_i], CHECK_VERIFY(this));
- sig_stream.next();
- }
- int nargs = sig_i;
+ // Get the UTF8 index for this signature.
+ int sig_index = cp->signature_ref_index_at(cp->name_and_type_ref_index_at(index));
-#ifdef ASSERT
- {
- ArgumentSizeComputer size_it(method_sig);
- assert(nargs == size_it.size(), "Argument sizes do not match");
- assert(nargs <= (method_sig->utf8_length() - 3) * 2, "estimate of max size isn't conservative enough");
+ // Get the signature's verification types.
+ sig_as_verification_types* mth_sig_verif_types;
+ sig_as_verification_types** mth_sig_verif_types_ptr = method_signatures_table()->get(sig_index);
+ if (mth_sig_verif_types_ptr != NULL) {
+ // Found the entry for the signature's verification types in the hash table.
+ mth_sig_verif_types = *mth_sig_verif_types_ptr;
+ assert(mth_sig_verif_types != NULL, "Unexpected NULL sig_as_verification_types value");
+ } else {
+ // Not found, add the entry to the table.
+ GrowableArray* verif_types = new GrowableArray(10);
+ mth_sig_verif_types = new sig_as_verification_types(verif_types);
+ create_method_sig_entry(mth_sig_verif_types, sig_index, CHECK_VERIFY(this));
}
-#endif
+
+ // Get the number of arguments for this signature.
+ int nargs = mth_sig_verif_types->num_args();
// Check instruction operands
u2 bci = bcs->bci();
@@ -2844,10 +2885,16 @@ void ClassVerifier::verify_invoke_instructions(
}
}
+
+ // Get the verification types for the method's arguments.
+ GrowableArray* sig_verif_types = mth_sig_verif_types->sig_verif_types();
+ assert(sig_verif_types != NULL, "Missing signature's array of verification types");
// Match method descriptor with operand stack
- for (int i = nargs - 1; i >= 0; i--) { // Run backwards
- current_frame->pop_stack(sig_types[i], CHECK_VERIFY(this));
+ // The arguments are on the stack in descending order.
+ for (int i = nargs - 1; i >= 0; i--) { // Run backwards
+ current_frame->pop_stack(sig_verif_types->at(i), CHECK_VERIFY(this));
}
+
// Check objectref on operand stack
if (opcode != Bytecodes::_invokestatic &&
opcode != Bytecodes::_invokedynamic) {
@@ -2919,7 +2966,8 @@ void ClassVerifier::verify_invoke_instructions(
}
}
// Push the result type.
- if (sig_stream.type() != T_VOID) {
+ int sig_verif_types_len = sig_verif_types->length();
+ if (sig_verif_types_len > nargs) { // There's a return type
if (method_name == vmSymbols::object_initializer_name()) {
// method must have a void return type
/* Unreachable? Class file parser verifies that methods with '<' have
@@ -2928,11 +2976,13 @@ void ClassVerifier::verify_invoke_instructions(
"Return type must be void in method");
return;
}
- VerificationType return_type[2];
- int n = change_sig_to_verificationType(
- &sig_stream, return_type, CHECK_VERIFY(this));
- for (int i = 0; i < n; i++) {
- current_frame->push_stack(return_type[i], CHECK_VERIFY(this)); // push types backwards
+
+ assert(sig_verif_types_len <= nargs + 2,
+ "Signature verification types array return type is bogus");
+ for (int i = nargs; i < sig_verif_types_len; i++) {
+ assert(i == nargs || sig_verif_types->at(i).is_long2() ||
+ sig_verif_types->at(i).is_double2(), "Unexpected return verificationType");
+ current_frame->push_stack(sig_verif_types->at(i), CHECK_VERIFY(this));
}
}
}
diff --git a/src/hotspot/share/classfile/verifier.hpp b/src/hotspot/share/classfile/verifier.hpp
index 1f565e5c880..c0696ca0821 100644
--- a/src/hotspot/share/classfile/verifier.hpp
+++ b/src/hotspot/share/classfile/verifier.hpp
@@ -31,6 +31,7 @@
#include "runtime/handles.hpp"
#include "utilities/exceptions.hpp"
#include "utilities/growableArray.hpp"
+#include "utilities/resourceHash.hpp"
// The verifier class
class Verifier : AllStatic {
@@ -246,6 +247,33 @@ class ErrorContext {
void stackmap_details(outputStream* ss, const Method* method) const;
};
+class sig_as_verification_types : public ResourceObj {
+ private:
+ int _num_args; // Number of arguments, not including return type.
+ GrowableArray* _sig_verif_types;
+
+ public:
+
+ sig_as_verification_types(GrowableArray* sig_verif_types) :
+ _num_args(0), _sig_verif_types(sig_verif_types) {
+ }
+
+ int num_args() const { return _num_args; }
+ void set_num_args(int num_args) { _num_args = num_args; }
+
+ GrowableArray* sig_verif_types() { return _sig_verif_types; }
+ void set_sig_verif_types(GrowableArray* sig_verif_types) {
+ _sig_verif_types = sig_verif_types;
+ }
+
+};
+
+// This hashtable is indexed by the Utf8 constant pool indexes pointed to
+// by constant pool (Interface)Method_refs' NameAndType signature entries.
+typedef ResourceHashtable, primitive_equals, 1007>
+ method_signatures_table_type;
+
// A new instance of this class is created for each class being verified
class ClassVerifier : public StackObj {
private:
@@ -257,6 +285,8 @@ class ClassVerifier : public StackObj {
Symbol* _exception_type;
char* _message;
+ method_signatures_table_type* _method_signatures_table;
+
ErrorContext _error_context; // contains information about an error
void verify_method(const methodHandle& method, TRAPS);
@@ -383,6 +413,13 @@ class ClassVerifier : public StackObj {
// the message_buffer will be filled in with the exception message.
void verify_class(TRAPS);
+ // Translates method signature entries into verificationTypes and saves them
+ // in the growable array.
+ void translate_signature(Symbol* const method_sig, sig_as_verification_types* sig_verif_types, TRAPS);
+
+ // Initializes a sig_as_verification_types entry and puts it in the hash table.
+ void create_method_sig_entry(sig_as_verification_types* sig_verif_types, int sig_index, TRAPS);
+
// Return status modes
Symbol* result() const { return _exception_type; }
bool has_error() const { return result() != NULL; }
@@ -400,6 +437,14 @@ class ClassVerifier : public StackObj {
Klass* load_class(Symbol* name, TRAPS);
+ method_signatures_table_type* method_signatures_table() const {
+ return _method_signatures_table;
+ }
+
+ void set_method_signatures_table(method_signatures_table_type* method_signatures_table) {
+ _method_signatures_table = method_signatures_table;
+ }
+
int change_sig_to_verificationType(
SignatureStream* sig_type, VerificationType* inference_type, TRAPS);
diff --git a/src/hotspot/share/classfile/vmSymbols.hpp b/src/hotspot/share/classfile/vmSymbols.hpp
index da923d99dc4..c6d4c7fdb02 100644
--- a/src/hotspot/share/classfile/vmSymbols.hpp
+++ b/src/hotspot/share/classfile/vmSymbols.hpp
@@ -25,7 +25,6 @@
#ifndef SHARE_CLASSFILE_VMSYMBOLS_HPP
#define SHARE_CLASSFILE_VMSYMBOLS_HPP
-#include "classfile/moduleEntry.hpp"
#include "jfr/support/jfrIntrinsics.hpp"
#include "jvmci/vmSymbols_jvmci.hpp"
#include "memory/iterator.hpp"
@@ -52,7 +51,7 @@
#define VM_SYMBOLS_DO(template, do_alias) \
/* commonly used class, package, module names */ \
- template(java_base, JAVA_BASE_NAME) \
+ template(java_base, "java.base") \
template(java_lang_System, "java/lang/System") \
template(java_lang_Object, "java/lang/Object") \
template(java_lang_Class, "java/lang/Class") \
diff --git a/src/hotspot/share/code/codeCache.cpp b/src/hotspot/share/code/codeCache.cpp
index 0056c789d5a..8d3395cdac4 100644
--- a/src/hotspot/share/code/codeCache.cpp
+++ b/src/hotspot/share/code/codeCache.cpp
@@ -1032,43 +1032,77 @@ bool CodeCache::is_far_target(address target) {
#endif
}
-// Just marks the methods in this class as needing deoptimization
-void CodeCache::mark_for_evol_deoptimization(InstanceKlass* dependee) {
- MutexLockerEx mu(CodeCache_lock, Mutex::_no_safepoint_check_flag);
+#ifdef INCLUDE_JVMTI
+// RedefineClasses support for unloading nmethods that are dependent on "old" methods.
+// We don't really expect this table to grow very large. If it does, it can become a hashtable.
+static GrowableArray* old_compiled_method_table = NULL;
- // Deoptimize all methods of the evolving class itself
- Array* old_methods = dependee->methods();
- for (int i = 0; i < old_methods->length(); i++) {
- ResourceMark rm;
- Method* old_method = old_methods->at(i);
- CompiledMethod* nm = old_method->code();
- if (nm != NULL) {
- nm->mark_for_deoptimization();
+static void add_to_old_table(CompiledMethod* c) {
+ if (old_compiled_method_table == NULL) {
+ old_compiled_method_table = new (ResourceObj::C_HEAP, mtCode) GrowableArray(100, true);
+ }
+ old_compiled_method_table->push(c);
+}
+
+static void reset_old_method_table() {
+ if (old_compiled_method_table != NULL) {
+ delete old_compiled_method_table;
+ old_compiled_method_table = NULL;
+ }
+}
+
+// Remove this method when zombied or unloaded.
+void CodeCache::unregister_old_nmethod(CompiledMethod* c) {
+ assert_locked_or_safepoint(CodeCache_lock);
+ if (old_compiled_method_table != NULL) {
+ int index = old_compiled_method_table->find(c);
+ if (index != -1) {
+ old_compiled_method_table->delete_at(index);
}
}
+}
+
+void CodeCache::old_nmethods_do(MetadataClosure* f) {
+ // Walk old method table and mark those on stack.
+ int length = 0;
+ if (old_compiled_method_table != NULL) {
+ length = old_compiled_method_table->length();
+ for (int i = 0; i < length; i++) {
+ old_compiled_method_table->at(i)->metadata_do(f);
+ }
+ }
+ log_debug(redefine, class, nmethod)("Walked %d nmethods for mark_on_stack", length);
+}
+
+// Just marks the methods in this class as needing deoptimization
+void CodeCache::mark_for_evol_deoptimization(InstanceKlass* dependee) {
+ assert(SafepointSynchronize::is_at_safepoint(), "Can only do this at a safepoint!");
// Mark dependent AOT nmethods, which are only found via the class redefined.
+ // TODO: add dependencies to aotCompiledMethod's metadata section so this isn't
+ // needed.
AOTLoader::mark_evol_dependent_methods(dependee);
}
+
// Walk compiled methods and mark dependent methods for deoptimization.
int CodeCache::mark_dependents_for_evol_deoptimization() {
+ assert(SafepointSynchronize::is_at_safepoint(), "Can only do this at a safepoint!");
+ // Each redefinition creates a new set of nmethods that have references to "old" Methods
+ // So delete old method table and create a new one.
+ reset_old_method_table();
+
int number_of_marked_CodeBlobs = 0;
CompiledMethodIterator iter(CompiledMethodIterator::only_alive_and_not_unloading);
while(iter.next()) {
CompiledMethod* nm = iter.method();
- if (nm->is_marked_for_deoptimization()) {
- // ...Already marked in the previous pass; count it here.
- // Also counts AOT compiled methods, already marked.
- number_of_marked_CodeBlobs++;
- } else if (nm->has_evol_metadata()) {
- ResourceMark rm;
+ // Walk all alive nmethods to check for old Methods.
+ // This includes methods whose inline caches point to old methods, so
+ // inline cache clearing is unnecessary.
+ if (nm->has_evol_metadata()) {
nm->mark_for_deoptimization();
+ add_to_old_table(nm);
number_of_marked_CodeBlobs++;
- } else {
- // Inline caches that refer to an nmethod are deoptimized already, because
- // the Method* is walked in the metadata section of the nmethod.
- assert(!nm->is_evol_dependent(), "should no longer be necessary");
}
}
@@ -1077,6 +1111,46 @@ int CodeCache::mark_dependents_for_evol_deoptimization() {
return number_of_marked_CodeBlobs;
}
+void CodeCache::mark_all_nmethods_for_evol_deoptimization() {
+ assert(SafepointSynchronize::is_at_safepoint(), "Can only do this at a safepoint!");
+ CompiledMethodIterator iter(CompiledMethodIterator::only_alive_and_not_unloading);
+ while(iter.next()) {
+ CompiledMethod* nm = iter.method();
+ if (!nm->method()->is_method_handle_intrinsic()) {
+ nm->mark_for_deoptimization();
+ if (nm->has_evol_metadata()) {
+ add_to_old_table(nm);
+ }
+ }
+ }
+}
+
+// Flushes compiled methods dependent on redefined classes, that have already been
+// marked for deoptimization.
+void CodeCache::flush_evol_dependents() {
+ assert(SafepointSynchronize::is_at_safepoint(), "Can only do this at a safepoint!");
+
+ // CodeCache can only be updated by a thread_in_VM and they will all be
+ // stopped during the safepoint so CodeCache will be safe to update without
+ // holding the CodeCache_lock.
+
+ // At least one nmethod has been marked for deoptimization
+
+ // All this already happens inside a VM_Operation, so we'll do all the work here.
+ // Stuff copied from VM_Deoptimize and modified slightly.
+
+ // We do not want any GCs to happen while we are in the middle of this VM operation
+ ResourceMark rm;
+ DeoptimizationMarker dm;
+
+ // Deoptimize all activations depending on marked nmethods
+ Deoptimization::deoptimize_dependents();
+
+ // Make the dependent methods not entrant
+ make_marked_nmethods_not_entrant();
+}
+#endif // INCLUDE_JVMTI
+
// Deoptimize all methods
void CodeCache::mark_all_nmethods_for_deoptimization() {
MutexLockerEx mu(CodeCache_lock, Mutex::_no_safepoint_check_flag);
@@ -1137,32 +1211,6 @@ void CodeCache::flush_dependents_on(InstanceKlass* dependee) {
}
}
-// Flushes compiled methods dependent on redefined classes, that have already been
-// marked for deoptimization.
-void CodeCache::flush_evol_dependents() {
- // --- Compile_lock is not held. However we are at a safepoint.
- assert_locked_or_safepoint(Compile_lock);
-
- // CodeCache can only be updated by a thread_in_VM and they will all be
- // stopped during the safepoint so CodeCache will be safe to update without
- // holding the CodeCache_lock.
-
- // At least one nmethod has been marked for deoptimization
-
- // All this already happens inside a VM_Operation, so we'll do all the work here.
- // Stuff copied from VM_Deoptimize and modified slightly.
-
- // We do not want any GCs to happen while we are in the middle of this VM operation
- ResourceMark rm;
- DeoptimizationMarker dm;
-
- // Deoptimize all activations depending on marked nmethods
- Deoptimization::deoptimize_dependents();
-
- // Make the dependent methods not entrant
- make_marked_nmethods_not_entrant();
-}
-
// Flushes compiled methods dependent on dependee
void CodeCache::flush_dependents_on_method(const methodHandle& m_h) {
// --- Compile_lock is not held. However we are at a safepoint.
diff --git a/src/hotspot/share/code/codeCache.hpp b/src/hotspot/share/code/codeCache.hpp
index a6eff0fe853..eb6ebd59242 100644
--- a/src/hotspot/share/code/codeCache.hpp
+++ b/src/hotspot/share/code/codeCache.hpp
@@ -270,10 +270,16 @@ class CodeCache : AllStatic {
// Flushing and deoptimization
static void flush_dependents_on(InstanceKlass* dependee);
+
+ // RedefineClasses support
// Flushing and deoptimization in case of evolution
static void mark_for_evol_deoptimization(InstanceKlass* dependee);
static int mark_dependents_for_evol_deoptimization();
+ static void mark_all_nmethods_for_evol_deoptimization();
static void flush_evol_dependents();
+ static void old_nmethods_do(MetadataClosure* f);
+ static void unregister_old_nmethod(CompiledMethod* c);
+
// Support for fullspeed debugging
static void flush_dependents_on_method(const methodHandle& dependee);
diff --git a/src/hotspot/share/code/compiledMethod.hpp b/src/hotspot/share/code/compiledMethod.hpp
index a5d915c396a..9d67695d51d 100644
--- a/src/hotspot/share/code/compiledMethod.hpp
+++ b/src/hotspot/share/code/compiledMethod.hpp
@@ -368,7 +368,6 @@ public:
int verify_icholder_relocations();
void verify_oop_relocations();
- virtual bool is_evol_dependent() = 0;
bool has_evol_metadata();
// Fast breakpoint support. Tells if this compiled method is
diff --git a/src/hotspot/share/code/nmethod.cpp b/src/hotspot/share/code/nmethod.cpp
index 00295ac66f1..5eb4162537b 100644
--- a/src/hotspot/share/code/nmethod.cpp
+++ b/src/hotspot/share/code/nmethod.cpp
@@ -1089,7 +1089,6 @@ void nmethod::make_unloaded() {
if (_method->code() == this) {
_method->clear_code(); // Break a cycle
}
- _method = NULL; // Clear the method of this dead nmethod
}
// Make the class unloaded - i.e., change state and notify sweeper
@@ -1107,8 +1106,12 @@ void nmethod::make_unloaded() {
MutexLockerEx ml(SafepointSynchronize::is_at_safepoint() ? NULL : CodeCache_lock,
Mutex::_no_safepoint_check_flag);
Universe::heap()->unregister_nmethod(this);
+ CodeCache::unregister_old_nmethod(this);
}
+ // Clear the method of this dead nmethod
+ set_method(NULL);
+
// Log the unloading.
log_state_change();
@@ -1289,6 +1292,7 @@ bool nmethod::make_not_entrant_or_zombie(int state) {
MutexLockerEx mu(CodeCache_lock, Mutex::_no_safepoint_check_flag);
if (nmethod_needs_unregister) {
Universe::heap()->unregister_nmethod(this);
+ CodeCache::unregister_old_nmethod(this);
}
flush_dependencies(/*delete_immediately*/true);
}
@@ -1986,32 +1990,6 @@ bool nmethod::check_dependency_on(DepChange& changes) {
return found_check;
}
-bool nmethod::is_evol_dependent() {
- for (Dependencies::DepStream deps(this); deps.next(); ) {
- if (deps.type() == Dependencies::evol_method) {
- Method* method = deps.method_argument(0);
- if (method->is_old()) {
- if (log_is_enabled(Debug, redefine, class, nmethod)) {
- ResourceMark rm;
- log_debug(redefine, class, nmethod)
- ("Found evol dependency of nmethod %s.%s(%s) compile_id=%d on method %s.%s(%s)",
- _method->method_holder()->external_name(),
- _method->name()->as_C_string(),
- _method->signature()->as_C_string(),
- compile_id(),
- method->method_holder()->external_name(),
- method->name()->as_C_string(),
- method->signature()->as_C_string());
- }
- if (TraceDependencies || LogCompilation)
- deps.log_dependency(method->method_holder());
- return true;
- }
- }
- }
- return false;
-}
-
// Called from mark_for_deoptimization, when dependee is invalidated.
bool nmethod::is_dependent_on_method(Method* dependee) {
for (Dependencies::DepStream deps(this); deps.next(); ) {
diff --git a/src/hotspot/share/code/nmethod.hpp b/src/hotspot/share/code/nmethod.hpp
index 32f404a06e1..35bee9a25ee 100644
--- a/src/hotspot/share/code/nmethod.hpp
+++ b/src/hotspot/share/code/nmethod.hpp
@@ -565,11 +565,6 @@ public:
// and the changes have invalidated it
bool check_dependency_on(DepChange& changes);
- // Evolution support. Tells if this compiled method is dependent on any of
- // redefined methods, such that if m() is replaced,
- // this compiled method will have to be deoptimized.
- bool is_evol_dependent();
-
// Fast breakpoint support. Tells if this compiled method is
// dependent on the given method. Returns true if this nmethod
// corresponds to the given method as well.
diff --git a/src/hotspot/share/gc/cms/concurrentMarkSweepGeneration.cpp b/src/hotspot/share/gc/cms/concurrentMarkSweepGeneration.cpp
index ddc418a3c7a..446e2385fc9 100644
--- a/src/hotspot/share/gc/cms/concurrentMarkSweepGeneration.cpp
+++ b/src/hotspot/share/gc/cms/concurrentMarkSweepGeneration.cpp
@@ -24,8 +24,6 @@
#include "precompiled.hpp"
#include "classfile/classLoaderDataGraph.hpp"
-#include "classfile/stringTable.hpp"
-#include "classfile/symbolTable.hpp"
#include "classfile/systemDictionary.hpp"
#include "code/codeCache.hpp"
#include "gc/cms/cmsCollectorPolicy.hpp"
@@ -54,7 +52,6 @@
#include "gc/shared/genCollectedHeap.hpp"
#include "gc/shared/genOopClosures.inline.hpp"
#include "gc/shared/isGCActiveMark.hpp"
-#include "gc/shared/oopStorageParState.hpp"
#include "gc/shared/owstTaskTerminator.hpp"
#include "gc/shared/referencePolicy.hpp"
#include "gc/shared/referenceProcessorPhaseTimes.hpp"
@@ -2771,12 +2768,10 @@ class CMSParMarkTask : public AbstractGangTask {
protected:
CMSCollector* _collector;
uint _n_workers;
- OopStorage::ParState _par_state_string;
CMSParMarkTask(const char* name, CMSCollector* collector, uint n_workers) :
AbstractGangTask(name),
_collector(collector),
- _n_workers(n_workers),
- _par_state_string(StringTable::weak_storage()) {}
+ _n_workers(n_workers) {}
// Work method in support of parallel rescan ... of young gen spaces
void do_young_space_rescan(OopsInGenClosure* cl,
ContiguousSpace* space,
diff --git a/src/hotspot/share/gc/cms/parNewGeneration.cpp b/src/hotspot/share/gc/cms/parNewGeneration.cpp
index 53213126abe..aecdccf2bdb 100644
--- a/src/hotspot/share/gc/cms/parNewGeneration.cpp
+++ b/src/hotspot/share/gc/cms/parNewGeneration.cpp
@@ -582,8 +582,7 @@ ParNewGenTask::ParNewGenTask(ParNewGeneration* young_gen,
_young_gen(young_gen), _old_gen(old_gen),
_young_old_boundary(young_old_boundary),
_state_set(state_set),
- _strong_roots_scope(strong_roots_scope),
- _par_state_string(StringTable::weak_storage())
+ _strong_roots_scope(strong_roots_scope)
{}
void ParNewGenTask::work(uint worker_id) {
diff --git a/src/hotspot/share/gc/cms/parNewGeneration.hpp b/src/hotspot/share/gc/cms/parNewGeneration.hpp
index 5c2aa943c8e..025ada089d0 100644
--- a/src/hotspot/share/gc/cms/parNewGeneration.hpp
+++ b/src/hotspot/share/gc/cms/parNewGeneration.hpp
@@ -235,7 +235,6 @@ class ParNewGenTask: public AbstractGangTask {
HeapWord* _young_old_boundary;
class ParScanThreadStateSet* _state_set;
StrongRootsScope* _strong_roots_scope;
- OopStorage::ParState _par_state_string;
public:
ParNewGenTask(ParNewGeneration* young_gen,
diff --git a/src/hotspot/share/gc/epsilon/epsilonHeap.hpp b/src/hotspot/share/gc/epsilon/epsilonHeap.hpp
index a07dc6fa494..b9dbaed7d77 100644
--- a/src/hotspot/share/gc/epsilon/epsilonHeap.hpp
+++ b/src/hotspot/share/gc/epsilon/epsilonHeap.hpp
@@ -129,6 +129,12 @@ public:
virtual void print_gc_threads_on(outputStream* st) const {}
virtual void gc_threads_do(ThreadClosure* tc) const {}
+ // No nmethod handling
+ virtual void register_nmethod(nmethod* nm) {}
+ virtual void unregister_nmethod(nmethod* nm) {}
+ virtual void flush_nmethod(nmethod* nm) {}
+ virtual void verify_nmethod(nmethod* nm) {}
+
// No heap verification
virtual void prepare_for_verify() {}
virtual void verify(VerifyOption option) {}
diff --git a/src/hotspot/share/gc/g1/g1BarrierSet.cpp b/src/hotspot/share/gc/g1/g1BarrierSet.cpp
index bd64f954032..f0689f3ec08 100644
--- a/src/hotspot/share/gc/g1/g1BarrierSet.cpp
+++ b/src/hotspot/share/gc/g1/g1BarrierSet.cpp
@@ -58,7 +58,8 @@ G1BarrierSet::G1BarrierSet(G1CardTable* card_table) :
_satb_mark_queue_buffer_allocator("SATB Buffer Allocator", G1SATBBufferSize),
_dirty_card_queue_buffer_allocator("DC Buffer Allocator", G1UpdateBufferSize),
_satb_mark_queue_set(),
- _dirty_card_queue_set()
+ _dirty_card_queue_set(),
+ _shared_dirty_card_queue(&_dirty_card_queue_set)
{}
void G1BarrierSet::enqueue(oop pre_val) {
@@ -147,24 +148,7 @@ void G1BarrierSet::on_thread_attach(Thread* thread) {
// If we are creating the thread during a marking cycle, we should
// set the active field of the SATB queue to true. That involves
- // copying the global is_active value to this thread's queue, which
- // is done without any direct synchronization here.
- //
- // The activation and deactivation of the SATB queues occurs at the
- // beginning / end of a marking cycle, and is done during
- // safepoints. This function is called just before a thread is
- // added to its corresponding threads list (for Java or non-Java
- // threads, respectively).
- //
- // For Java threads, that's done while holding the Threads_lock,
- // which ensures we're not at a safepoint, so reading the global
- // is_active state is synchronized against update.
- assert(!thread->is_Java_thread() || !SafepointSynchronize::is_at_safepoint(),
- "Should not be at a safepoint");
- // For non-Java threads, thread creation (and list addition) may,
- // and indeed usually does, occur during a safepoint. But such
- // creation isn't concurrent with updating the global SATB active
- // state.
+ // copying the global is_active value to this thread's queue.
bool is_satb_active = _satb_mark_queue_set.is_active();
G1ThreadLocalData::satb_mark_queue(thread).set_active(is_satb_active);
}
diff --git a/src/hotspot/share/gc/g1/g1BarrierSet.hpp b/src/hotspot/share/gc/g1/g1BarrierSet.hpp
index 3ad2fe64314..83c2bc5ec6c 100644
--- a/src/hotspot/share/gc/g1/g1BarrierSet.hpp
+++ b/src/hotspot/share/gc/g1/g1BarrierSet.hpp
@@ -27,6 +27,7 @@
#include "gc/g1/g1DirtyCardQueue.hpp"
#include "gc/g1/g1SATBMarkQueueSet.hpp"
+#include "gc/g1/g1SharedDirtyCardQueue.hpp"
#include "gc/shared/cardTable.hpp"
#include "gc/shared/cardTableBarrierSet.hpp"
@@ -42,6 +43,7 @@ class G1BarrierSet: public CardTableBarrierSet {
BufferNode::Allocator _dirty_card_queue_buffer_allocator;
G1SATBMarkQueueSet _satb_mark_queue_set;
G1DirtyCardQueueSet _dirty_card_queue_set;
+ G1SharedDirtyCardQueue _shared_dirty_card_queue;
static G1BarrierSet* g1_barrier_set() {
return barrier_set_cast(BarrierSet::barrier_set());
@@ -91,6 +93,10 @@ class G1BarrierSet: public CardTableBarrierSet {
return g1_barrier_set()->_dirty_card_queue_set;
}
+ static G1SharedDirtyCardQueue& shared_dirty_card_queue() {
+ return g1_barrier_set()->_shared_dirty_card_queue;
+ }
+
// Callbacks for runtime accesses.
template
class AccessBarrier: public ModRefBarrierSet::AccessBarrier {
diff --git a/src/hotspot/share/gc/g1/g1CollectedHeap.cpp b/src/hotspot/share/gc/g1/g1CollectedHeap.cpp
index 51c48293a95..fd07887d068 100644
--- a/src/hotspot/share/gc/g1/g1CollectedHeap.cpp
+++ b/src/hotspot/share/gc/g1/g1CollectedHeap.cpp
@@ -1575,7 +1575,10 @@ static size_t actual_reserved_page_size(ReservedSpace rs) {
// And ReservedSpace calls it 'special'. If we failed to set 'special',
// we reserved memory without large page.
if (os::can_commit_large_page_memory() || rs.special()) {
- page_size = rs.alignment();
+ // An alignment at ReservedSpace comes from preferred page size or
+ // heap alignment, and if the alignment came from heap alignment, it could be
+ // larger than large pages size. So need to cap with the large page size.
+ page_size = MIN2(rs.alignment(), os::large_page_size());
}
}
@@ -1682,12 +1685,10 @@ jint G1CollectedHeap::initialize() {
// later, based on the concurrent refinement object.
G1BarrierSet::dirty_card_queue_set().initialize(DirtyCardQ_CBL_mon,
&bs->dirty_card_queue_buffer_allocator(),
- Shared_DirtyCardQ_lock,
true); // init_free_ids
dirty_card_queue_set().initialize(DirtyCardQ_CBL_mon,
- &bs->dirty_card_queue_buffer_allocator(),
- Shared_DirtyCardQ_lock);
+ &bs->dirty_card_queue_buffer_allocator());
// Create the hot card cache.
_hot_card_cache = new G1HotCardCache(this);
@@ -2537,7 +2538,7 @@ void G1CollectedHeap::gc_prologue(bool full) {
// Update common counters.
increment_total_collections(full /* full gc */);
- if (full) {
+ if (full || collector_state()->in_initial_mark_gc()) {
increment_old_marking_cycles_started();
}
@@ -2863,16 +2864,92 @@ public:
};
void G1CollectedHeap::start_new_collection_set() {
+ double start = os::elapsedTime();
+
collection_set()->start_incremental_building();
clear_cset_fast_test();
guarantee(_eden.length() == 0, "eden should have been cleared");
policy()->transfer_survivors_to_cset(survivor());
+
+ // We redo the verification but now wrt to the new CSet which
+ // has just got initialized after the previous CSet was freed.
+ _cm->verify_no_collection_set_oops();
+
+ phase_times()->record_start_new_cset_time_ms((os::elapsedTime() - start) * 1000.0);
}
-bool
-G1CollectedHeap::do_collection_pause_at_safepoint(double target_pause_time_ms) {
+void G1CollectedHeap::calculate_collection_set(G1EvacuationInfo& evacuation_info, double target_pause_time_ms){
+ policy()->finalize_collection_set(target_pause_time_ms, &_survivor);
+ evacuation_info.set_collectionset_regions(collection_set()->region_length());
+
+ _cm->verify_no_collection_set_oops();
+
+ if (_hr_printer.is_active()) {
+ G1PrintCollectionSetClosure cl(&_hr_printer);
+ _collection_set.iterate(&cl);
+ }
+}
+
+G1HeapVerifier::G1VerifyType G1CollectedHeap::young_collection_verify_type() const {
+ if (collector_state()->in_initial_mark_gc()) {
+ return G1HeapVerifier::G1VerifyConcurrentStart;
+ } else if (collector_state()->in_young_only_phase()) {
+ return G1HeapVerifier::G1VerifyYoungNormal;
+ } else {
+ return G1HeapVerifier::G1VerifyMixed;
+ }
+}
+
+void G1CollectedHeap::verify_before_young_collection(G1HeapVerifier::G1VerifyType type) {
+ if (VerifyRememberedSets) {
+ log_info(gc, verify)("[Verifying RemSets before GC]");
+ VerifyRegionRemSetClosure v_cl;
+ heap_region_iterate(&v_cl);
+ }
+ _verifier->verify_before_gc(type);
+ _verifier->check_bitmaps("GC Start");
+}
+
+void G1CollectedHeap::verify_after_young_collection(G1HeapVerifier::G1VerifyType type) {
+ if (VerifyRememberedSets) {
+ log_info(gc, verify)("[Verifying RemSets after GC]");
+ VerifyRegionRemSetClosure v_cl;
+ heap_region_iterate(&v_cl);
+ }
+ _verifier->verify_after_gc(type);
+ _verifier->check_bitmaps("GC End");
+}
+
+void G1CollectedHeap::expand_heap_after_young_collection(){
+ size_t expand_bytes = _heap_sizing_policy->expansion_amount();
+ if (expand_bytes > 0) {
+ // No need for an ergo logging here,
+ // expansion_amount() does this when it returns a value > 0.
+ double expand_ms;
+ if (!expand(expand_bytes, _workers, &expand_ms)) {
+ // We failed to expand the heap. Cannot do anything about it.
+ }
+ phase_times()->record_expand_heap_time(expand_ms);
+ }
+}
+
+const char* G1CollectedHeap::young_gc_name() const {
+ if (collector_state()->in_initial_mark_gc()) {
+ return "Pause Young (Concurrent Start)";
+ } else if (collector_state()->in_young_only_phase()) {
+ if (collector_state()->in_young_gc_before_mixed()) {
+ return "Pause Young (Prepare Mixed)";
+ } else {
+ return "Pause Young (Normal)";
+ }
+ } else {
+ return "Pause Young (Mixed)";
+ }
+}
+
+bool G1CollectedHeap::do_collection_pause_at_safepoint(double target_pause_time_ms) {
assert_at_safepoint_on_vm_thread();
guarantee(!is_gc_active(), "collection is not reentrant");
@@ -2880,16 +2957,16 @@ G1CollectedHeap::do_collection_pause_at_safepoint(double target_pause_time_ms) {
return false;
}
- _gc_timer_stw->register_gc_start();
-
GCIdMark gc_id_mark;
- _gc_tracer_stw->report_gc_start(gc_cause(), _gc_timer_stw->gc_start());
SvcGCMarker sgcm(SvcGCMarker::MINOR);
ResourceMark rm;
policy()->note_gc_start();
+ _gc_timer_stw->register_gc_start();
+ _gc_tracer_stw->report_gc_start(gc_cause(), _gc_timer_stw->gc_start());
+
wait_for_root_region_scanning();
print_heap_before_gc();
@@ -2909,8 +2986,7 @@ G1CollectedHeap::do_collection_pause_at_safepoint(double target_pause_time_ms) {
// We do not allow initial-mark to be piggy-backed on a mixed GC.
assert(!collector_state()->in_initial_mark_gc() ||
- collector_state()->in_young_only_phase(), "sanity");
-
+ collector_state()->in_young_only_phase(), "sanity");
// We also do not allow mixed GCs during marking.
assert(!collector_state()->mark_or_rebuild_in_progress() || collector_state()->in_young_only_phase(), "sanity");
@@ -2918,39 +2994,19 @@ G1CollectedHeap::do_collection_pause_at_safepoint(double target_pause_time_ms) {
// thread has completed its logging output and it's safe to signal
// the CM thread, the flag's value in the policy has been reset.
bool should_start_conc_mark = collector_state()->in_initial_mark_gc();
+ if (should_start_conc_mark) {
+ _cm->gc_tracer_cm()->set_gc_cause(gc_cause());
+ }
// Inner scope for scope based logging, timers, and stats collection
{
G1EvacuationInfo evacuation_info;
- if (collector_state()->in_initial_mark_gc()) {
- // We are about to start a marking cycle, so we increment the
- // full collection counter.
- increment_old_marking_cycles_started();
- _cm->gc_tracer_cm()->set_gc_cause(gc_cause());
- }
-
_gc_tracer_stw->report_yc_type(collector_state()->yc_type());
GCTraceCPUTime tcpu;
- G1HeapVerifier::G1VerifyType verify_type;
- FormatBuffer<> gc_string("Pause Young ");
- if (collector_state()->in_initial_mark_gc()) {
- gc_string.append("(Concurrent Start)");
- verify_type = G1HeapVerifier::G1VerifyConcurrentStart;
- } else if (collector_state()->in_young_only_phase()) {
- if (collector_state()->in_young_gc_before_mixed()) {
- gc_string.append("(Prepare Mixed)");
- } else {
- gc_string.append("(Normal)");
- }
- verify_type = G1HeapVerifier::G1VerifyYoungNormal;
- } else {
- gc_string.append("(Mixed)");
- verify_type = G1HeapVerifier::G1VerifyMixed;
- }
- GCTraceTime(Info, gc) tm(gc_string, NULL, gc_cause(), true);
+ GCTraceTime(Info, gc) tm(young_gc_name(), NULL, gc_cause(), true);
uint active_workers = WorkerPolicy::calc_active_workers(workers()->total_workers(),
workers()->active_workers(),
@@ -2965,88 +3021,43 @@ G1CollectedHeap::do_collection_pause_at_safepoint(double target_pause_time_ms) {
G1HeapTransition heap_transition(this);
size_t heap_used_bytes_before_gc = used();
- // Don't dynamically change the number of GC threads this early. A value of
- // 0 is used to indicate serial work. When parallel work is done,
- // it will be set.
-
- { // Call to jvmpi::post_class_unload_events must occur outside of active GC
+ {
IsGCActiveMark x;
gc_prologue(false);
- if (VerifyRememberedSets) {
- log_info(gc, verify)("[Verifying RemSets before GC]");
- VerifyRegionRemSetClosure v_cl;
- heap_region_iterate(&v_cl);
- }
-
- _verifier->verify_before_gc(verify_type);
-
- _verifier->check_bitmaps("GC Start");
-
-#if COMPILER2_OR_JVMCI
- DerivedPointerTable::clear();
-#endif
-
- // Please see comment in g1CollectedHeap.hpp and
- // G1CollectedHeap::ref_processing_init() to see how
- // reference processing currently works in G1.
-
- // Enable discovery in the STW reference processor
- _ref_processor_stw->enable_discovery();
+ G1HeapVerifier::G1VerifyType verify_type = young_collection_verify_type();
+ verify_before_young_collection(verify_type);
{
+ // The elapsed time induced by the start time below deliberately elides
+ // the possible verification above.
+ double sample_start_time_sec = os::elapsedTime();
+
+ // Please see comment in g1CollectedHeap.hpp and
+ // G1CollectedHeap::ref_processing_init() to see how
+ // reference processing currently works in G1.
+ _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);
- // Forget the current alloc region (we might even choose it to be part
+ policy()->record_collection_pause_start(sample_start_time_sec);
+
+ // Forget the current allocation region (we might even choose it to be part
// of the collection set!).
_allocator->release_mutator_alloc_region();
- // This timing is only used by the ergonomics to handle our pause target.
- // It is unclear why this should not include the full pause. We will
- // investigate this in CR 7178365.
- //
- // Preserving the old comment here if that helps the investigation:
- //
- // The elapsed time induced by the start time below deliberately elides
- // the possible verification above.
- double sample_start_time_sec = os::elapsedTime();
-
- policy()->record_collection_pause_start(sample_start_time_sec);
-
- if (collector_state()->in_initial_mark_gc()) {
- concurrent_mark()->pre_initial_mark();
- }
-
- policy()->finalize_collection_set(target_pause_time_ms, &_survivor);
-
- evacuation_info.set_collectionset_regions(collection_set()->region_length());
-
- register_humongous_regions_with_cset();
-
- assert(_verifier->check_cset_fast_test(), "Inconsistency in the InCSetState table.");
-
- // We call this after finalize_cset() to
- // ensure that the CSet has been finalized.
- _cm->verify_no_cset_oops();
-
- if (_hr_printer.is_active()) {
- G1PrintCollectionSetClosure cl(&_hr_printer);
- _collection_set.iterate(&cl);
- }
-
- // Initialize the GC alloc regions.
- _allocator->init_gc_alloc_regions(evacuation_info);
+ calculate_collection_set(evacuation_info, target_pause_time_ms);
G1ParScanThreadStateSet per_thread_states(this,
workers()->active_workers(),
collection_set()->young_region_length(),
collection_set()->optional_region_length());
- pre_evacuate_collection_set();
+ pre_evacuate_collection_set(evacuation_info);
// Actually do the work...
evacuate_collection_set(&per_thread_states);
@@ -3054,39 +3065,12 @@ G1CollectedHeap::do_collection_pause_at_safepoint(double target_pause_time_ms) {
post_evacuate_collection_set(evacuation_info, &per_thread_states);
- const size_t* surviving_young_words = per_thread_states.surviving_young_words();
- free_collection_set(&_collection_set, evacuation_info, surviving_young_words);
+ start_new_collection_set();
- eagerly_reclaim_humongous_regions();
-
- record_obj_copy_mem_stats();
_survivor_evac_stats.adjust_desired_plab_sz();
_old_evac_stats.adjust_desired_plab_sz();
- double start = os::elapsedTime();
- start_new_collection_set();
- phase_times()->record_start_new_cset_time_ms((os::elapsedTime() - start) * 1000.0);
-
- if (evacuation_failed()) {
- double recalculate_used_start = os::elapsedTime();
- set_used(recalculate_used());
- phase_times()->record_evac_fail_recalc_used_time((os::elapsedTime() - recalculate_used_start) * 1000.0);
-
- if (_archive_allocator != NULL) {
- _archive_allocator->clear_used();
- }
- for (uint i = 0; i < ParallelGCThreads; i++) {
- if (_evacuation_failed_info_array[i].has_failed()) {
- _gc_tracer_stw->report_evacuation_failed(_evacuation_failed_info_array[i]);
- }
- }
- } else {
- // The "used" of the the collection set have already been subtracted
- // when they were freed. Add in the bytes evacuated.
- increase_used(policy()->bytes_copied_during_gc());
- }
-
- if (collector_state()->in_initial_mark_gc()) {
+ if (should_start_conc_mark) {
// We have to do this before we notify the CM threads that
// they can start working to make sure that all the
// appropriate initialization is done on the CM object.
@@ -3100,50 +3084,16 @@ G1CollectedHeap::do_collection_pause_at_safepoint(double target_pause_time_ms) {
_allocator->init_mutator_alloc_region();
- {
- size_t expand_bytes = _heap_sizing_policy->expansion_amount();
- if (expand_bytes > 0) {
- size_t bytes_before = capacity();
- // No need for an ergo logging here,
- // expansion_amount() does this when it returns a value > 0.
- double expand_ms;
- if (!expand(expand_bytes, _workers, &expand_ms)) {
- // We failed to expand the heap. Cannot do anything about it.
- }
- phase_times()->record_expand_heap_time(expand_ms);
- }
- }
+ expand_heap_after_young_collection();
- // We redo the verification but now wrt to the new CSet which
- // has just got initialized after the previous CSet was freed.
- _cm->verify_no_cset_oops();
-
- // This timing is only used by the ergonomics to handle our pause target.
- // It is unclear why this should not include the full pause. We will
- // investigate this in CR 7178365.
double sample_end_time_sec = os::elapsedTime();
double pause_time_ms = (sample_end_time_sec - sample_start_time_sec) * MILLIUNITS;
size_t total_cards_scanned = phase_times()->sum_thread_work_items(G1GCPhaseTimes::ScanRS, G1GCPhaseTimes::ScanRSScannedCards);
policy()->record_collection_pause_end(pause_time_ms, total_cards_scanned, heap_used_bytes_before_gc);
-
- evacuation_info.set_collectionset_used_before(collection_set()->bytes_used_before());
- evacuation_info.set_bytes_copied(policy()->bytes_copied_during_gc());
-
- if (VerifyRememberedSets) {
- log_info(gc, verify)("[Verifying RemSets after GC]");
- VerifyRegionRemSetClosure v_cl;
- heap_region_iterate(&v_cl);
- }
-
- _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();
-
- // CM reference discovery will be re-enabled if necessary.
}
+ verify_after_young_collection(verify_type);
+
#ifdef TRACESPINNING
ParallelTaskTerminator::print_termination_counts();
#endif
@@ -3159,11 +3109,6 @@ G1CollectedHeap::do_collection_pause_at_safepoint(double target_pause_time_ms) {
policy()->print_phases();
heap_transition.print();
- // It is not yet to safe to tell the concurrent mark to
- // start as we have some optional output below. We don't want the
- // output from the concurrent mark thread interfering with this
- // logging output either.
-
_hrm->verify_optional();
_verifier->verify_region_sets_optional();
@@ -3190,13 +3135,11 @@ G1CollectedHeap::do_collection_pause_at_safepoint(double target_pause_time_ms) {
// that came from the pause.
if (should_start_conc_mark) {
- // CAUTION: after the doConcurrentMark() call below,
- // the concurrent marking thread(s) could be running
- // concurrently with us. Make sure that anything after
- // this point does not assume that we are the only GC thread
- // running. Note: of course, the actual marking work will
- // not start until the safepoint itself is released in
- // SuspendibleThreadSet::desynchronize().
+ // CAUTION: after the doConcurrentMark() call below, the concurrent marking
+ // thread(s) could be running concurrently with us. Make sure that anything
+ // after this point does not assume that we are the only GC thread running.
+ // Note: of course, the actual marking work will not start until the safepoint
+ // itself is released in SuspendibleThreadSet::desynchronize().
do_concurrent_mark();
}
@@ -3677,6 +3620,7 @@ void G1CollectedHeap::process_discovered_references(G1ParScanThreadStateSet* per
make_pending_list_reachable();
+ assert(!rp->discovery_enabled(), "Postcondition");
rp->verify_no_references_recorded();
double ref_proc_time = os::elapsedTime() - ref_proc_start;
@@ -3699,7 +3643,7 @@ void G1CollectedHeap::merge_per_thread_state_info(G1ParScanThreadStateSet* per_t
phase_times()->record_merge_pss_time_ms((os::elapsedTime() - merge_pss_time_start) * 1000.0);
}
-void G1CollectedHeap::pre_evacuate_collection_set() {
+void G1CollectedHeap::pre_evacuate_collection_set(G1EvacuationInfo& evacuation_info) {
_expand_heap_after_alloc_failure = true;
_evacuation_failed = false;
@@ -3707,11 +3651,23 @@ void G1CollectedHeap::pre_evacuate_collection_set() {
_hot_card_cache->reset_hot_cache_claimed_index();
_hot_card_cache->set_use_cache(false);
+ // Initialize the GC alloc regions.
+ _allocator->init_gc_alloc_regions(evacuation_info);
+
+ register_humongous_regions_with_cset();
+ assert(_verifier->check_cset_fast_test(), "Inconsistency in the InCSetState table.");
+
rem_set()->prepare_for_oops_into_collection_set_do();
_preserved_marks_set.assert_empty();
+#if COMPILER2_OR_JVMCI
+ DerivedPointerTable::clear();
+#endif
+
// InitialMark needs claim bits to keep track of the marked-through CLDs.
if (collector_state()->in_initial_mark_gc()) {
+ concurrent_mark()->pre_initial_mark();
+
double start_clear_claimed_marks = os::elapsedTime();
ClassLoaderDataGraph::clear_claimed_marks();
@@ -3918,19 +3874,34 @@ void G1CollectedHeap::post_evacuate_collection_set(G1EvacuationInfo& evacuation_
phase_times()->record_string_deduplication_time(string_cleanup_time_ms);
}
+ _allocator->release_gc_alloc_regions(evacuation_info);
+
if (evacuation_failed()) {
restore_after_evac_failure();
// Reset the G1EvacuationFailureALot counters and flags
- // Note: the values are reset only when an actual
- // evacuation failure occurs.
NOT_PRODUCT(reset_evacuation_should_fail();)
+
+ double recalculate_used_start = os::elapsedTime();
+ set_used(recalculate_used());
+ phase_times()->record_evac_fail_recalc_used_time((os::elapsedTime() - recalculate_used_start) * 1000.0);
+
+ if (_archive_allocator != NULL) {
+ _archive_allocator->clear_used();
+ }
+ for (uint i = 0; i < ParallelGCThreads; i++) {
+ if (_evacuation_failed_info_array[i].has_failed()) {
+ _gc_tracer_stw->report_evacuation_failed(_evacuation_failed_info_array[i]);
+ }
+ }
+ } else {
+ // The "used" of the the collection set have already been subtracted
+ // when they were freed. Add in the bytes evacuated.
+ increase_used(policy()->bytes_copied_during_gc());
}
_preserved_marks_set.assert_empty();
- _allocator->release_gc_alloc_regions(evacuation_info);
-
merge_per_thread_state_info(per_thread_states);
// Reset and re-enable the hot card cache.
@@ -3942,6 +3913,16 @@ void G1CollectedHeap::post_evacuate_collection_set(G1EvacuationInfo& evacuation_
purge_code_root_memory();
redirty_logged_cards();
+
+ free_collection_set(&_collection_set, evacuation_info, per_thread_states->surviving_young_words());
+
+ eagerly_reclaim_humongous_regions();
+
+ record_obj_copy_mem_stats();
+
+ evacuation_info.set_collectionset_used_before(collection_set()->bytes_used_before());
+ evacuation_info.set_bytes_copied(policy()->bytes_copied_during_gc());
+
#if COMPILER2_OR_JVMCI
double start = os::elapsedTime();
DerivedPointerTable::update_pointers();
diff --git a/src/hotspot/share/gc/g1/g1CollectedHeap.hpp b/src/hotspot/share/gc/g1/g1CollectedHeap.hpp
index 007804bf7c7..a1915b68d19 100644
--- a/src/hotspot/share/gc/g1/g1CollectedHeap.hpp
+++ b/src/hotspot/share/gc/g1/g1CollectedHeap.hpp
@@ -357,6 +357,8 @@ private:
assert(Thread::current()->is_VM_thread(), "current thread is not VM thread"); \
} while (0)
+ const char* young_gc_name() const;
+
// The young region list.
G1EdenRegions _eden;
G1SurvivorRegions _survivor;
@@ -730,14 +732,21 @@ private:
// to the GC locker being active, true otherwise
bool do_collection_pause_at_safepoint(double target_pause_time_ms);
+ G1HeapVerifier::G1VerifyType young_collection_verify_type() const;
+ void verify_before_young_collection(G1HeapVerifier::G1VerifyType type);
+ void verify_after_young_collection(G1HeapVerifier::G1VerifyType type);
+
+ void calculate_collection_set(G1EvacuationInfo& evacuation_info, double target_pause_time_ms);
+
// Actually do the work of evacuating the collection set.
void evacuate_collection_set(G1ParScanThreadStateSet* per_thread_states);
void evacuate_optional_collection_set(G1ParScanThreadStateSet* per_thread_states);
void evacuate_optional_regions(G1ParScanThreadStateSet* per_thread_states, G1OptionalCSet* ocset);
- void pre_evacuate_collection_set();
+ void pre_evacuate_collection_set(G1EvacuationInfo& evacuation_info);
void post_evacuate_collection_set(G1EvacuationInfo& evacuation_info, G1ParScanThreadStateSet* pss);
+ void expand_heap_after_young_collection();
// Update object copying statistics.
void record_obj_copy_mem_stats();
@@ -1313,6 +1322,12 @@ public:
// Unregister the given nmethod from the G1 heap.
virtual void unregister_nmethod(nmethod* nm);
+ // No nmethod flushing needed.
+ virtual void flush_nmethod(nmethod* nm) {}
+
+ // No nmethod verification implemented.
+ virtual void verify_nmethod(nmethod* nm) {}
+
// Free up superfluous code root memory.
void purge_code_root_memory();
diff --git a/src/hotspot/share/gc/g1/g1ConcurrentMark.cpp b/src/hotspot/share/gc/g1/g1ConcurrentMark.cpp
index 36bd2539318..ff8d2d5d012 100644
--- a/src/hotspot/share/gc/g1/g1ConcurrentMark.cpp
+++ b/src/hotspot/share/gc/g1/g1ConcurrentMark.cpp
@@ -734,7 +734,9 @@ public:
};
void G1ConcurrentMark::pre_initial_mark() {
- // Initialize marking structures. This has to be done in a STW phase.
+ assert_at_safepoint_on_vm_thread();
+
+ // Reset marking state.
reset();
// For each region note start of marking.
@@ -1944,7 +1946,7 @@ public:
}
};
-void G1ConcurrentMark::verify_no_cset_oops() {
+void G1ConcurrentMark::verify_no_collection_set_oops() {
assert(SafepointSynchronize::is_at_safepoint(), "should be at a safepoint");
if (!_g1h->collector_state()->mark_or_rebuild_in_progress()) {
return;
diff --git a/src/hotspot/share/gc/g1/g1ConcurrentMark.hpp b/src/hotspot/share/gc/g1/g1ConcurrentMark.hpp
index 7051815cb30..780874fdea0 100644
--- a/src/hotspot/share/gc/g1/g1ConcurrentMark.hpp
+++ b/src/hotspot/share/gc/g1/g1ConcurrentMark.hpp
@@ -579,7 +579,7 @@ public:
// Verify that there are no collection set oops on the stacks (taskqueues /
// global mark stack) and fingers (global / per-task).
// If marking is not in progress, it's a no-op.
- void verify_no_cset_oops() PRODUCT_RETURN;
+ void verify_no_collection_set_oops() PRODUCT_RETURN;
inline bool do_yield_check();
diff --git a/src/hotspot/share/gc/g1/g1DirtyCardQueue.cpp b/src/hotspot/share/gc/g1/g1DirtyCardQueue.cpp
index 3407ac112ff..038430a8bd7 100644
--- a/src/hotspot/share/gc/g1/g1DirtyCardQueue.cpp
+++ b/src/hotspot/share/gc/g1/g1DirtyCardQueue.cpp
@@ -56,21 +56,18 @@ public:
}
};
-G1DirtyCardQueue::G1DirtyCardQueue(G1DirtyCardQueueSet* qset, bool permanent) :
+G1DirtyCardQueue::G1DirtyCardQueue(G1DirtyCardQueueSet* qset) :
// Dirty card queues are always active, so we create them with their
// active field set to true.
- PtrQueue(qset, permanent, true /* active */)
+ PtrQueue(qset, true /* active */)
{ }
G1DirtyCardQueue::~G1DirtyCardQueue() {
- if (!is_permanent()) {
- flush();
- }
+ flush();
}
G1DirtyCardQueueSet::G1DirtyCardQueueSet(bool notify_when_complete) :
PtrQueueSet(notify_when_complete),
- _shared_dirty_card_queue(this, true /* permanent */),
_free_ids(NULL),
_processed_buffers_mut(0),
_processed_buffers_rs_thread(0),
@@ -90,10 +87,8 @@ uint G1DirtyCardQueueSet::num_par_ids() {
void G1DirtyCardQueueSet::initialize(Monitor* cbl_mon,
BufferNode::Allocator* allocator,
- Mutex* lock,
bool init_free_ids) {
PtrQueueSet::initialize(cbl_mon, allocator);
- _shared_dirty_card_queue.set_lock(lock);
if (init_free_ids) {
_free_ids = new G1FreeIdSet(0, num_par_ids());
}
@@ -217,13 +212,7 @@ void G1DirtyCardQueueSet::abandon_logs() {
} closure;
Threads::threads_do(&closure);
- shared_dirty_card_queue()->reset();
-}
-
-void G1DirtyCardQueueSet::concatenate_log(G1DirtyCardQueue& dcq) {
- if (!dcq.is_empty()) {
- dcq.flush();
- }
+ G1BarrierSet::shared_dirty_card_queue().reset();
}
void G1DirtyCardQueueSet::concatenate_logs() {
@@ -234,16 +223,16 @@ void G1DirtyCardQueueSet::concatenate_logs() {
size_t old_limit = max_completed_buffers();
set_max_completed_buffers(MaxCompletedBuffersUnlimited);
- class ConcatenateThreadLogClosure : public ThreadClosure {
- G1DirtyCardQueueSet* _qset;
- public:
- ConcatenateThreadLogClosure(G1DirtyCardQueueSet* qset) : _qset(qset) {}
+ struct ConcatenateThreadLogClosure : public ThreadClosure {
virtual void do_thread(Thread* t) {
- _qset->concatenate_log(G1ThreadLocalData::dirty_card_queue(t));
+ G1DirtyCardQueue& dcq = G1ThreadLocalData::dirty_card_queue(t);
+ if (!dcq.is_empty()) {
+ dcq.flush();
+ }
}
- } closure(this);
+ } closure;
Threads::threads_do(&closure);
- concatenate_log(_shared_dirty_card_queue);
+ G1BarrierSet::shared_dirty_card_queue().flush();
set_max_completed_buffers(old_limit);
}
diff --git a/src/hotspot/share/gc/g1/g1DirtyCardQueue.hpp b/src/hotspot/share/gc/g1/g1DirtyCardQueue.hpp
index 545843e437e..8b9a71d2c95 100644
--- a/src/hotspot/share/gc/g1/g1DirtyCardQueue.hpp
+++ b/src/hotspot/share/gc/g1/g1DirtyCardQueue.hpp
@@ -48,7 +48,7 @@ public:
// A ptrQueue whose elements are "oops", pointers to object heads.
class G1DirtyCardQueue: public PtrQueue {
public:
- G1DirtyCardQueue(G1DirtyCardQueueSet* qset, bool permanent = false);
+ G1DirtyCardQueue(G1DirtyCardQueueSet* qset);
// Flush before destroying; queue may be used to capture pending work while
// doing something else, with auto-flush on completion.
@@ -70,11 +70,7 @@ public:
};
-
-
class G1DirtyCardQueueSet: public PtrQueueSet {
- G1DirtyCardQueue _shared_dirty_card_queue;
-
// Apply the closure to the elements of "node" from it's index to
// buffer_size. If all closure applications return true, then
// returns true. Stops processing after the first closure
@@ -116,15 +112,12 @@ class G1DirtyCardQueueSet: public PtrQueueSet {
// Current buffer node used for parallel iteration.
BufferNode* volatile _cur_par_buffer_node;
- void concatenate_log(G1DirtyCardQueue& dcq);
-
public:
G1DirtyCardQueueSet(bool notify_when_complete = true);
~G1DirtyCardQueueSet();
void initialize(Monitor* cbl_mon,
BufferNode::Allocator* allocator,
- Mutex* lock,
bool init_free_ids = false);
// The number of parallel ids that can be claimed to allow collector or
@@ -147,10 +140,6 @@ public:
// by reset_for_par_iteration.
void par_apply_closure_to_all_completed_buffers(G1CardTableEntryClosure* cl);
- G1DirtyCardQueue* shared_dirty_card_queue() {
- return &_shared_dirty_card_queue;
- }
-
// If a full collection is happening, reset partial logs, and ignore
// completed ones: the full collection will make them all irrelevant.
void abandon_logs();
diff --git a/src/hotspot/share/gc/g1/g1Policy.cpp b/src/hotspot/share/gc/g1/g1Policy.cpp
index cd03722d312..14729bc840a 100644
--- a/src/hotspot/share/gc/g1/g1Policy.cpp
+++ b/src/hotspot/share/gc/g1/g1Policy.cpp
@@ -1188,9 +1188,11 @@ uint G1Policy::calc_max_old_cset_length() const {
return (uint) result;
}
-void G1Policy::finalize_collection_set(double target_pause_time_ms, G1SurvivorRegions* survivor) {
+uint G1Policy::finalize_collection_set(double target_pause_time_ms, G1SurvivorRegions* survivor) {
double time_remaining_ms = _collection_set->finalize_young_part(target_pause_time_ms, survivor);
_collection_set->finalize_old_part(time_remaining_ms);
+
+ return _collection_set->region_length();
}
void G1Policy::transfer_survivors_to_cset(const G1SurvivorRegions* survivors) {
diff --git a/src/hotspot/share/gc/g1/g1Policy.hpp b/src/hotspot/share/gc/g1/g1Policy.hpp
index 22b9ea8d8db..771def9b4ee 100644
--- a/src/hotspot/share/gc/g1/g1Policy.hpp
+++ b/src/hotspot/share/gc/g1/g1Policy.hpp
@@ -344,7 +344,7 @@ public:
bool next_gc_should_be_mixed(const char* true_action_str,
const char* false_action_str) const;
- void finalize_collection_set(double target_pause_time_ms, G1SurvivorRegions* survivor);
+ uint finalize_collection_set(double target_pause_time_ms, G1SurvivorRegions* survivor);
private:
// Set the state to start a concurrent marking cycle and clear
// _initiate_conc_mark_if_possible because it has now been
diff --git a/src/hotspot/share/gc/g1/g1RegionToSpaceMapper.cpp b/src/hotspot/share/gc/g1/g1RegionToSpaceMapper.cpp
index a5fe219f994..61d7332d8b0 100644
--- a/src/hotspot/share/gc/g1/g1RegionToSpaceMapper.cpp
+++ b/src/hotspot/share/gc/g1/g1RegionToSpaceMapper.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2001, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2001, 2019, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -205,8 +205,10 @@ G1RegionToHeteroSpaceMapper::G1RegionToHeteroSpaceMapper(ReservedSpace rs,
MemoryType type) :
G1RegionToSpaceMapper(rs, actual_size, page_size, alloc_granularity, commit_factor, type),
_rs(rs),
+ _dram_mapper(NULL),
_num_committed_dram(0),
_num_committed_nvdimm(0),
+ _start_index_of_dram(0),
_page_size(page_size),
_commit_factor(commit_factor),
_type(type) {
@@ -248,7 +250,6 @@ bool G1RegionToHeteroSpaceMapper::initialize() {
_dram_mapper = new G1RegionsSmallerThanCommitSizeMapper(rs_dram, rs_dram.size(), _page_size, _region_granularity, _commit_factor, _type);
}
- _start_index_of_nvdimm = 0;
_start_index_of_dram = (uint)(rs_nvdimm.size() / _region_granularity);
return true;
}
diff --git a/src/hotspot/share/gc/g1/g1RegionToSpaceMapper.hpp b/src/hotspot/share/gc/g1/g1RegionToSpaceMapper.hpp
index a0c70db9ee5..9db83350eff 100644
--- a/src/hotspot/share/gc/g1/g1RegionToSpaceMapper.hpp
+++ b/src/hotspot/share/gc/g1/g1RegionToSpaceMapper.hpp
@@ -101,12 +101,10 @@ class G1RegionToSpaceMapper : public CHeapObj {
// part of space is mapped to dram and part to nv-dimm
class G1RegionToHeteroSpaceMapper : public G1RegionToSpaceMapper {
private:
- size_t _pages_per_region;
ReservedSpace _rs;
G1RegionToSpaceMapper* _dram_mapper;
uint _num_committed_dram;
uint _num_committed_nvdimm;
- uint _start_index_of_nvdimm;
uint _start_index_of_dram;
size_t _page_size;
size_t _commit_factor;
diff --git a/src/hotspot/share/gc/g1/g1RemSet.cpp b/src/hotspot/share/gc/g1/g1RemSet.cpp
index b2404cbac29..01862e30088 100644
--- a/src/hotspot/share/gc/g1/g1RemSet.cpp
+++ b/src/hotspot/share/gc/g1/g1RemSet.cpp
@@ -35,6 +35,7 @@
#include "gc/g1/g1OopClosures.inline.hpp"
#include "gc/g1/g1RootClosures.hpp"
#include "gc/g1/g1RemSet.hpp"
+#include "gc/g1/g1SharedDirtyCardQueue.hpp"
#include "gc/g1/heapRegion.inline.hpp"
#include "gc/g1/heapRegionManager.inline.hpp"
#include "gc/g1/heapRegionRemSet.hpp"
@@ -519,9 +520,7 @@ void G1RemSet::oops_into_collection_set_do(G1ParScanThreadState* pss, uint worke
}
void G1RemSet::prepare_for_oops_into_collection_set_do() {
- G1DirtyCardQueueSet& dcqs = G1BarrierSet::dirty_card_queue_set();
- dcqs.concatenate_logs();
-
+ G1BarrierSet::dirty_card_queue_set().concatenate_logs();
_scan_state->reset();
}
@@ -660,29 +659,30 @@ void G1RemSet::refine_card_concurrently(CardValue* card_ptr,
assert(!dirty_region.is_empty(), "sanity");
G1ConcurrentRefineOopClosure conc_refine_cl(_g1h, worker_i);
-
- bool card_processed =
- r->oops_on_card_seq_iterate_careful(dirty_region, &conc_refine_cl);
+ if (r->oops_on_card_seq_iterate_careful(dirty_region, &conc_refine_cl)) {
+ _num_conc_refined_cards++; // Unsynchronized update, only used for logging.
+ return;
+ }
// If unable to process the card then we encountered an unparsable
- // part of the heap (e.g. a partially allocated object) while
- // processing a stale card. Despite the card being stale, redirty
- // and re-enqueue, because we've already cleaned the card. Without
- // this we could incorrectly discard a non-stale card.
- if (!card_processed) {
- // The card might have gotten re-dirtied and re-enqueued while we
- // worked. (In fact, it's pretty likely.)
- if (*card_ptr != G1CardTable::dirty_card_val()) {
- *card_ptr = G1CardTable::dirty_card_val();
- MutexLockerEx x(Shared_DirtyCardQ_lock,
- Mutex::_no_safepoint_check_flag);
- G1DirtyCardQueue* sdcq =
- G1BarrierSet::dirty_card_queue_set().shared_dirty_card_queue();
- sdcq->enqueue(card_ptr);
- }
- } else {
- _num_conc_refined_cards++; // Unsynchronized update, only used for logging.
+ // part of the heap (e.g. a partially allocated object, so only
+ // temporarily a problem) while processing a stale card. Despite
+ // the card being stale, we can't simply ignore it, because we've
+ // already marked the card cleaned, so taken responsibility for
+ // ensuring the card gets scanned.
+ //
+ // However, the card might have gotten re-dirtied and re-enqueued
+ // while we worked. (In fact, it's pretty likely.)
+ if (*card_ptr == G1CardTable::dirty_card_val()) {
+ return;
}
+
+ // Re-dirty the card and enqueue in the *shared* queue. Can't use
+ // the thread-local queue, because that might be the queue that is
+ // being processed by us; we could be a Java thread conscripted to
+ // perform refinement on our queue's current buffer.
+ *card_ptr = G1CardTable::dirty_card_val();
+ G1BarrierSet::shared_dirty_card_queue().enqueue(card_ptr);
}
bool G1RemSet::refine_card_during_gc(CardValue* card_ptr,
diff --git a/src/hotspot/share/gc/g1/g1RootProcessor.cpp b/src/hotspot/share/gc/g1/g1RootProcessor.cpp
index c5fda25d4c1..431eaed901c 100644
--- a/src/hotspot/share/gc/g1/g1RootProcessor.cpp
+++ b/src/hotspot/share/gc/g1/g1RootProcessor.cpp
@@ -38,7 +38,6 @@
#include "gc/g1/g1RootClosures.hpp"
#include "gc/g1/g1RootProcessor.hpp"
#include "gc/g1/heapRegion.inline.hpp"
-#include "gc/shared/oopStorageParState.hpp"
#include "gc/shared/referenceProcessor.hpp"
#include "memory/allocation.inline.hpp"
#include "runtime/mutex.hpp"
@@ -71,7 +70,6 @@ G1RootProcessor::G1RootProcessor(G1CollectedHeap* g1h, uint n_workers) :
_g1h(g1h),
_process_strong_tasks(G1RP_PS_NumElements),
_srs(n_workers),
- _par_state_string(StringTable::weak_storage()),
_lock(Mutex::leaf, "G1 Root Scanning barrier lock", false, Monitor::_safepoint_check_never),
_n_workers_discovered_strong_classes(0) {}
diff --git a/src/hotspot/share/gc/g1/g1RootProcessor.hpp b/src/hotspot/share/gc/g1/g1RootProcessor.hpp
index 2650ea48632..b274199b147 100644
--- a/src/hotspot/share/gc/g1/g1RootProcessor.hpp
+++ b/src/hotspot/share/gc/g1/g1RootProcessor.hpp
@@ -25,7 +25,6 @@
#ifndef SHARE_GC_G1_G1ROOTPROCESSOR_HPP
#define SHARE_GC_G1_G1ROOTPROCESSOR_HPP
-#include "gc/shared/oopStorageParState.hpp"
#include "gc/shared/strongRootsScope.hpp"
#include "memory/allocation.hpp"
#include "runtime/mutex.hpp"
@@ -50,7 +49,6 @@ class G1RootProcessor : public StackObj {
G1CollectedHeap* _g1h;
SubTasksDone _process_strong_tasks;
StrongRootsScope _srs;
- OopStorage::ParState _par_state_string;
// Used to implement the Thread work barrier.
Monitor _lock;
diff --git a/src/hotspot/share/gc/g1/g1SharedDirtyCardQueue.cpp b/src/hotspot/share/gc/g1/g1SharedDirtyCardQueue.cpp
new file mode 100644
index 00000000000..c29096beebc
--- /dev/null
+++ b/src/hotspot/share/gc/g1/g1SharedDirtyCardQueue.cpp
@@ -0,0 +1,73 @@
+/*
+ * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#include "precompiled.hpp"
+#include "gc/g1/g1DirtyCardQueue.hpp"
+#include "gc/g1/g1SharedDirtyCardQueue.hpp"
+#include "gc/shared/ptrQueue.hpp"
+#include "runtime/mutex.hpp"
+#include "runtime/mutexLocker.hpp"
+
+G1SharedDirtyCardQueue::G1SharedDirtyCardQueue(G1DirtyCardQueueSet* qset) :
+ _qset(qset),
+ _buffer(NULL),
+ _index(0)
+{}
+
+G1SharedDirtyCardQueue::~G1SharedDirtyCardQueue() {
+ flush();
+}
+
+void G1SharedDirtyCardQueue::enqueue(void* card_ptr) {
+ MutexLockerEx ml(Shared_DirtyCardQ_lock, Mutex::_no_safepoint_check_flag);
+ if (_index == 0) {
+ flush();
+ _buffer = _qset->allocate_buffer();
+ _index = _qset->buffer_size();
+ assert(_index != 0, "invariant");
+ }
+ _buffer[--_index] = card_ptr;
+}
+
+void G1SharedDirtyCardQueue::flush() {
+ if (_buffer != NULL) {
+ BufferNode* node = BufferNode::make_node_from_buffer(_buffer, _index);
+ _buffer = NULL;
+ _index = 0;
+ if (node->index() == _qset->buffer_size()) {
+ _qset->deallocate_buffer(node);
+ } else {
+ _qset->enqueue_completed_buffer(node);
+ }
+ }
+ assert(_index == 0, "invariant");
+}
+
+void G1SharedDirtyCardQueue::reset() {
+ if (_buffer == NULL) {
+ _index = 0;
+ } else {
+ _index = _qset->buffer_size();
+ }
+}
diff --git a/src/hotspot/share/gc/g1/g1SharedDirtyCardQueue.hpp b/src/hotspot/share/gc/g1/g1SharedDirtyCardQueue.hpp
new file mode 100644
index 00000000000..d921b881714
--- /dev/null
+++ b/src/hotspot/share/gc/g1/g1SharedDirtyCardQueue.hpp
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
+ * 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_G1_G1SHAREDDIRTYCARDQUEUE_HPP
+#define SHARE_GC_G1_G1SHAREDDIRTYCARDQUEUE_HPP
+
+#include "utilities/globalDefinitions.hpp"
+
+class G1DirtyCardQueueSet;
+
+// A dirty card queue providing thread-safe enqueue. A shared global
+// instance can be used for cases where a thread-local dirty card can't
+// be used.
+class G1SharedDirtyCardQueue {
+ G1DirtyCardQueueSet* const _qset;
+ void** _buffer;
+ size_t _index;
+
+ // Noncopyable
+ G1SharedDirtyCardQueue(const G1SharedDirtyCardQueue&);
+ G1SharedDirtyCardQueue& operator=(const G1SharedDirtyCardQueue&);
+
+public:
+ G1SharedDirtyCardQueue(G1DirtyCardQueueSet* qset);
+ ~G1SharedDirtyCardQueue(); // flushes the queue.
+
+ // Thread-safe addition to shared logging buffer.
+ void enqueue(void* card_ptr);
+
+ // Flush any pending entries to the qset and remove the buffer.
+ // Not thread-safe.
+ void flush();
+
+ // Discard any pending entries.
+ // Not thread-safe.
+ void reset();
+};
+
+#endif // SHARE_GC_G1_G1SHAREDDIRTYCARDQUEUE_HPP
diff --git a/src/hotspot/share/gc/parallel/adjoiningGenerations.cpp b/src/hotspot/share/gc/parallel/adjoiningGenerations.cpp
index b41108520a4..e60c46ec933 100644
--- a/src/hotspot/share/gc/parallel/adjoiningGenerations.cpp
+++ b/src/hotspot/share/gc/parallel/adjoiningGenerations.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2003, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2019, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -119,7 +119,7 @@ AdjoiningGenerations::AdjoiningGenerations(ReservedSpace old_young_rs,
}
}
-AdjoiningGenerations::AdjoiningGenerations() { }
+AdjoiningGenerations::AdjoiningGenerations(): _young_gen(NULL), _old_gen(NULL), _virtual_spaces(NULL) { }
size_t AdjoiningGenerations::reserved_byte_size() {
return virtual_spaces()->reserved_space().size();
diff --git a/src/hotspot/share/gc/parallel/adjoiningGenerations.hpp b/src/hotspot/share/gc/parallel/adjoiningGenerations.hpp
index 8b73dcc56e1..8ab919be80b 100644
--- a/src/hotspot/share/gc/parallel/adjoiningGenerations.hpp
+++ b/src/hotspot/share/gc/parallel/adjoiningGenerations.hpp
@@ -50,6 +50,7 @@ class AdjoiningGenerations : public CHeapObj {
bool request_young_gen_expansion(size_t desired_change_in_bytes);
protected:
+ AdjoiningGenerations();
// The young generation and old generation, respectively
PSYoungGen* _young_gen;
PSOldGen* _old_gen;
@@ -59,7 +60,6 @@ class AdjoiningGenerations : public CHeapObj {
public:
AdjoiningGenerations(ReservedSpace rs, GenerationSizer* policy, size_t alignment);
- AdjoiningGenerations();
// Accessors
PSYoungGen* young_gen() { return _young_gen; }
diff --git a/src/hotspot/share/gc/parallel/gcTaskThread.cpp b/src/hotspot/share/gc/parallel/gcTaskThread.cpp
index 7982c8c9d10..9a336175fa6 100644
--- a/src/hotspot/share/gc/parallel/gcTaskThread.cpp
+++ b/src/hotspot/share/gc/parallel/gcTaskThread.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2002, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2002, 2019, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -167,7 +167,6 @@ void GCTaskThread::run() {
// so that a task can complete without waiting for idle tasks.
// They have to be terminated separately.
IdleGCTask::destroy((IdleGCTask*)task);
- set_is_working(true);
}
// Check if we should release our inner resources.
diff --git a/src/hotspot/share/gc/parallel/gcTaskThread.hpp b/src/hotspot/share/gc/parallel/gcTaskThread.hpp
index ae2b8d488ad..6646f563573 100644
--- a/src/hotspot/share/gc/parallel/gcTaskThread.hpp
+++ b/src/hotspot/share/gc/parallel/gcTaskThread.hpp
@@ -47,8 +47,6 @@ private:
GCTaskTimeStamp* time_stamp_at(uint index);
void add_task_timestamp(const char* name, jlong t_entry, jlong t_exit);
- bool _is_working; // True if participating in GC tasks
-
// Factory create and destroy methods.
static GCTaskThread* create(GCTaskManager* manager,
uint which,
@@ -85,7 +83,6 @@ protected:
uint processor_id() const {
return _processor_id;
}
- void set_is_working(bool v) { _is_working = v; }
};
class GCTaskTimeStamp : public CHeapObj
diff --git a/src/hotspot/share/gc/parallel/parallelScavengeHeap.hpp b/src/hotspot/share/gc/parallel/parallelScavengeHeap.hpp
index f9315e65e85..f7bbd054d1e 100644
--- a/src/hotspot/share/gc/parallel/parallelScavengeHeap.hpp
+++ b/src/hotspot/share/gc/parallel/parallelScavengeHeap.hpp
@@ -93,7 +93,15 @@ class ParallelScavengeHeap : public CollectedHeap {
public:
ParallelScavengeHeap(GenerationSizer* policy) :
- CollectedHeap(), _collector_policy(policy), _death_march_count(0) { }
+ CollectedHeap(),
+ _collector_policy(policy),
+ _gens(NULL),
+ _death_march_count(0),
+ _young_manager(NULL),
+ _old_manager(NULL),
+ _eden_pool(NULL),
+ _survivor_pool(NULL),
+ _old_pool(NULL) { }
// For use by VM operations
enum CollectionType {
diff --git a/src/hotspot/share/gc/parallel/psAdaptiveSizePolicy.cpp b/src/hotspot/share/gc/parallel/psAdaptiveSizePolicy.cpp
index dd6bf9150f3..cad4f7387eb 100644
--- a/src/hotspot/share/gc/parallel/psAdaptiveSizePolicy.cpp
+++ b/src/hotspot/share/gc/parallel/psAdaptiveSizePolicy.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2002, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2002, 2019, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -49,34 +49,25 @@ PSAdaptiveSizePolicy::PSAdaptiveSizePolicy(size_t init_eden_size,
init_survivor_size,
gc_pause_goal_sec,
gc_cost_ratio),
+ _avg_major_pause(new AdaptivePaddedAverage(AdaptiveTimeWeight, PausePadding)),
+ _avg_base_footprint(new AdaptiveWeightedAverage(AdaptiveSizePolicyWeight)),
+ _gc_stats(),
_collection_cost_margin_fraction(AdaptiveSizePolicyCollectionCostMargin / 100.0),
+ _major_pause_old_estimator(new LinearLeastSquareFit(AdaptiveSizePolicyWeight)),
+ _major_pause_young_estimator(new LinearLeastSquareFit(AdaptiveSizePolicyWeight)),
_latest_major_mutator_interval_seconds(0),
_space_alignment(space_alignment),
_gc_minor_pause_goal_sec(gc_minor_pause_goal_sec),
_live_at_last_full_gc(init_promo_size),
- _young_gen_change_for_major_pause_count(0)
+ _change_old_gen_for_min_pauses(0),
+ _change_young_gen_for_maj_pauses(0),
+ _old_gen_policy_is_ready(false),
+ _young_gen_size_increment_supplement(YoungGenerationSizeSupplement),
+ _old_gen_size_increment_supplement(TenuredGenerationSizeSupplement),
+ _bytes_absorbed_from_eden(0)
{
- // Sizing policy statistics
- _avg_major_pause =
- new AdaptivePaddedAverage(AdaptiveTimeWeight, PausePadding);
- _avg_minor_interval = new AdaptiveWeightedAverage(AdaptiveTimeWeight);
- _avg_major_interval = new AdaptiveWeightedAverage(AdaptiveTimeWeight);
-
- _avg_base_footprint = new AdaptiveWeightedAverage(AdaptiveSizePolicyWeight);
- _major_pause_old_estimator =
- new LinearLeastSquareFit(AdaptiveSizePolicyWeight);
- _major_pause_young_estimator =
- new LinearLeastSquareFit(AdaptiveSizePolicyWeight);
- _major_collection_estimator =
- new LinearLeastSquareFit(AdaptiveSizePolicyWeight);
-
- _young_gen_size_increment_supplement = YoungGenerationSizeSupplement;
- _old_gen_size_increment_supplement = TenuredGenerationSizeSupplement;
-
// Start the timers
_major_timer.start();
-
- _old_gen_policy_is_ready = false;
}
size_t PSAdaptiveSizePolicy::calculate_free_based_on_live(size_t live, uintx ratio_as_percentage) {
diff --git a/src/hotspot/share/gc/parallel/psAdaptiveSizePolicy.hpp b/src/hotspot/share/gc/parallel/psAdaptiveSizePolicy.hpp
index 96a2393ef94..e8f783c1c5f 100644
--- a/src/hotspot/share/gc/parallel/psAdaptiveSizePolicy.hpp
+++ b/src/hotspot/share/gc/parallel/psAdaptiveSizePolicy.hpp
@@ -75,7 +75,6 @@ class PSAdaptiveSizePolicy : public AdaptiveSizePolicy {
// Statistical data gathered for GC
GCStats _gc_stats;
- size_t _survivor_size_limit; // Limit in bytes of survivor size
const double _collection_cost_margin_fraction;
// Variable for estimating the major and minor pause times.
@@ -111,13 +110,6 @@ class PSAdaptiveSizePolicy : public AdaptiveSizePolicy {
// Flag indicating that the adaptive policy is ready to use
bool _old_gen_policy_is_ready;
- // Changing the generation sizing depends on the data that is
- // gathered about the effects of changes on the pause times and
- // throughput. These variable count the number of data points
- // gathered. The policy may use these counters as a threshold
- // for reliable data.
- julong _young_gen_change_for_major_pause_count;
-
// To facilitate faster growth at start up, supplement the normal
// growth percentage for the young gen eden and the
// old gen space for promotion with these value which decay
diff --git a/src/hotspot/share/gc/parallel/psFileBackedVirtualspace.cpp b/src/hotspot/share/gc/parallel/psFileBackedVirtualspace.cpp
index 83172401530..455049d9a92 100644
--- a/src/hotspot/share/gc/parallel/psFileBackedVirtualspace.cpp
+++ b/src/hotspot/share/gc/parallel/psFileBackedVirtualspace.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2018, 2019, Oracle and/or its affiliates. All rights reserved.
* 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,10 +51,6 @@ bool PSFileBackedVirtualSpace::initialize() {
return true;
}
-PSFileBackedVirtualSpace::PSFileBackedVirtualSpace(ReservedSpace rs, const char* path) {
- PSFileBackedVirtualSpace(rs, os::vm_page_size(), path);
-}
-
bool PSFileBackedVirtualSpace::expand_by(size_t bytes) {
assert(special(), "Since entire space is committed at initialization, _special should always be true for PSFileBackedVirtualSpace");
diff --git a/src/hotspot/share/gc/parallel/psFileBackedVirtualspace.hpp b/src/hotspot/share/gc/parallel/psFileBackedVirtualspace.hpp
index d815a1dc4e5..7f689647d0b 100644
--- a/src/hotspot/share/gc/parallel/psFileBackedVirtualspace.hpp
+++ b/src/hotspot/share/gc/parallel/psFileBackedVirtualspace.hpp
@@ -34,7 +34,6 @@ private:
bool _mapping_succeeded;
public:
PSFileBackedVirtualSpace(ReservedSpace rs, size_t alignment, const char* file_path);
- PSFileBackedVirtualSpace(ReservedSpace rs, const char* file_path);
bool initialize();
bool expand_by(size_t bytes);
diff --git a/src/hotspot/share/gc/parallel/psMarkSweepDecorator.hpp b/src/hotspot/share/gc/parallel/psMarkSweepDecorator.hpp
index ec21c287d39..8ffed5f8677 100644
--- a/src/hotspot/share/gc/parallel/psMarkSweepDecorator.hpp
+++ b/src/hotspot/share/gc/parallel/psMarkSweepDecorator.hpp
@@ -52,7 +52,11 @@ class PSMarkSweepDecorator: public CHeapObj {
public:
PSMarkSweepDecorator(MutableSpace* space, ObjectStartArray* start_array,
size_t allowed_dead_ratio) :
- _space(space), _start_array(start_array),
+ _space(space),
+ _start_array(start_array),
+ _first_dead(NULL),
+ _end_of_live(NULL),
+ _compaction_top(NULL),
_allowed_dead_ratio(allowed_dead_ratio) { }
// During a compacting collection, we need to collapse objects into
diff --git a/src/hotspot/share/gc/parallel/psParallelCompact.cpp b/src/hotspot/share/gc/parallel/psParallelCompact.cpp
index c9978f1b9b9..de1e8b3e6e5 100644
--- a/src/hotspot/share/gc/parallel/psParallelCompact.cpp
+++ b/src/hotspot/share/gc/parallel/psParallelCompact.cpp
@@ -406,19 +406,16 @@ size_t mark_bitmap_count;
size_t mark_bitmap_size;
#endif // #ifdef ASSERT
-ParallelCompactData::ParallelCompactData()
-{
- _region_start = 0;
-
- _region_vspace = 0;
- _reserved_byte_size = 0;
- _region_data = 0;
- _region_count = 0;
-
- _block_vspace = 0;
- _block_data = 0;
- _block_count = 0;
-}
+ParallelCompactData::ParallelCompactData() :
+ _region_start(NULL),
+ DEBUG_ONLY(_region_end(NULL) COMMA)
+ _region_vspace(NULL),
+ _reserved_byte_size(0),
+ _region_data(NULL),
+ _region_count(0),
+ _block_vspace(NULL),
+ _block_data(NULL),
+ _block_count(0) {}
bool ParallelCompactData::initialize(MemRegion covered_region)
{
diff --git a/src/hotspot/share/gc/parallel/psVirtualspace.cpp b/src/hotspot/share/gc/parallel/psVirtualspace.cpp
index 3572c722af1..eb52aab5c4a 100644
--- a/src/hotspot/share/gc/parallel/psVirtualspace.cpp
+++ b/src/hotspot/share/gc/parallel/psVirtualspace.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2003, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2019, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -46,7 +46,13 @@ PSVirtualSpace::PSVirtualSpace(ReservedSpace rs) :
}
// Deprecated.
-PSVirtualSpace::PSVirtualSpace(): _alignment(os::vm_page_size()) {
+PSVirtualSpace::PSVirtualSpace():
+ _alignment(os::vm_page_size()),
+ _reserved_low_addr(NULL),
+ _reserved_high_addr(NULL),
+ _committed_low_addr(NULL),
+ _committed_high_addr(NULL),
+ _special(false) {
}
// Deprecated.
diff --git a/src/hotspot/share/gc/parallel/psVirtualspace.hpp b/src/hotspot/share/gc/parallel/psVirtualspace.hpp
index aa38a271aff..8fe6a03af53 100644
--- a/src/hotspot/share/gc/parallel/psVirtualspace.hpp
+++ b/src/hotspot/share/gc/parallel/psVirtualspace.hpp
@@ -64,7 +64,14 @@ class PSVirtualSpace : public CHeapObj {
// Eventually all instances should be created with the above 1- or 2-arg
// constructors. Then the 1st constructor below should become protected and
// the 2nd ctor and initialize() removed.
- PSVirtualSpace(size_t alignment): _alignment(alignment) { }
+ PSVirtualSpace(size_t alignment):
+ _alignment(alignment),
+ _reserved_low_addr(NULL),
+ _reserved_high_addr(NULL),
+ _committed_low_addr(NULL),
+ _committed_high_addr(NULL),
+ _special(false) {
+ }
PSVirtualSpace();
bool initialize(ReservedSpace rs, size_t commit_size);
diff --git a/src/hotspot/share/gc/parallel/psYoungGen.cpp b/src/hotspot/share/gc/parallel/psYoungGen.cpp
index 72b50fa26ac..588c750acb8 100644
--- a/src/hotspot/share/gc/parallel/psYoungGen.cpp
+++ b/src/hotspot/share/gc/parallel/psYoungGen.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2001, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2001, 2019, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -35,12 +35,22 @@
#include "runtime/java.hpp"
#include "utilities/align.hpp"
-PSYoungGen::PSYoungGen(size_t initial_size,
- size_t min_size,
- size_t max_size) :
+PSYoungGen::PSYoungGen(size_t initial_size, size_t min_size, size_t max_size) :
+ _reserved(),
+ _virtual_space(NULL),
+ _eden_space(NULL),
+ _from_space(NULL),
+ _to_space(NULL),
+ _eden_mark_sweep(NULL),
+ _from_mark_sweep(NULL),
+ _to_mark_sweep(NULL),
_init_gen_size(initial_size),
_min_gen_size(min_size),
- _max_gen_size(max_size)
+ _max_gen_size(max_size),
+ _gen_counters(NULL),
+ _eden_counters(NULL),
+ _from_counters(NULL),
+ _to_counters(NULL)
{}
void PSYoungGen::initialize_virtual_space(ReservedSpace rs, size_t alignment) {
diff --git a/src/hotspot/share/gc/shared/adaptiveSizePolicy.cpp b/src/hotspot/share/gc/shared/adaptiveSizePolicy.cpp
index 067f5d52ae0..5895652065f 100644
--- a/src/hotspot/share/gc/shared/adaptiveSizePolicy.cpp
+++ b/src/hotspot/share/gc/shared/adaptiveSizePolicy.cpp
@@ -48,40 +48,38 @@ AdaptiveSizePolicy::AdaptiveSizePolicy(size_t init_eden_size,
_eden_size(init_eden_size),
_promo_size(init_promo_size),
_survivor_size(init_survivor_size),
+ _avg_minor_pause(new AdaptivePaddedAverage(AdaptiveTimeWeight, PausePadding)),
+ _avg_minor_interval(new AdaptiveWeightedAverage(AdaptiveTimeWeight)),
+ _avg_minor_gc_cost(new AdaptiveWeightedAverage(AdaptiveTimeWeight)),
+ _avg_major_interval(new AdaptiveWeightedAverage(AdaptiveTimeWeight)),
+ _avg_major_gc_cost(new AdaptiveWeightedAverage(AdaptiveTimeWeight)),
+ _avg_young_live(new AdaptiveWeightedAverage(AdaptiveSizePolicyWeight)),
+ _avg_eden_live(new AdaptiveWeightedAverage(AdaptiveSizePolicyWeight)),
+ _avg_old_live(new AdaptiveWeightedAverage(AdaptiveSizePolicyWeight)),
+ _avg_survived(new AdaptivePaddedAverage(AdaptiveSizePolicyWeight, SurvivorPadding)),
+ _avg_pretenured(new AdaptivePaddedNoZeroDevAverage(AdaptiveSizePolicyWeight, SurvivorPadding)),
+ _minor_pause_old_estimator(new LinearLeastSquareFit(AdaptiveSizePolicyWeight)),
+ _minor_pause_young_estimator(new LinearLeastSquareFit(AdaptiveSizePolicyWeight)),
+ _minor_collection_estimator(new LinearLeastSquareFit(AdaptiveSizePolicyWeight)),
+ _major_collection_estimator(new LinearLeastSquareFit(AdaptiveSizePolicyWeight)),
_latest_minor_mutator_interval_seconds(0),
_threshold_tolerance_percent(1.0 + ThresholdTolerance/100.0),
_gc_pause_goal_sec(gc_pause_goal_sec),
+ _young_gen_policy_is_ready(false),
+ _change_young_gen_for_min_pauses(0),
+ _change_old_gen_for_maj_pauses(0),
+ _change_old_gen_for_throughput(0),
+ _change_young_gen_for_throughput(0),
+ _increment_tenuring_threshold_for_gc_cost(false),
+ _decrement_tenuring_threshold_for_gc_cost(false),
+ _decrement_tenuring_threshold_for_survivor_limit(false),
+ _decrease_for_footprint(0),
+ _decide_at_full_gc(0),
_young_gen_change_for_minor_throughput(0),
_old_gen_change_for_major_throughput(0) {
- _avg_minor_pause =
- new AdaptivePaddedAverage(AdaptiveTimeWeight, PausePadding);
- _avg_minor_interval = new AdaptiveWeightedAverage(AdaptiveTimeWeight);
- _avg_minor_gc_cost = new AdaptiveWeightedAverage(AdaptiveTimeWeight);
- _avg_major_gc_cost = new AdaptiveWeightedAverage(AdaptiveTimeWeight);
-
- _avg_young_live = new AdaptiveWeightedAverage(AdaptiveSizePolicyWeight);
- _avg_old_live = new AdaptiveWeightedAverage(AdaptiveSizePolicyWeight);
- _avg_eden_live = new AdaptiveWeightedAverage(AdaptiveSizePolicyWeight);
-
- _avg_survived = new AdaptivePaddedAverage(AdaptiveSizePolicyWeight,
- SurvivorPadding);
- _avg_pretenured = new AdaptivePaddedNoZeroDevAverage(
- AdaptiveSizePolicyWeight,
- SurvivorPadding);
-
- _minor_pause_old_estimator =
- new LinearLeastSquareFit(AdaptiveSizePolicyWeight);
- _minor_pause_young_estimator =
- new LinearLeastSquareFit(AdaptiveSizePolicyWeight);
- _minor_collection_estimator =
- new LinearLeastSquareFit(AdaptiveSizePolicyWeight);
- _major_collection_estimator =
- new LinearLeastSquareFit(AdaptiveSizePolicyWeight);
// Start the timers
_minor_timer.start();
-
- _young_gen_policy_is_ready = false;
}
bool AdaptiveSizePolicy::tenuring_threshold_change() const {
diff --git a/src/hotspot/share/gc/shared/barrierSet.hpp b/src/hotspot/share/gc/shared/barrierSet.hpp
index 34ae5416574..52b575078e4 100644
--- a/src/hotspot/share/gc/shared/barrierSet.hpp
+++ b/src/hotspot/share/gc/shared/barrierSet.hpp
@@ -130,8 +130,18 @@ public:
virtual void on_slowpath_allocation_exit(JavaThread* thread, oop new_obj) {}
virtual void on_thread_create(Thread* thread) {}
virtual void on_thread_destroy(Thread* thread) {}
+
+ // These perform BarrierSet-related initialization/cleanup before the thread
+ // is added to or removed from the corresponding set of threads. The
+ // argument thread is the current thread. These are called either holding
+ // the Threads_lock (for a JavaThread) and so not at a safepoint, or holding
+ // the NonJavaThreadsList_lock (for a NonJavaThread) locked by the
+ // caller. That locking ensures the operation is "atomic" with the list
+ // modification wrto operations that hold the NJTList_lock and either also
+ // hold the Threads_lock or are at a safepoint.
virtual void on_thread_attach(Thread* thread) {}
virtual void on_thread_detach(Thread* thread) {}
+
virtual void make_parsable(JavaThread* thread) {}
#ifdef CHECK_UNHANDLED_OOPS
diff --git a/src/hotspot/share/gc/shared/collectedHeap.hpp b/src/hotspot/share/gc/shared/collectedHeap.hpp
index c8277bbfb1f..0bff3f002cd 100644
--- a/src/hotspot/share/gc/shared/collectedHeap.hpp
+++ b/src/hotspot/share/gc/shared/collectedHeap.hpp
@@ -510,11 +510,11 @@ class CollectedHeap : public CHeapObj {
void print_heap_after_gc();
// Registering and unregistering an nmethod (compiled code) with the heap.
- // Override with specific mechanism for each specialized heap type.
- virtual void register_nmethod(nmethod* nm) {}
- virtual void unregister_nmethod(nmethod* nm) {}
- virtual void flush_nmethod(nmethod* nm) {}
- virtual void verify_nmethod(nmethod* nmethod) {}
+ virtual void register_nmethod(nmethod* nm) = 0;
+ virtual void unregister_nmethod(nmethod* nm) = 0;
+ // Callback for when nmethod is about to be deleted.
+ virtual void flush_nmethod(nmethod* nm) = 0;
+ virtual void verify_nmethod(nmethod* nm) = 0;
void trace_heap_before_gc(const GCTracer* gc_tracer);
void trace_heap_after_gc(const GCTracer* gc_tracer);
diff --git a/src/hotspot/share/gc/shared/concurrentGCThread.cpp b/src/hotspot/share/gc/shared/concurrentGCThread.cpp
index 7209ba28760..6b1c119cda2 100644
--- a/src/hotspot/share/gc/shared/concurrentGCThread.cpp
+++ b/src/hotspot/share/gc/shared/concurrentGCThread.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2001, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2001, 2019, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -23,79 +23,58 @@
*/
#include "precompiled.hpp"
-#include "classfile/systemDictionary.hpp"
#include "gc/shared/concurrentGCThread.hpp"
-#include "oops/instanceRefKlass.hpp"
-#include "oops/oop.inline.hpp"
#include "runtime/init.hpp"
-#include "runtime/java.hpp"
-#include "runtime/javaCalls.hpp"
+#include "runtime/mutexLocker.hpp"
+#include "runtime/orderAccess.hpp"
#include "runtime/os.hpp"
ConcurrentGCThread::ConcurrentGCThread() :
- _should_terminate(false), _has_terminated(false) {
-};
+ _should_terminate(false),
+ _has_terminated(false) {}
void ConcurrentGCThread::create_and_start(ThreadPriority prio) {
if (os::create_thread(this, os::cgc_thread)) {
- // XXX: need to set this to low priority
- // unless "aggressive mode" set; priority
- // should be just less than that of VMThread.
os::set_priority(this, prio);
- if (!_should_terminate) {
- os::start_thread(this);
- }
- }
-}
-
-void ConcurrentGCThread::initialize_in_thread() {
- this->set_active_handles(JNIHandleBlock::allocate_block());
- // From this time Thread::current() should be working.
- assert(this == Thread::current(), "just checking");
-}
-
-void ConcurrentGCThread::wait_for_universe_init() {
- MutexLockerEx x(CGC_lock, Mutex::_no_safepoint_check_flag);
- while (!is_init_completed() && !_should_terminate) {
- CGC_lock->wait(Mutex::_no_safepoint_check_flag, 1);
- }
-}
-
-void ConcurrentGCThread::terminate() {
- assert(_should_terminate, "Should only be called on terminate request.");
- // Signal that it is terminated
- {
- MutexLockerEx mu(Terminator_lock,
- Mutex::_no_safepoint_check_flag);
- _has_terminated = true;
- Terminator_lock->notify();
+ os::start_thread(this);
}
}
void ConcurrentGCThread::run() {
- initialize_in_thread();
- wait_for_universe_init();
+ // Setup handle area
+ set_active_handles(JNIHandleBlock::allocate_block());
+
+ // Wait for initialization to complete
+ wait_init_completed();
run_service();
- terminate();
+ // Signal thread has terminated
+ MonitorLockerEx ml(Terminator_lock);
+ OrderAccess::release_store(&_has_terminated, true);
+ ml.notify_all();
}
void ConcurrentGCThread::stop() {
- // it is ok to take late safepoints here, if needed
- {
- MutexLockerEx mu(Terminator_lock);
- assert(!_has_terminated, "stop should only be called once");
- assert(!_should_terminate, "stop should only be called once");
- _should_terminate = true;
- }
+ assert(!should_terminate(), "Invalid state");
+ assert(!has_terminated(), "Invalid state");
+
+ // Signal thread to terminate
+ OrderAccess::release_store_fence(&_should_terminate, true);
stop_service();
- {
- MutexLockerEx mu(Terminator_lock);
- while (!_has_terminated) {
- Terminator_lock->wait();
- }
+ // Wait for thread to terminate
+ MonitorLockerEx ml(Terminator_lock);
+ while (!_has_terminated) {
+ ml.wait();
}
}
+
+bool ConcurrentGCThread::should_terminate() const {
+ return OrderAccess::load_acquire(&_should_terminate);
+}
+
+bool ConcurrentGCThread::has_terminated() const {
+ return OrderAccess::load_acquire(&_has_terminated);
+}
diff --git a/src/hotspot/share/gc/shared/concurrentGCThread.hpp b/src/hotspot/share/gc/shared/concurrentGCThread.hpp
index 36d7371c7a8..021fdd76498 100644
--- a/src/hotspot/share/gc/shared/concurrentGCThread.hpp
+++ b/src/hotspot/share/gc/shared/concurrentGCThread.hpp
@@ -26,48 +26,28 @@
#define SHARE_GC_SHARED_CONCURRENTGCTHREAD_HPP
#include "runtime/thread.hpp"
-#include "utilities/macros.hpp"
class ConcurrentGCThread: public NamedThread {
- friend class VMStructs;
-
- bool volatile _should_terminate;
- bool _has_terminated;
-
- // Do initialization steps in the thread: record stack base and size,
- // init thread local storage, set JNI handle block.
- void initialize_in_thread();
-
- // Wait until Universe::is_fully_initialized();
- void wait_for_universe_init();
-
- // Record that the current thread is terminating, and will do more
- // concurrent work.
- void terminate();
+private:
+ volatile bool _should_terminate;
+ volatile bool _has_terminated;
protected:
- // Create and start the thread (setting it's priority.)
void create_and_start(ThreadPriority prio = NearMaxPriority);
- // Do the specific GC work. Called by run() after initialization complete.
virtual void run_service() = 0;
-
- // Shut down the specific GC work. Called by stop() as part of termination protocol.
- virtual void stop_service() = 0;
+ virtual void stop_service() = 0;
public:
ConcurrentGCThread();
- // Tester
- bool is_ConcurrentGC_thread() const { return true; }
+ virtual bool is_ConcurrentGC_thread() const { return true; }
virtual void run();
-
- // shutdown following termination protocol
virtual void stop();
- bool should_terminate() { return _should_terminate; }
- bool has_terminated() { return _has_terminated; }
+ bool should_terminate() const;
+ bool has_terminated() const;
};
#endif // SHARE_GC_SHARED_CONCURRENTGCTHREAD_HPP
diff --git a/src/hotspot/share/gc/shared/gcStats.cpp b/src/hotspot/share/gc/shared/gcStats.cpp
index 4e26a83e3ee..55514d91fd0 100644
--- a/src/hotspot/share/gc/shared/gcStats.cpp
+++ b/src/hotspot/share/gc/shared/gcStats.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2003, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2019, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -26,8 +26,4 @@
#include "gc/shared/gcStats.hpp"
#include "gc/shared/gcUtil.inline.hpp"
-GCStats::GCStats() {
- _avg_promoted = new AdaptivePaddedNoZeroDevAverage(
- AdaptiveSizePolicyWeight,
- PromotedPadding);
-}
+GCStats::GCStats() : _avg_promoted(new AdaptivePaddedNoZeroDevAverage(AdaptiveSizePolicyWeight, PromotedPadding)) {}
diff --git a/src/hotspot/share/gc/shared/ptrQueue.cpp b/src/hotspot/share/gc/shared/ptrQueue.cpp
index 25d6cc662c5..401828eea50 100644
--- a/src/hotspot/share/gc/shared/ptrQueue.cpp
+++ b/src/hotspot/share/gc/shared/ptrQueue.cpp
@@ -36,18 +36,16 @@
#include
-PtrQueue::PtrQueue(PtrQueueSet* qset, bool permanent, bool active) :
+PtrQueue::PtrQueue(PtrQueueSet* qset, bool active) :
_qset(qset),
_active(active),
- _permanent(permanent),
_index(0),
_capacity_in_bytes(0),
- _buf(NULL),
- _lock(NULL)
+ _buf(NULL)
{}
PtrQueue::~PtrQueue() {
- assert(_permanent || (_buf == NULL), "queue must be flushed before delete");
+ assert(_buf == NULL, "queue must be flushed before delete");
}
void PtrQueue::flush_impl() {
@@ -271,23 +269,13 @@ void PtrQueue::handle_zero_index() {
return;
}
- if (_lock) {
- assert(_lock->owned_by_self(), "Required.");
-
- BufferNode* node = BufferNode::make_node_from_buffer(_buf, index());
- _buf = NULL; // clear shared _buf field
-
- qset()->enqueue_completed_buffer(node);
- assert(_buf == NULL, "multiple enqueuers appear to be racing");
- } else {
- BufferNode* node = BufferNode::make_node_from_buffer(_buf, index());
- if (qset()->process_or_enqueue_completed_buffer(node)) {
- // Recycle the buffer. No allocation.
- assert(_buf == BufferNode::make_buffer_from_node(node), "invariant");
- assert(capacity() == qset()->buffer_size(), "invariant");
- reset();
- return;
- }
+ BufferNode* node = BufferNode::make_node_from_buffer(_buf, index());
+ if (qset()->process_or_enqueue_completed_buffer(node)) {
+ // Recycle the buffer. No allocation.
+ assert(_buf == BufferNode::make_buffer_from_node(node), "invariant");
+ assert(capacity() == qset()->buffer_size(), "invariant");
+ reset();
+ return;
}
}
// Set capacity in case this is the first allocation.
diff --git a/src/hotspot/share/gc/shared/ptrQueue.hpp b/src/hotspot/share/gc/shared/ptrQueue.hpp
index 06a20981a4b..b87a58bae4a 100644
--- a/src/hotspot/share/gc/shared/ptrQueue.hpp
+++ b/src/hotspot/share/gc/shared/ptrQueue.hpp
@@ -54,11 +54,6 @@ class PtrQueue {
// Whether updates should be logged.
bool _active;
- // If true, the queue is permanent, and doesn't need to deallocate
- // its buffer in the destructor (since that obtains a lock which may not
- // be legally locked by then.
- const bool _permanent;
-
// The (byte) index at which an object was last enqueued. Starts at
// capacity_in_bytes (indicating an empty buffer) and goes towards zero.
// Value is always pointer-size aligned.
@@ -111,27 +106,20 @@ protected:
return byte_index_to_index(capacity_in_bytes());
}
- // If there is a lock associated with this buffer, this is that lock.
- Mutex* _lock;
-
PtrQueueSet* qset() { return _qset; }
- bool is_permanent() const { return _permanent; }
// Process queue entries and release resources.
void flush_impl();
// Initialize this queue to contain a null buffer, and be part of the
// given PtrQueueSet.
- PtrQueue(PtrQueueSet* qset, bool permanent = false, bool active = false);
+ PtrQueue(PtrQueueSet* qset, bool active = false);
- // Requires queue flushed or permanent.
+ // Requires queue flushed.
~PtrQueue();
public:
- // Associate a lock with a ptr queue.
- void set_lock(Mutex* lock) { _lock = lock; }
-
// Forcibly set empty.
void reset() {
if (_buf != NULL) {
diff --git a/src/hotspot/share/gc/shared/satbMarkQueue.cpp b/src/hotspot/share/gc/shared/satbMarkQueue.cpp
index bd853a82269..0a827c1b40c 100644
--- a/src/hotspot/share/gc/shared/satbMarkQueue.cpp
+++ b/src/hotspot/share/gc/shared/satbMarkQueue.cpp
@@ -35,14 +35,14 @@
#include "runtime/threadSMR.hpp"
#include "runtime/vmThread.hpp"
-SATBMarkQueue::SATBMarkQueue(SATBMarkQueueSet* qset, bool permanent) :
+SATBMarkQueue::SATBMarkQueue(SATBMarkQueueSet* qset) :
// SATB queues are only active during marking cycles. We create
// them with their active field set to false. If a thread is
// created during a cycle and its SATB queue needs to be activated
// before the thread starts running, we'll need to set its active
// field to true. This must be done in the collector-specific
// BarrierSet thread attachment protocol.
- PtrQueue(qset, permanent, false /* active */)
+ PtrQueue(qset, false /* active */)
{ }
void SATBMarkQueue::flush() {
@@ -170,7 +170,11 @@ void SATBMarkQueueSet::set_active_all_threads(bool active, bool expected_active)
#ifdef ASSERT
verify_active_states(expected_active);
#endif // ASSERT
- _all_active = active;
+ // Update the global state, synchronized with threads list management.
+ {
+ MutexLockerEx ml(NonJavaThreadsList_lock, Mutex::_no_safepoint_check_flag);
+ _all_active = active;
+ }
class SetThreadActiveClosure : public ThreadClosure {
SATBMarkQueueSet* _qset;
diff --git a/src/hotspot/share/gc/shared/satbMarkQueue.hpp b/src/hotspot/share/gc/shared/satbMarkQueue.hpp
index 945e953d309..8ffe9170cb5 100644
--- a/src/hotspot/share/gc/shared/satbMarkQueue.hpp
+++ b/src/hotspot/share/gc/shared/satbMarkQueue.hpp
@@ -55,7 +55,7 @@ private:
inline void apply_filter(Filter filter_out);
public:
- SATBMarkQueue(SATBMarkQueueSet* qset, bool permanent = false);
+ SATBMarkQueue(SATBMarkQueueSet* qset);
// Process queue entries and free resources.
void flush();
diff --git a/src/hotspot/share/gc/shenandoah/c2/shenandoahSupport.cpp b/src/hotspot/share/gc/shenandoah/c2/shenandoahSupport.cpp
index bae90b6a0d4..709209859bf 100644
--- a/src/hotspot/share/gc/shenandoah/c2/shenandoahSupport.cpp
+++ b/src/hotspot/share/gc/shenandoah/c2/shenandoahSupport.cpp
@@ -682,7 +682,7 @@ uint ShenandoahBarrierNode::hash() const {
return TypeNode::hash() + _allow_fromspace;
}
-uint ShenandoahBarrierNode::cmp(const Node& n) const {
+bool ShenandoahBarrierNode::cmp(const Node& n) const {
return _allow_fromspace == ((ShenandoahBarrierNode&) n)._allow_fromspace
&& TypeNode::cmp(n);
}
@@ -3400,6 +3400,7 @@ const Type* ShenandoahEnqueueBarrierNode::Value(PhaseGVN* phase) const {
int ShenandoahEnqueueBarrierNode::needed(Node* n) {
if (n == NULL ||
n->is_Allocate() ||
+ n->Opcode() == Op_ShenandoahEnqueueBarrier ||
n->bottom_type() == TypePtr::NULL_PTR ||
(n->bottom_type()->make_oopptr() != NULL && n->bottom_type()->make_oopptr()->const_oop() != NULL)) {
return NotNeeded;
diff --git a/src/hotspot/share/gc/shenandoah/c2/shenandoahSupport.hpp b/src/hotspot/share/gc/shenandoah/c2/shenandoahSupport.hpp
index 7ed9ab536e9..02caf091f20 100644
--- a/src/hotspot/share/gc/shenandoah/c2/shenandoahSupport.hpp
+++ b/src/hotspot/share/gc/shenandoah/c2/shenandoahSupport.hpp
@@ -120,7 +120,7 @@ public:
protected:
uint hash() const;
- uint cmp(const Node& n) const;
+ bool cmp(const Node& n) const;
uint size_of() const;
private:
diff --git a/src/hotspot/share/gc/shenandoah/shenandoahArguments.cpp b/src/hotspot/share/gc/shenandoah/shenandoahArguments.cpp
index 907a91a58bb..caefc0605e5 100644
--- a/src/hotspot/share/gc/shenandoah/shenandoahArguments.cpp
+++ b/src/hotspot/share/gc/shenandoah/shenandoahArguments.cpp
@@ -135,18 +135,6 @@ void ShenandoahArguments::initialize() {
FLAG_SET_DEFAULT(ShenandoahAlwaysPreTouch, true);
}
- // Shenandoah C2 optimizations apparently dislike the shape of thread-local handshakes.
- // Disable it by default, unless we enable it specifically for debugging.
- if (FLAG_IS_DEFAULT(ThreadLocalHandshakes)) {
- if (ThreadLocalHandshakes) {
- FLAG_SET_DEFAULT(ThreadLocalHandshakes, false);
- }
- } else {
- if (ThreadLocalHandshakes) {
- warning("Thread-local handshakes are not working correctly with Shenandoah at the moment. Enable at your own risk.");
- }
- }
-
// Record more information about previous cycles for improved debugging pleasure
if (FLAG_IS_DEFAULT(LogEventsBufferEntries)) {
FLAG_SET_DEFAULT(LogEventsBufferEntries, 250);
diff --git a/src/hotspot/share/gc/shenandoah/shenandoahConcurrentMark.cpp b/src/hotspot/share/gc/shenandoah/shenandoahConcurrentMark.cpp
index b980a5457d4..7d8d979c2d1 100644
--- a/src/hotspot/share/gc/shenandoah/shenandoahConcurrentMark.cpp
+++ b/src/hotspot/share/gc/shenandoah/shenandoahConcurrentMark.cpp
@@ -36,7 +36,7 @@
#include "gc/shenandoah/shenandoahConcurrentMark.inline.hpp"
#include "gc/shenandoah/shenandoahMarkCompact.hpp"
#include "gc/shenandoah/shenandoahHeap.inline.hpp"
-#include "gc/shenandoah/shenandoahRootProcessor.hpp"
+#include "gc/shenandoah/shenandoahRootProcessor.inline.hpp"
#include "gc/shenandoah/shenandoahOopClosures.inline.hpp"
#include "gc/shenandoah/shenandoahTaskqueue.inline.hpp"
#include "gc/shenandoah/shenandoahTimingTracker.hpp"
@@ -120,11 +120,10 @@ private:
CLDToOopClosure clds_cl(oops, ClassLoaderData::_claim_strong);
MarkingCodeBlobClosure blobs_cl(oops, ! CodeBlobToOopClosure::FixRelocations);
- OopClosure* weak_oops = _process_refs ? NULL : oops;
ResourceMark m;
if (heap->unload_classes()) {
- _rp->process_strong_roots(oops, weak_oops, &clds_cl, NULL, &blobs_cl, NULL, worker_id);
+ _rp->process_strong_roots(oops, &clds_cl, &blobs_cl, NULL, worker_id);
} else {
if (ShenandoahConcurrentScanCodeRoots) {
CodeBlobClosure* code_blobs = NULL;
@@ -137,9 +136,9 @@ private:
code_blobs = &assert_to_space;
}
#endif
- _rp->process_all_roots(oops, weak_oops, &clds_cl, code_blobs, NULL, worker_id);
+ _rp->process_all_roots(oops, &clds_cl, code_blobs, NULL, worker_id);
} else {
- _rp->process_all_roots(oops, weak_oops, &clds_cl, &blobs_cl, NULL, worker_id);
+ _rp->process_all_roots(oops, &clds_cl, &blobs_cl, NULL, worker_id);
}
}
}
@@ -177,7 +176,7 @@ public:
DEBUG_ONLY(&assert_to_space)
NOT_DEBUG(NULL);
}
- _rp->process_all_roots(&cl, &cl, &cldCl, code_blobs, NULL, worker_id);
+ _rp->update_all_roots(&cl, &cldCl, code_blobs, NULL, worker_id);
}
};
@@ -446,11 +445,16 @@ void ShenandoahConcurrentMark::finish_mark_from_roots(bool full_gc) {
weak_refs_work(full_gc);
}
+ weak_roots_work();
+
// And finally finish class unloading
if (_heap->unload_classes()) {
_heap->unload_classes_and_cleanup_tables(full_gc);
+ } else if (ShenandoahStringDedup::is_enabled()) {
+ ShenandoahIsAliveSelector alive;
+ BoolObjectClosure* is_alive = alive.is_alive_closure();
+ ShenandoahStringDedup::unlink_or_oops_do(is_alive, NULL, false);
}
-
assert(task_queues()->is_empty(), "Should be empty");
TASKQUEUE_STATS_ONLY(task_queues()->print_taskqueue_stats());
TASKQUEUE_STATS_ONLY(task_queues()->reset_taskqueue_stats());
@@ -555,11 +559,13 @@ class ShenandoahWeakAssertNotForwardedClosure : public OopClosure {
private:
template
inline void do_oop_work(T* p) {
+#ifdef ASSERT
T o = RawAccess<>::oop_load(p);
if (!CompressedOops::is_null(o)) {
oop obj = CompressedOops::decode_not_null(o);
shenandoah_assert_not_forwarded(p, obj);
}
+#endif
}
public:
@@ -648,6 +654,23 @@ void ShenandoahConcurrentMark::weak_refs_work(bool full_gc) {
}
+// Process leftover weak oops: update them, if needed or assert they do not
+// need updating otherwise.
+// Weak processor API requires us to visit the oops, even if we are not doing
+// anything to them.
+void ShenandoahConcurrentMark::weak_roots_work() {
+ WorkGang* workers = _heap->workers();
+ ShenandoahIsAliveSelector is_alive;
+
+ if (_heap->has_forwarded_objects()) {
+ ShenandoahWeakUpdateClosure cl;
+ WeakProcessor::weak_oops_do(workers, is_alive.is_alive_closure(), &cl, 1);
+ } else {
+ ShenandoahWeakAssertNotForwardedClosure cl;
+ WeakProcessor::weak_oops_do(workers, is_alive.is_alive_closure(), &cl, 1);
+ }
+}
+
void ShenandoahConcurrentMark::weak_refs_work_doit(bool full_gc) {
ReferenceProcessor* rp = _heap->ref_processor();
@@ -689,26 +712,18 @@ void ShenandoahConcurrentMark::weak_refs_work_doit(bool full_gc) {
ShenandoahGCPhase phase(phase_process);
ShenandoahTerminationTracker phase_term(phase_process_termination);
- // Process leftover weak oops: update them, if needed (using parallel version),
- // or assert they do not need updating (using serial version) otherwise.
- // Weak processor API requires us to visit the oops, even if we are not doing
- // anything to them.
if (_heap->has_forwarded_objects()) {
ShenandoahCMKeepAliveUpdateClosure keep_alive(get_queue(serial_worker_id));
rp->process_discovered_references(is_alive.is_alive_closure(), &keep_alive,
&complete_gc, &executor,
&pt);
- ShenandoahWeakUpdateClosure cl;
- WeakProcessor::weak_oops_do(workers, is_alive.is_alive_closure(), &cl, 1);
} else {
ShenandoahCMKeepAliveClosure keep_alive(get_queue(serial_worker_id));
rp->process_discovered_references(is_alive.is_alive_closure(), &keep_alive,
&complete_gc, &executor,
&pt);
- ShenandoahWeakAssertNotForwardedClosure cl;
- WeakProcessor::weak_oops_do(is_alive.is_alive_closure(), &cl);
}
pt.print_all_references();
diff --git a/src/hotspot/share/gc/shenandoah/shenandoahConcurrentMark.hpp b/src/hotspot/share/gc/shenandoah/shenandoahConcurrentMark.hpp
index 4e25aa4fb70..f16da74fe06 100644
--- a/src/hotspot/share/gc/shenandoah/shenandoahConcurrentMark.hpp
+++ b/src/hotspot/share/gc/shenandoah/shenandoahConcurrentMark.hpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2013, 2018, Red Hat, Inc. All rights reserved.
+ * Copyright (c) 2013, 2019, Red Hat, Inc. All rights reserved.
*
* 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
@@ -86,6 +86,8 @@ private:
void weak_refs_work(bool full_gc);
void weak_refs_work_doit(bool full_gc);
+ void weak_roots_work();
+
public:
void preclean_weak_refs();
diff --git a/src/hotspot/share/gc/shenandoah/shenandoahHeap.cpp b/src/hotspot/share/gc/shenandoah/shenandoahHeap.cpp
index 80669994aec..e5cd812f81e 100644
--- a/src/hotspot/share/gc/shenandoah/shenandoahHeap.cpp
+++ b/src/hotspot/share/gc/shenandoah/shenandoahHeap.cpp
@@ -1127,16 +1127,6 @@ void ShenandoahHeap::evacuate_and_update_roots() {
#endif
}
-void ShenandoahHeap::roots_iterate(OopClosure* cl) {
- assert(ShenandoahSafepoint::is_at_shenandoah_safepoint(), "Only iterate roots while world is stopped");
-
- CodeBlobToOopClosure blobsCl(cl, false);
- CLDToOopClosure cldCl(cl, ClassLoaderData::_claim_strong);
-
- ShenandoahRootProcessor rp(this, 1, ShenandoahPhaseTimings::_num_phases);
- rp.process_all_roots(cl, NULL, &cldCl, &blobsCl, NULL, 0);
-}
-
// Returns size in bytes
size_t ShenandoahHeap::unsafe_max_tlab_alloc(Thread *thread) const {
if (ShenandoahElasticTLAB) {
@@ -1337,7 +1327,7 @@ void ShenandoahHeap::object_iterate(ObjectClosure* cl) {
ObjectIterateScanRootClosure oops(&_aux_bit_map, &oop_stack);
CLDToOopClosure clds(&oops, ClassLoaderData::_claim_none);
CodeBlobToOopClosure blobs(&oops, false);
- rp.process_all_roots(&oops, &oops, &clds, &blobs, NULL, 0);
+ rp.process_all_roots(&oops, &clds, &blobs, NULL, 0);
// Work through the oop stack to traverse heap.
while (! oop_stack.is_empty()) {
diff --git a/src/hotspot/share/gc/shenandoah/shenandoahHeap.hpp b/src/hotspot/share/gc/shenandoah/shenandoahHeap.hpp
index f7006367fde..4d882ea719f 100644
--- a/src/hotspot/share/gc/shenandoah/shenandoahHeap.hpp
+++ b/src/hotspot/share/gc/shenandoah/shenandoahHeap.hpp
@@ -584,6 +584,8 @@ public:
public:
void register_nmethod(nmethod* nm);
void unregister_nmethod(nmethod* nm);
+ void flush_nmethod(nmethod* nm) {}
+ void verify_nmethod(nmethod* nm) {}
// ---------- Pinning hooks
//
@@ -742,8 +744,6 @@ public:
void stop_concurrent_marking();
- void roots_iterate(OopClosure* cl);
-
private:
void trash_cset_regions();
void update_heap_references(bool concurrent);
diff --git a/src/hotspot/share/gc/shenandoah/shenandoahMarkCompact.cpp b/src/hotspot/share/gc/shenandoah/shenandoahMarkCompact.cpp
index 206a43f0617..b67af972f1e 100644
--- a/src/hotspot/share/gc/shenandoah/shenandoahMarkCompact.cpp
+++ b/src/hotspot/share/gc/shenandoah/shenandoahMarkCompact.cpp
@@ -35,7 +35,7 @@
#include "gc/shenandoah/shenandoahHeap.inline.hpp"
#include "gc/shenandoah/shenandoahHeuristics.hpp"
#include "gc/shenandoah/shenandoahMarkingContext.inline.hpp"
-#include "gc/shenandoah/shenandoahRootProcessor.hpp"
+#include "gc/shenandoah/shenandoahRootProcessor.inline.hpp"
#include "gc/shenandoah/shenandoahTraversalGC.hpp"
#include "gc/shenandoah/shenandoahTaskqueue.inline.hpp"
#include "gc/shenandoah/shenandoahUtils.hpp"
@@ -572,9 +572,9 @@ public:
MarkingCodeBlobClosure adjust_code_closure(&cl,
CodeBlobToOopClosure::FixRelocations);
- _rp->process_all_roots(&cl, &cl,
- &adjust_cld_closure,
- &adjust_code_closure, NULL, worker_id);
+ _rp->update_all_roots(&cl,
+ &adjust_cld_closure,
+ &adjust_code_closure, NULL, worker_id);
}
};
diff --git a/src/hotspot/share/gc/shenandoah/shenandoahRootProcessor.cpp b/src/hotspot/share/gc/shenandoah/shenandoahRootProcessor.cpp
index 783115be395..62e38518681 100644
--- a/src/hotspot/share/gc/shenandoah/shenandoahRootProcessor.cpp
+++ b/src/hotspot/share/gc/shenandoah/shenandoahRootProcessor.cpp
@@ -119,14 +119,9 @@ void ShenandoahRootProcessor::process_all_roots_slow(OopClosure* oops) {
Management::oops_do(oops);
JvmtiExport::oops_do(oops);
JNIHandles::oops_do(oops);
- WeakProcessor::oops_do(oops);
ObjectSynchronizer::oops_do(oops);
SystemDictionary::oops_do(oops);
- if (ShenandoahStringDedup::is_enabled()) {
- ShenandoahStringDedup::oops_do_slow(oops);
- }
-
// Do thread roots the last. This allows verification code to find
// any broken objects from those special roots first, not the accidental
// dangling reference from the thread root.
@@ -134,21 +129,18 @@ void ShenandoahRootProcessor::process_all_roots_slow(OopClosure* oops) {
}
void ShenandoahRootProcessor::process_strong_roots(OopClosure* oops,
- OopClosure* weak_oops,
CLDClosure* clds,
- CLDClosure* weak_clds,
CodeBlobClosure* blobs,
ThreadClosure* thread_cl,
uint worker_id) {
- process_java_roots(oops, clds, weak_clds, blobs, thread_cl, worker_id);
- process_vm_roots(oops, NULL, weak_oops, worker_id);
+ process_java_roots(oops, clds, NULL, blobs, thread_cl, worker_id);
+ process_vm_roots(oops, worker_id);
_process_strong_tasks->all_tasks_completed(n_workers());
}
void ShenandoahRootProcessor::process_all_roots(OopClosure* oops,
- OopClosure* weak_oops,
CLDClosure* clds,
CodeBlobClosure* blobs,
ThreadClosure* thread_cl,
@@ -156,7 +148,7 @@ void ShenandoahRootProcessor::process_all_roots(OopClosure* oops,
ShenandoahWorkerTimings* worker_times = ShenandoahHeap::heap()->phase_timings()->worker_times();
process_java_roots(oops, clds, clds, blobs, thread_cl, worker_id);
- process_vm_roots(oops, oops, weak_oops, worker_id);
+ process_vm_roots(oops, worker_id);
if (blobs != NULL) {
ShenandoahWorkerTimingsTracker timer(worker_times, ShenandoahPhaseTimings::CodeCacheRoots, worker_id);
@@ -164,6 +156,7 @@ void ShenandoahRootProcessor::process_all_roots(OopClosure* oops,
}
_process_strong_tasks->all_tasks_completed(n_workers());
+
}
class ShenandoahParallelOopsDoThreadClosure : public ThreadClosure {
@@ -209,10 +202,7 @@ void ShenandoahRootProcessor::process_java_roots(OopClosure* strong_roots,
}
void ShenandoahRootProcessor::process_vm_roots(OopClosure* strong_roots,
- OopClosure* weak_roots,
- OopClosure* jni_weak_roots,
- uint worker_id)
-{
+ uint worker_id) {
ShenandoahWorkerTimings* worker_times = ShenandoahHeap::heap()->phase_timings()->worker_times();
if (_process_strong_tasks->try_claim_task(SHENANDOAH_RP_PS_Universe_oops_do)) {
ShenandoahWorkerTimingsTracker timer(worker_times, ShenandoahPhaseTimings::UniverseRoots, worker_id);
@@ -235,15 +225,6 @@ void ShenandoahRootProcessor::process_vm_roots(OopClosure* strong_roots,
ShenandoahWorkerTimingsTracker timer(worker_times, ShenandoahPhaseTimings::SystemDictionaryRoots, worker_id);
SystemDictionary::oops_do(strong_roots);
}
- if (jni_weak_roots != NULL) {
- AlwaysTrueClosure always_true;
- _weak_processor_task.work(worker_id, &always_true, jni_weak_roots);
- _processed_weak_roots = true;
- }
-
- if (ShenandoahStringDedup::is_enabled() && weak_roots != NULL) {
- ShenandoahStringDedup::parallel_oops_do(weak_roots, worker_id);
- }
{
ShenandoahWorkerTimingsTracker timer(worker_times, ShenandoahPhaseTimings::ObjectSynchronizerRoots, worker_id);
diff --git a/src/hotspot/share/gc/shenandoah/shenandoahRootProcessor.hpp b/src/hotspot/share/gc/shenandoah/shenandoahRootProcessor.hpp
index f81f31c65c3..323475b2768 100644
--- a/src/hotspot/share/gc/shenandoah/shenandoahRootProcessor.hpp
+++ b/src/hotspot/share/gc/shenandoah/shenandoahRootProcessor.hpp
@@ -73,8 +73,6 @@ class ShenandoahRootProcessor : public StackObj {
uint worker_i);
void process_vm_roots(OopClosure* scan_non_heap_roots,
- OopClosure* scan_non_heap_weak_roots,
- OopClosure* weak_jni_roots,
uint worker_i);
void weak_processor_timing_to_shenandoah_timing(const WeakProcessorPhases::Phase wpp,
@@ -86,21 +84,30 @@ public:
ShenandoahPhaseTimings::Phase phase);
~ShenandoahRootProcessor();
- // Apply oops, clds and blobs to all strongly reachable roots in the system
- void process_strong_roots(OopClosure* oops, OopClosure* weak_oops,
+ // Apply oops, clds and blobs to all strongly reachable roots in the system.
+ // Optionally, apply class loader closure to weak clds, depending on class unloading
+ // for the particular GC cycles.
+ void process_strong_roots(OopClosure* oops,
CLDClosure* clds,
- CLDClosure* weak_clds,
CodeBlobClosure* blobs,
ThreadClosure* thread_cl,
uint worker_id);
- // Apply oops, clds and blobs to strongly and weakly reachable roots in the system
- void process_all_roots(OopClosure* oops, OopClosure* weak_oops,
+ // Apply oops, clds and blobs to strongly reachable roots in the system
+ void process_all_roots(OopClosure* oops,
CLDClosure* clds,
CodeBlobClosure* blobs,
ThreadClosure* thread_cl,
uint worker_id);
+ // Apply oops, clds and blobs to strongly and weakly reachable roots in the system
+ template
+ void update_all_roots(OopClosure* oops,
+ CLDClosure* clds,
+ CodeBlobClosure* blobs,
+ ThreadClosure* thread_cl,
+ uint worker_id);
+
// For slow debug/verification code
void process_all_roots_slow(OopClosure* oops);
diff --git a/src/hotspot/share/gc/shenandoah/shenandoahRootProcessor.inline.hpp b/src/hotspot/share/gc/shenandoah/shenandoahRootProcessor.inline.hpp
new file mode 100644
index 00000000000..51afd6057c4
--- /dev/null
+++ b/src/hotspot/share/gc/shenandoah/shenandoahRootProcessor.inline.hpp
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2019, Red Hat, Inc. All rights reserved.
+ *
+ * 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_SHENANDOAH_SHENANDOAHROOTPROCESSOR_INLINE_HPP
+#define SHARE_GC_SHENANDOAH_SHENANDOAHROOTPROCESSOR_INLINE_HPP
+
+#include "gc/shenandoah/shenandoahRootProcessor.hpp"
+
+template
+void ShenandoahRootProcessor::update_all_roots(OopClosure* oops,
+ CLDClosure* clds,
+ CodeBlobClosure* blobs,
+ ThreadClosure* thread_cl,
+ uint worker_id) {
+ process_all_roots(oops, clds, blobs, thread_cl, worker_id);
+
+ IsAlive is_alive;
+ _weak_processor_task.work(worker_id, &is_alive, oops);
+ _processed_weak_roots = true;
+
+ if (ShenandoahStringDedup::is_enabled()) {
+ ShenandoahStringDedup::parallel_oops_do(&is_alive, oops, worker_id);
+ }
+}
+
+#endif // SHARE_GC_SHENANDOAH_SHENANDOAHROOTPROCESSOR_INLINE_HPP
diff --git a/src/hotspot/share/gc/shenandoah/shenandoahSATBMarkQueueSet.hpp b/src/hotspot/share/gc/shenandoah/shenandoahSATBMarkQueueSet.hpp
index b4f69ae20cf..1d99d16a79b 100644
--- a/src/hotspot/share/gc/shenandoah/shenandoahSATBMarkQueueSet.hpp
+++ b/src/hotspot/share/gc/shenandoah/shenandoahSATBMarkQueueSet.hpp
@@ -31,7 +31,7 @@
class ShenandoahSATBMarkQueue: public SATBMarkQueue {
public:
- ShenandoahSATBMarkQueue(SATBMarkQueueSet* qset) : SATBMarkQueue(qset, /* permanent = */ false) {}
+ ShenandoahSATBMarkQueue(SATBMarkQueueSet* qset) : SATBMarkQueue(qset) {}
virtual bool should_enqueue_buffer();
};
diff --git a/src/hotspot/share/gc/shenandoah/shenandoahStringDedup.cpp b/src/hotspot/share/gc/shenandoah/shenandoahStringDedup.cpp
index 59e4196ba26..a9f6a2b7970 100644
--- a/src/hotspot/share/gc/shenandoah/shenandoahStringDedup.cpp
+++ b/src/hotspot/share/gc/shenandoah/shenandoahStringDedup.cpp
@@ -71,13 +71,13 @@ void ShenandoahStringDedup::deduplicate(oop java_string) {
StringDedupTable::deduplicate(java_string, &dummy);
}
-void ShenandoahStringDedup::parallel_oops_do(OopClosure* cl, uint worker_id) {
+void ShenandoahStringDedup::parallel_oops_do(BoolObjectClosure* is_alive, OopClosure* cl, uint worker_id) {
assert(SafepointSynchronize::is_at_safepoint(), "Must be at a safepoint");
assert(is_enabled(), "String deduplication not enabled");
ShenandoahWorkerTimings* worker_times = ShenandoahHeap::heap()->phase_timings()->worker_times();
- StringDedupUnlinkOrOopsDoClosure sd_cl(NULL, cl);
+ StringDedupUnlinkOrOopsDoClosure sd_cl(is_alive, cl);
{
ShenandoahWorkerTimingsTracker x(worker_times, ShenandoahPhaseTimings::StringDedupQueueRoots, worker_id);
diff --git a/src/hotspot/share/gc/shenandoah/shenandoahStringDedup.hpp b/src/hotspot/share/gc/shenandoah/shenandoahStringDedup.hpp
index d35042c3506..439524705c7 100644
--- a/src/hotspot/share/gc/shenandoah/shenandoahStringDedup.hpp
+++ b/src/hotspot/share/gc/shenandoah/shenandoahStringDedup.hpp
@@ -38,11 +38,11 @@ public:
// Deduplicate a string, the call is lock-free
static void deduplicate(oop java_string);
- static void parallel_oops_do(OopClosure* cl, uint worker_id);
+ static void parallel_oops_do(BoolObjectClosure* is_alive, OopClosure* cl, uint worker_id);
static void oops_do_slow(OopClosure* cl);
static inline bool is_candidate(oop obj);
-private:
+
static void unlink_or_oops_do(BoolObjectClosure* is_alive,
OopClosure* keep_alive,
bool allow_resize_and_rehash);
diff --git a/src/hotspot/share/gc/shenandoah/shenandoahTraversalGC.cpp b/src/hotspot/share/gc/shenandoah/shenandoahTraversalGC.cpp
index 6bf92cb88c2..88a22d3d146 100644
--- a/src/hotspot/share/gc/shenandoah/shenandoahTraversalGC.cpp
+++ b/src/hotspot/share/gc/shenandoah/shenandoahTraversalGC.cpp
@@ -40,7 +40,7 @@
#include "gc/shenandoah/shenandoahHeuristics.hpp"
#include "gc/shenandoah/shenandoahMarkingContext.inline.hpp"
#include "gc/shenandoah/shenandoahOopClosures.inline.hpp"
-#include "gc/shenandoah/shenandoahRootProcessor.hpp"
+#include "gc/shenandoah/shenandoahRootProcessor.inline.hpp"
#include "gc/shenandoah/shenandoahStringDedup.hpp"
#include "gc/shenandoah/shenandoahTaskqueue.inline.hpp"
#include "gc/shenandoah/shenandoahTimingTracker.hpp"
@@ -188,13 +188,13 @@ public:
ShenandoahMarkCLDClosure cld_cl(&roots_cl);
MarkingCodeBlobClosure code_cl(&roots_cl, CodeBlobToOopClosure::FixRelocations);
if (unload_classes) {
- _rp->process_strong_roots(&roots_cl, process_refs ? NULL : &roots_cl, &cld_cl, NULL, NULL, NULL, worker_id);
+ _rp->process_strong_roots(&roots_cl, &cld_cl, NULL, NULL, worker_id);
// Need to pre-evac code roots here. Otherwise we might see from-space constants.
ShenandoahWorkerTimings* worker_times = _heap->phase_timings()->worker_times();
ShenandoahWorkerTimingsTracker timer(worker_times, ShenandoahPhaseTimings::CodeCacheRoots, worker_id);
_cset_coderoots->possibly_parallel_blobs_do(&code_cl);
} else {
- _rp->process_all_roots(&roots_cl, process_refs ? NULL : &roots_cl, &cld_cl, &code_cl, NULL, worker_id);
+ _rp->process_all_roots(&roots_cl, &cld_cl, &code_cl, NULL, worker_id);
}
}
}
@@ -269,20 +269,20 @@ public:
CLDToOopClosure cld_cl(&roots_cl, ClassLoaderData::_claim_strong);
ShenandoahTraversalSATBThreadsClosure tc(&satb_cl);
if (unload_classes) {
- ShenandoahRemarkCLDClosure weak_cld_cl(&roots_cl);
- _rp->process_strong_roots(&roots_cl, process_refs ? NULL : &roots_cl, &cld_cl, &weak_cld_cl, NULL, &tc, worker_id);
+ ShenandoahRemarkCLDClosure remark_cld_cl(&roots_cl);
+ _rp->process_strong_roots(&roots_cl, &remark_cld_cl, NULL, &tc, worker_id);
} else {
- _rp->process_all_roots(&roots_cl, process_refs ? NULL : &roots_cl, &cld_cl, NULL, &tc, worker_id);
+ _rp->process_all_roots(&roots_cl, &cld_cl, NULL, &tc, worker_id);
}
} else {
ShenandoahTraversalDegenClosure roots_cl(q, rp);
CLDToOopClosure cld_cl(&roots_cl, ClassLoaderData::_claim_strong);
ShenandoahTraversalSATBThreadsClosure tc(&satb_cl);
if (unload_classes) {
- ShenandoahRemarkCLDClosure weak_cld_cl(&roots_cl);
- _rp->process_strong_roots(&roots_cl, process_refs ? NULL : &roots_cl, &cld_cl, &weak_cld_cl, NULL, &tc, worker_id);
+ ShenandoahRemarkCLDClosure remark_cld_cl(&roots_cl);
+ _rp->process_strong_roots(&roots_cl, &remark_cld_cl, NULL, &tc, worker_id);
} else {
- _rp->process_all_roots(&roots_cl, process_refs ? NULL : &roots_cl, &cld_cl, NULL, &tc, worker_id);
+ _rp->process_all_roots(&roots_cl, &cld_cl, NULL, &tc, worker_id);
}
}
@@ -594,8 +594,11 @@ void ShenandoahTraversalGC::final_traversal_collection() {
weak_refs_work();
}
- if (!_heap->cancelled_gc() && _heap->unload_classes()) {
- _heap->unload_classes_and_cleanup_tables(false);
+ if (!_heap->cancelled_gc()) {
+ if (_heap->unload_classes()) {
+ _heap->unload_classes_and_cleanup_tables(false);
+ }
+
fixup_roots();
}
@@ -691,14 +694,16 @@ private:
public:
ShenandoahTraversalFixRootsTask(ShenandoahRootProcessor* rp) :
AbstractGangTask("Shenandoah traversal fix roots"),
- _rp(rp) {}
+ _rp(rp) {
+ assert(ShenandoahHeap::heap()->has_forwarded_objects(), "Must be");
+ }
void work(uint worker_id) {
ShenandoahParallelWorkerSession worker_session(worker_id);
ShenandoahTraversalFixRootsClosure cl;
MarkingCodeBlobClosure blobsCl(&cl, CodeBlobToOopClosure::FixRelocations);
CLDToOopClosure cldCl(&cl, ClassLoaderData::_claim_strong);
- _rp->process_all_roots(&cl, &cl, &cldCl, &blobsCl, NULL, worker_id);
+ _rp->update_all_roots(&cl, &cldCl, &blobsCl, NULL, worker_id);
}
};
diff --git a/src/hotspot/share/gc/z/c2/zBarrierSetC2.cpp b/src/hotspot/share/gc/z/c2/zBarrierSetC2.cpp
index 632a9f9dfb6..70dd2c8775a 100644
--- a/src/hotspot/share/gc/z/c2/zBarrierSetC2.cpp
+++ b/src/hotspot/share/gc/z/c2/zBarrierSetC2.cpp
@@ -194,9 +194,9 @@ uint LoadBarrierNode::size_of() const {
return sizeof(*this);
}
-uint LoadBarrierNode::cmp(const Node& n) const {
+bool LoadBarrierNode::cmp(const Node& n) const {
ShouldNotReachHere();
- return 0;
+ return false;
}
const Type *LoadBarrierNode::bottom_type() const {
diff --git a/src/hotspot/share/gc/z/c2/zBarrierSetC2.hpp b/src/hotspot/share/gc/z/c2/zBarrierSetC2.hpp
index 713e6d2ae29..1b7c7bf4d95 100644
--- a/src/hotspot/share/gc/z/c2/zBarrierSetC2.hpp
+++ b/src/hotspot/share/gc/z/c2/zBarrierSetC2.hpp
@@ -63,7 +63,7 @@ public:
virtual int Opcode() const;
virtual uint size_of() const;
- virtual uint cmp(const Node& n) const;
+ virtual bool cmp(const Node& n) const;
virtual const Type *bottom_type() const;
virtual const TypePtr* adr_type() const;
virtual const Type *Value(PhaseGVN *phase) const;
diff --git a/src/hotspot/share/gc/z/zForwarding.cpp b/src/hotspot/share/gc/z/zForwarding.cpp
index c7109afcb78..75a1718a36c 100644
--- a/src/hotspot/share/gc/z/zForwarding.cpp
+++ b/src/hotspot/share/gc/z/zForwarding.cpp
@@ -58,7 +58,7 @@ void ZForwarding::verify() const {
for (ZForwardingCursor i = 0; i < _entries.length(); i++) {
const ZForwardingEntry entry = at(&i);
- if (entry.is_empty()) {
+ if (!entry.populated()) {
// Skip empty entries
continue;
}
diff --git a/src/hotspot/share/gc/z/zForwarding.inline.hpp b/src/hotspot/share/gc/z/zForwarding.inline.hpp
index 3a5d835d1ce..fc653312b70 100644
--- a/src/hotspot/share/gc/z/zForwarding.inline.hpp
+++ b/src/hotspot/share/gc/z/zForwarding.inline.hpp
@@ -119,9 +119,9 @@ inline ZForwardingEntry ZForwarding::find(uintptr_t from_index) const {
inline ZForwardingEntry ZForwarding::find(uintptr_t from_index, ZForwardingCursor* cursor) const {
// Reading entries in the table races with the atomic CAS done for
// insertion into the table. This is safe because each entry is at
- // most updated once (from -1 to something else).
+ // most updated once (from zero to something else).
ZForwardingEntry entry = first(from_index, cursor);
- while (!entry.is_empty()) {
+ while (entry.populated()) {
if (entry.from_index() == from_index) {
// Match found, return matching entry
return entry;
@@ -140,14 +140,14 @@ inline uintptr_t ZForwarding::insert(uintptr_t from_index, uintptr_t to_offset,
for (;;) {
const ZForwardingEntry prev_entry = Atomic::cmpxchg(new_entry, entries() + *cursor, old_entry);
- if (prev_entry.is_empty()) {
+ if (!prev_entry.populated()) {
// Success
return to_offset;
}
// Find next empty or matching entry
ZForwardingEntry entry = at(cursor);
- while (!entry.is_empty()) {
+ while (entry.populated()) {
if (entry.from_index() == from_index) {
// Match found, return already inserted address
return entry.to_offset();
diff --git a/src/hotspot/share/gc/z/zForwardingEntry.hpp b/src/hotspot/share/gc/z/zForwardingEntry.hpp
index b52593e1443..8c6eee940f6 100644
--- a/src/hotspot/share/gc/z/zForwardingEntry.hpp
+++ b/src/hotspot/share/gc/z/zForwardingEntry.hpp
@@ -32,40 +32,40 @@
// Forwarding entry layout
// -----------------------
//
-// 6 4 4 0
-// 3 2 1 0
-// +------------------------+-----------------------------------------------+
-// |11111111 11111111 111111|11 11111111 11111111 11111111 11111111 11111111|
-// +------------------------+-----------------------------------------------+
-// | |
-// | * 41-0 To Object Offset (42-bits)
+// 6 4 4
+// 3 6 5 1 0
+// +--------------------+--------------------------------------------------+-+
+// |11111111 11111111 11|111111 11111111 11111111 11111111 11111111 1111111|1|
+// +--------------------+--------------------------------------------------+-+
+// | | |
+// | | 0-0 Populated Flag (1-bits) *
+// | |
+// | * 45-1 To Object Offset (45-bits)
// |
-// * 63-42 From Object Index (22-bits)
+// * 63-46 From Object Index (18-bits)
//
class ZForwardingEntry {
friend struct PrimitiveConversions;
private:
- typedef ZBitField field_to_offset;
- typedef ZBitField field_from_index;
+ typedef ZBitField field_populated;
+ typedef ZBitField field_to_offset;
+ typedef ZBitField field_from_index;
uint64_t _entry;
- static uintptr_t empty() {
- return (uintptr_t)-1;
- }
-
public:
ZForwardingEntry() :
- _entry(empty()) {}
+ _entry(0) {}
ZForwardingEntry(size_t from_index, size_t to_offset) :
- _entry(field_from_index::encode(from_index) |
- field_to_offset::encode(to_offset)) {}
+ _entry(field_populated::encode(true) |
+ field_to_offset::encode(to_offset) |
+ field_from_index::encode(from_index)) {}
- bool is_empty() const {
- return _entry == empty();
+ bool populated() const {
+ return field_populated::decode(_entry);
}
size_t to_offset() const {
diff --git a/src/hotspot/share/gc/z/zHeap.cpp b/src/hotspot/share/gc/z/zHeap.cpp
index 0ecba6171ec..9c64bdcf90f 100644
--- a/src/hotspot/share/gc/z/zHeap.cpp
+++ b/src/hotspot/share/gc/z/zHeap.cpp
@@ -540,16 +540,19 @@ void ZHeap::print_extended_on(outputStream* st) const {
class ZVerifyRootsTask : public ZTask {
private:
+ ZStatTimerDisable _disable;
ZRootsIterator _strong_roots;
ZWeakRootsIterator _weak_roots;
public:
ZVerifyRootsTask() :
ZTask("ZVerifyRootsTask"),
+ _disable(),
_strong_roots(),
_weak_roots() {}
virtual void work() {
+ ZStatTimerDisable disable;
ZVerifyOopClosure cl;
_strong_roots.oops_do(&cl);
_weak_roots.oops_do(&cl);
diff --git a/src/hotspot/share/gc/z/zHeapIterator.cpp b/src/hotspot/share/gc/z/zHeapIterator.cpp
index 497b1b35161..6c95bfd93cd 100644
--- a/src/hotspot/share/gc/z/zHeapIterator.cpp
+++ b/src/hotspot/share/gc/z/zHeapIterator.cpp
@@ -28,6 +28,7 @@
#include "gc/z/zHeapIterator.hpp"
#include "gc/z/zOop.inline.hpp"
#include "gc/z/zRootsIterator.hpp"
+#include "gc/z/zStat.hpp"
#include "memory/iterator.inline.hpp"
#include "utilities/bitMap.inline.hpp"
#include "utilities/stack.inline.hpp"
@@ -170,6 +171,7 @@ void ZHeapIterator::objects_do(ObjectClosure* cl) {
// If we didn't do this the application would have expected to see
// ObjectFree events for phantom reachable objects in the tag map.
+ ZStatTimerDisable disable;
ZHeapIteratorRootOopClosure root_cl(this);
// Push strong roots onto stack
diff --git a/src/hotspot/share/gc/z/zNMethodTableEntry.hpp b/src/hotspot/share/gc/z/zNMethodTableEntry.hpp
index bdbb0feeab0..8b30542999d 100644
--- a/src/hotspot/share/gc/z/zNMethodTableEntry.hpp
+++ b/src/hotspot/share/gc/z/zNMethodTableEntry.hpp
@@ -37,13 +37,11 @@
// |11111111 11111111 11111111 11111111 11111111 11111111 11111111 111111|1|1|
// +---------------------------------------------------------------------+-+-+
// | | |
-// | | |
-// | | |
// | 1-1 Unregistered Flag (1-bits) * |
// | |
// | 0-0 Registered Flag (1-bits) *
// |
-// * 63-3 NMethod Address (61-bits)
+// * 63-2 NMethod Address (62-bits)
//
class nmethod;
diff --git a/src/hotspot/share/gc/z/zObjectAllocator.cpp b/src/hotspot/share/gc/z/zObjectAllocator.cpp
index f8e04694f7a..028c075ccfa 100644
--- a/src/hotspot/share/gc/z/zObjectAllocator.cpp
+++ b/src/hotspot/share/gc/z/zObjectAllocator.cpp
@@ -186,10 +186,6 @@ uintptr_t ZObjectAllocator::alloc_object(size_t size) {
ZAllocationFlags flags;
flags.set_no_reserve();
- if (!ZStallOnOutOfMemory) {
- flags.set_non_blocking();
- }
-
return alloc_object(size, flags);
}
diff --git a/src/hotspot/share/gc/z/zRelocate.cpp b/src/hotspot/share/gc/z/zRelocate.cpp
index c6a2c7faca3..14169d69730 100644
--- a/src/hotspot/share/gc/z/zRelocate.cpp
+++ b/src/hotspot/share/gc/z/zRelocate.cpp
@@ -88,7 +88,7 @@ uintptr_t ZRelocate::relocate_object_inner(ZForwarding* forwarding, uintptr_t fr
// Lookup forwarding entry
const ZForwardingEntry entry = forwarding->find(from_index, &cursor);
- if (entry.from_index() == from_index) {
+ if (entry.populated() && entry.from_index() == from_index) {
// Already relocated, return new address
return entry.to_offset();
}
@@ -150,7 +150,9 @@ uintptr_t ZRelocate::forward_object(ZForwarding* forwarding, uintptr_t from_addr
const uintptr_t from_index = (from_offset - forwarding->start()) >> forwarding->object_alignment_shift();
const ZForwardingEntry entry = forwarding->find(from_index);
+ assert(entry.populated(), "Should be forwarded");
assert(entry.from_index() == from_index, "Should be forwarded");
+
return ZAddress::good(entry.to_offset());
}
diff --git a/src/hotspot/share/gc/z/zRelocationSetSelector.cpp b/src/hotspot/share/gc/z/zRelocationSetSelector.cpp
index b1aa2950625..cf86de058e5 100644
--- a/src/hotspot/share/gc/z/zRelocationSetSelector.cpp
+++ b/src/hotspot/share/gc/z/zRelocationSetSelector.cpp
@@ -103,6 +103,7 @@ void ZRelocationSetSelectorGroup::select() {
const size_t npages = _registered_pages.size();
size_t selected_from = 0;
size_t selected_to = 0;
+ size_t selected_from_size = 0;
size_t from_size = 0;
semi_sort();
@@ -127,6 +128,7 @@ void ZRelocationSetSelectorGroup::select() {
if (diff_reclaimable > ZFragmentationLimit) {
selected_from = from;
selected_to = to;
+ selected_from_size = from_size;
}
log_trace(gc, reloc)("Candidate Relocation Set (%s Pages): "
@@ -138,7 +140,7 @@ void ZRelocationSetSelectorGroup::select() {
_nselected = selected_from;
// Update statistics
- _relocating = from_size;
+ _relocating = selected_from_size;
for (size_t i = _nselected; i < npages; i++) {
ZPage* const page = _sorted_pages[i];
_fragmentation += page->size() - page->live_bytes();
diff --git a/src/hotspot/share/gc/z/zStat.cpp b/src/hotspot/share/gc/z/zStat.cpp
index 2906058e1f8..30261565a00 100644
--- a/src/hotspot/share/gc/z/zStat.cpp
+++ b/src/hotspot/share/gc/z/zStat.cpp
@@ -748,6 +748,11 @@ void ZStatCriticalPhase::register_end(const Ticks& start, const Ticks& end) cons
}
}
+//
+// Stat timer
+//
+__thread uint32_t ZStatTimerDisable::_active = 0;
+
//
// Stat sample/inc
//
diff --git a/src/hotspot/share/gc/z/zStat.hpp b/src/hotspot/share/gc/z/zStat.hpp
index 3390466e648..3b13ef8d8f0 100644
--- a/src/hotspot/share/gc/z/zStat.hpp
+++ b/src/hotspot/share/gc/z/zStat.hpp
@@ -269,21 +269,45 @@ public:
//
// Stat timer
//
+class ZStatTimerDisable : public StackObj {
+private:
+ static __thread uint32_t _active;
+
+public:
+ ZStatTimerDisable() {
+ _active++;
+ }
+
+ ~ZStatTimerDisable() {
+ _active--;
+ }
+
+ static bool is_active() {
+ return _active > 0;
+ }
+};
+
class ZStatTimer : public StackObj {
private:
+ const bool _enabled;
const ZStatPhase& _phase;
const Ticks _start;
public:
ZStatTimer(const ZStatPhase& phase) :
+ _enabled(!ZStatTimerDisable::is_active()),
_phase(phase),
_start(Ticks::now()) {
- _phase.register_start(_start);
+ if (_enabled) {
+ _phase.register_start(_start);
+ }
}
~ZStatTimer() {
- const Ticks end = Ticks::now();
- _phase.register_end(_start, end);
+ if (_enabled) {
+ const Ticks end = Ticks::now();
+ _phase.register_end(_start, end);
+ }
}
};
diff --git a/src/hotspot/share/gc/z/z_globals.hpp b/src/hotspot/share/gc/z/z_globals.hpp
index 0b64abea0ab..dce11654512 100644
--- a/src/hotspot/share/gc/z/z_globals.hpp
+++ b/src/hotspot/share/gc/z/z_globals.hpp
@@ -39,28 +39,24 @@
constraint, \
writeable) \
\
- product(ccstr, ZPath, NULL, \
+ experimental(ccstr, ZPath, NULL, \
"Filesystem path for Java heap backing storage " \
"(must be a tmpfs or a hugetlbfs filesystem)") \
\
- product(double, ZAllocationSpikeTolerance, 2.0, \
+ experimental(double, ZAllocationSpikeTolerance, 2.0, \
"Allocation spike tolerance factor") \
\
- product(double, ZFragmentationLimit, 25.0, \
+ experimental(double, ZFragmentationLimit, 25.0, \
"Maximum allowed heap fragmentation") \
\
- product(bool, ZStallOnOutOfMemory, true, \
- "Allow Java threads to stall and wait for GC to complete " \
- "instead of immediately throwing an OutOfMemoryError") \
- \
- product(size_t, ZMarkStackSpaceLimit, 8*G, \
+ experimental(size_t, ZMarkStackSpaceLimit, 8*G, \
"Maximum number of bytes allocated for mark stacks") \
range(32*M, 1024*G) \
\
- product(uint, ZCollectionInterval, 0, \
+ experimental(uint, ZCollectionInterval, 0, \
"Force GC at a fixed time interval (in seconds)") \
\
- product(uint, ZStatisticsInterval, 10, \
+ diagnostic(uint, ZStatisticsInterval, 10, \
"Time between statistics print outs (in seconds)") \
range(1, (uint)-1) \
\
diff --git a/src/hotspot/share/jfr/recorder/repository/jfrChunkWriter.cpp b/src/hotspot/share/jfr/recorder/repository/jfrChunkWriter.cpp
index cbd539568f8..02941d167fd 100644
--- a/src/hotspot/share/jfr/recorder/repository/jfrChunkWriter.cpp
+++ b/src/hotspot/share/jfr/recorder/repository/jfrChunkWriter.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2012, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2019, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -46,13 +46,9 @@ bool JfrChunkWriter::initialize() {
return _chunkstate != NULL;
}
-static fio_fd open_existing(const char* path) {
- return os::open(path, O_RDWR, S_IREAD | S_IWRITE);
-}
-
static fio_fd open_chunk(const char* path) {
assert(JfrStream_lock->owned_by_self(), "invariant");
- return path != NULL ? open_existing(path) : invalid_fd;
+ return path != NULL ? os::open(path, O_CREAT | O_RDWR, S_IREAD | S_IWRITE) : invalid_fd;
}
bool JfrChunkWriter::open() {
diff --git a/src/hotspot/share/jfr/recorder/repository/jfrEmergencyDump.cpp b/src/hotspot/share/jfr/recorder/repository/jfrEmergencyDump.cpp
index 147437e25e7..b8e4b0c064f 100644
--- a/src/hotspot/share/jfr/recorder/repository/jfrEmergencyDump.cpp
+++ b/src/hotspot/share/jfr/recorder/repository/jfrEmergencyDump.cpp
@@ -24,17 +24,315 @@
#include "precompiled.hpp"
#include "jfr/jfrEvents.hpp"
+#include "jfr/jni/jfrJavaSupport.hpp"
#include "jfr/leakprofiler/leakProfiler.hpp"
#include "jfr/recorder/repository/jfrEmergencyDump.hpp"
#include "jfr/recorder/service/jfrPostBox.hpp"
#include "jfr/recorder/service/jfrRecorderService.hpp"
#include "jfr/utilities/jfrTypes.hpp"
+#include "logging/log.hpp"
#include "memory/resourceArea.hpp"
#include "runtime/atomic.hpp"
#include "runtime/handles.inline.hpp"
#include "runtime/globals.hpp"
#include "runtime/mutexLocker.hpp"
-#include "runtime/thread.hpp"
+#include "runtime/os.hpp"
+#include "runtime/thread.inline.hpp"
+#include "utilities/growableArray.hpp"
+
+static const char vm_error_filename_fmt[] = "hs_err_pid%p.jfr";
+static const char vm_oom_filename_fmt[] = "hs_oom_pid%p.jfr";
+static const char vm_soe_filename_fmt[] = "hs_soe_pid%p.jfr";
+static const char chunk_file_jfr_ext[] = ".jfr";
+static const size_t iso8601_len = 19; // "YYYY-MM-DDTHH:MM:SS"
+
+static fio_fd open_exclusivly(const char* path) {
+ return os::open(path, O_CREAT | O_RDWR, S_IREAD | S_IWRITE);
+}
+
+static int file_sort(const char** const file1, const char** file2) {
+ assert(NULL != *file1 && NULL != *file2, "invariant");
+ int cmp = strncmp(*file1, *file2, iso8601_len);
+ if (0 == cmp) {
+ const char* const dot1 = strchr(*file1, '.');
+ assert(NULL != dot1, "invariant");
+ const char* const dot2 = strchr(*file2, '.');
+ assert(NULL != dot2, "invariant");
+ ptrdiff_t file1_len = dot1 - *file1;
+ ptrdiff_t file2_len = dot2 - *file2;
+ if (file1_len < file2_len) {
+ return -1;
+ }
+ if (file1_len > file2_len) {
+ return 1;
+ }
+ assert(file1_len == file2_len, "invariant");
+ cmp = strncmp(*file1, *file2, file1_len);
+ }
+ assert(cmp != 0, "invariant");
+ return cmp;
+}
+
+static void iso8601_to_date_time(char* iso8601_str) {
+ assert(iso8601_str != NULL, "invariant");
+ assert(strlen(iso8601_str) == iso8601_len, "invariant");
+ // "YYYY-MM-DDTHH:MM:SS"
+ for (size_t i = 0; i < iso8601_len; ++i) {
+ switch (iso8601_str[i]) {
+ case 'T':
+ case '-':
+ case ':':
+ iso8601_str[i] = '_';
+ break;
+ }
+ }
+ // "YYYY_MM_DD_HH_MM_SS"
+}
+
+static void date_time(char* buffer, size_t buffer_len) {
+ assert(buffer != NULL, "invariant");
+ assert(buffer_len >= iso8601_len, "buffer too small");
+ os::iso8601_time(buffer, buffer_len);
+ assert(strlen(buffer) >= iso8601_len + 1, "invariant");
+ // "YYYY-MM-DDTHH:MM:SS"
+ buffer[iso8601_len] = '\0';
+ iso8601_to_date_time(buffer);
+}
+
+static int64_t file_size(fio_fd fd) {
+ assert(fd != invalid_fd, "invariant");
+ const int64_t current_offset = os::current_file_offset(fd);
+ const int64_t size = os::lseek(fd, 0, SEEK_END);
+ os::seek_to_file_offset(fd, current_offset);
+ return size;
+}
+
+class RepositoryIterator : public StackObj {
+ private:
+ const char* const _repo;
+ const size_t _repository_len;
+ GrowableArray* _files;
+ const char* const fully_qualified(const char* entry) const;
+ mutable int _iterator;
+
+ public:
+ RepositoryIterator(const char* repository, size_t repository_len);
+ ~RepositoryIterator() {}
+ const char* const filter(const char* entry) const;
+ bool has_next() const;
+ const char* const next() const;
+};
+
+const char* const RepositoryIterator::fully_qualified(const char* entry) const {
+ assert(NULL != entry, "invariant");
+ char* file_path_entry = NULL;
+ // only use files that have content, not placeholders
+ const char* const file_separator = os::file_separator();
+ if (NULL != file_separator) {
+ const size_t entry_len = strlen(entry);
+ const size_t file_separator_length = strlen(file_separator);
+ const size_t file_path_entry_length = _repository_len + file_separator_length + entry_len;
+ file_path_entry = NEW_RESOURCE_ARRAY_RETURN_NULL(char, file_path_entry_length + 1);
+ if (NULL == file_path_entry) {
+ return NULL;
+ }
+ int position = 0;
+ position += jio_snprintf(&file_path_entry[position], _repository_len + 1, "%s", _repo);
+ position += jio_snprintf(&file_path_entry[position], file_separator_length + 1, "%s", os::file_separator());
+ position += jio_snprintf(&file_path_entry[position], entry_len + 1, "%s", entry);
+ file_path_entry[position] = '\0';
+ assert((size_t)position == file_path_entry_length, "invariant");
+ assert(strlen(file_path_entry) == (size_t)position, "invariant");
+ }
+ return file_path_entry;
+}
+
+const char* const RepositoryIterator::filter(const char* entry) const {
+ if (entry == NULL) {
+ return NULL;
+ }
+ const size_t entry_len = strlen(entry);
+ if (entry_len <= 2) {
+ // for "." and ".."
+ return NULL;
+ }
+ char* entry_name = NEW_RESOURCE_ARRAY_RETURN_NULL(char, entry_len + 1);
+ if (entry_name == NULL) {
+ return NULL;
+ }
+ strncpy(entry_name, entry, entry_len + 1);
+ const char* const fully_qualified_path_entry = fully_qualified(entry_name);
+ if (NULL == fully_qualified_path_entry) {
+ return NULL;
+ }
+ const fio_fd entry_fd = open_exclusivly(fully_qualified_path_entry);
+ if (invalid_fd == entry_fd) {
+ return NULL;
+ }
+ const int64_t entry_size = file_size(entry_fd);
+ os::close(entry_fd);
+ if (0 == entry_size) {
+ return NULL;
+ }
+ return entry_name;
+}
+
+RepositoryIterator::RepositoryIterator(const char* repository, size_t repository_len) :
+ _repo(repository),
+ _repository_len(repository_len),
+ _files(NULL),
+ _iterator(0) {
+ if (NULL != _repo) {
+ assert(strlen(_repo) == _repository_len, "invariant");
+ _files = new GrowableArray(10);
+ DIR* dirp = os::opendir(_repo);
+ if (dirp == NULL) {
+ log_error(jfr, system)("Unable to open repository %s", _repo);
+ return;
+ }
+ struct dirent* dentry;
+ while ((dentry = os::readdir(dirp)) != NULL) {
+ const char* const entry_path = filter(dentry->d_name);
+ if (NULL != entry_path) {
+ _files->append(entry_path);
+ }
+ }
+ os::closedir(dirp);
+ if (_files->length() > 1) {
+ _files->sort(file_sort);
+ }
+ }
+}
+
+bool RepositoryIterator::has_next() const {
+ return (_files != NULL && _iterator < _files->length());
+}
+
+const char* const RepositoryIterator::next() const {
+ return _iterator >= _files->length() ? NULL : fully_qualified(_files->at(_iterator++));
+}
+
+static void write_emergency_file(fio_fd emergency_fd, const RepositoryIterator& iterator) {
+ assert(emergency_fd != invalid_fd, "invariant");
+ const size_t size_of_file_copy_block = 1 * M; // 1 mb
+ jbyte* const file_copy_block = NEW_RESOURCE_ARRAY_RETURN_NULL(jbyte, size_of_file_copy_block);
+ if (file_copy_block == NULL) {
+ return;
+ }
+ while (iterator.has_next()) {
+ fio_fd current_fd = invalid_fd;
+ const char* const fqn = iterator.next();
+ if (fqn != NULL) {
+ current_fd = open_exclusivly(fqn);
+ if (current_fd != invalid_fd) {
+ const int64_t current_filesize = file_size(current_fd);
+ assert(current_filesize > 0, "invariant");
+ int64_t bytes_read = 0;
+ int64_t bytes_written = 0;
+ while (bytes_read < current_filesize) {
+ const ssize_t read_result = os::read_at(current_fd, file_copy_block, size_of_file_copy_block, bytes_read);
+ if (-1 == read_result) {
+ log_info(jfr)( // For user, should not be "jfr, system"
+ "Unable to recover JFR data");
+ break;
+ }
+ bytes_read += (int64_t)read_result;
+ assert(bytes_read - bytes_written <= (int64_t)size_of_file_copy_block, "invariant");
+ bytes_written += (int64_t)os::write(emergency_fd, file_copy_block, bytes_read - bytes_written);
+ assert(bytes_read == bytes_written, "invariant");
+ }
+ os::close(current_fd);
+ }
+ }
+ }
+}
+
+static const char* create_emergency_dump_path() {
+ assert(JfrStream_lock->owned_by_self(), "invariant");
+ char* buffer = NEW_RESOURCE_ARRAY_RETURN_NULL(char, JVM_MAXPATHLEN);
+ if (NULL == buffer) {
+ return NULL;
+ }
+ const char* const cwd = os::get_current_directory(buffer, JVM_MAXPATHLEN);
+ if (NULL == cwd) {
+ return NULL;
+ }
+ size_t pos = strlen(cwd);
+ const int fsep_len = jio_snprintf(&buffer[pos], JVM_MAXPATHLEN - pos, "%s", os::file_separator());
+ const char* filename_fmt = NULL;
+ // fetch specific error cause
+ switch (JfrJavaSupport::cause()) {
+ case JfrJavaSupport::OUT_OF_MEMORY:
+ filename_fmt = vm_oom_filename_fmt;
+ break;
+ case JfrJavaSupport::STACK_OVERFLOW:
+ filename_fmt = vm_soe_filename_fmt;
+ break;
+ default:
+ filename_fmt = vm_error_filename_fmt;
+ }
+ char* emergency_dump_path = NULL;
+ pos += fsep_len;
+ if (Arguments::copy_expand_pid(filename_fmt, strlen(filename_fmt), &buffer[pos], JVM_MAXPATHLEN - pos)) {
+ const size_t emergency_filename_length = strlen(buffer);
+ emergency_dump_path = NEW_RESOURCE_ARRAY_RETURN_NULL(char, emergency_filename_length + 1);
+ if (NULL == emergency_dump_path) {
+ return NULL;
+ }
+ strncpy(emergency_dump_path, buffer, emergency_filename_length + 1);
+ }
+ if (emergency_dump_path != NULL) {
+ log_info(jfr)( // For user, should not be "jfr, system"
+ "Attempting to recover JFR data, emergency jfr file: %s", emergency_dump_path);
+ }
+ return emergency_dump_path;
+}
+
+// Caller needs ResourceMark
+static const char* create_emergency_chunk_path(const char* repository_path) {
+ assert(repository_path != NULL, "invariant");
+ assert(JfrStream_lock->owned_by_self(), "invariant");
+ const size_t repository_path_len = strlen(repository_path);
+ // date time
+ char date_time_buffer[32] = { 0 };
+ date_time(date_time_buffer, sizeof(date_time_buffer));
+ size_t date_time_len = strlen(date_time_buffer);
+ size_t chunkname_max_len = repository_path_len // repository_base_path
+ + 1 // "/"
+ + date_time_len // date_time
+ + strlen(chunk_file_jfr_ext) // .jfr
+ + 1;
+ char* chunk_path = NEW_RESOURCE_ARRAY_RETURN_NULL(char, chunkname_max_len);
+ if (chunk_path == NULL) {
+ return NULL;
+ }
+ // append the individual substrings
+ jio_snprintf(chunk_path, chunkname_max_len, "%s%s%s%s", repository_path_len, os::file_separator(), date_time_buffer, chunk_file_jfr_ext);
+ return chunk_path;
+}
+
+static fio_fd emergency_dump_file_descriptor() {
+ assert(JfrStream_lock->owned_by_self(), "invariant");
+ ResourceMark rm;
+ const char* const emergency_dump_path = create_emergency_dump_path();
+ return emergency_dump_path != NULL ? open_exclusivly(emergency_dump_path) : invalid_fd;
+}
+
+const char* JfrEmergencyDump::build_dump_path(const char* repository_path) {
+ return repository_path == NULL ? create_emergency_dump_path() : create_emergency_chunk_path(repository_path);
+}
+
+void JfrEmergencyDump::on_vm_error(const char* repository_path) {
+ assert(repository_path != NULL, "invariant");
+ ResourceMark rm;
+ MutexLockerEx stream_lock(JfrStream_lock, Mutex::_no_safepoint_check_flag);
+ const fio_fd emergency_fd = emergency_dump_file_descriptor();
+ if (emergency_fd != invalid_fd) {
+ RepositoryIterator iterator(repository_path, strlen(repository_path));
+ write_emergency_file(emergency_fd, iterator);
+ os::close(emergency_fd);
+ }
+}
/*
* We are just about to exit the VM, so we will be very aggressive
diff --git a/src/hotspot/share/jfr/recorder/repository/jfrEmergencyDump.hpp b/src/hotspot/share/jfr/recorder/repository/jfrEmergencyDump.hpp
index 41e69b5c8c4..2752dec1356 100644
--- a/src/hotspot/share/jfr/recorder/repository/jfrEmergencyDump.hpp
+++ b/src/hotspot/share/jfr/recorder/repository/jfrEmergencyDump.hpp
@@ -33,6 +33,8 @@
class JfrEmergencyDump : AllStatic {
public:
static void on_vm_shutdown(bool exception_handler);
+ static void on_vm_error(const char* repository_path);
+ static const char* build_dump_path(const char* repository_path);
};
#endif // SHARE_JFR_RECORDER_REPOSITORY_JFREMERGENCYDUMP_HPP
diff --git a/src/hotspot/share/jfr/recorder/repository/jfrRepository.cpp b/src/hotspot/share/jfr/recorder/repository/jfrRepository.cpp
index 18817084357..20be0bea99e 100644
--- a/src/hotspot/share/jfr/recorder/repository/jfrRepository.cpp
+++ b/src/hotspot/share/jfr/recorder/repository/jfrRepository.cpp
@@ -28,12 +28,11 @@
#include "jfr/recorder/jfrRecorder.hpp"
#include "jfr/recorder/repository/jfrChunkState.hpp"
#include "jfr/recorder/repository/jfrChunkWriter.hpp"
+#include "jfr/recorder/repository/jfrEmergencyDump.hpp"
#include "jfr/recorder/repository/jfrRepository.hpp"
#include "jfr/recorder/service/jfrPostBox.hpp"
-#include "logging/log.hpp"
#include "memory/resourceArea.hpp"
#include "runtime/mutex.hpp"
-#include "runtime/os.hpp"
#include "runtime/thread.inline.hpp"
static JfrRepository* _instance = NULL;
@@ -84,321 +83,13 @@ void JfrRepository::destroy() {
_instance = NULL;
}
-static const char vm_error_filename_fmt[] = "hs_err_pid%p.jfr";
-static const char vm_oom_filename_fmt[] = "hs_oom_pid%p.jfr";
-static const char vm_soe_filename_fmt[] = "hs_soe_pid%p.jfr";
-static const char chunk_file_jfr_ext[] = ".jfr";
-static const size_t iso8601_len = 19; // "YYYY-MM-DDTHH:MM:SS"
-
-static fio_fd open_exclusivly(const char* path) {
- return os::open(path, O_CREAT | O_WRONLY, S_IREAD | S_IWRITE);
-}
-
-static fio_fd open_existing(const char* path) {
- return os::open(path, O_RDWR, S_IREAD | S_IWRITE);
-}
-
-static int file_sort(const char** const file1, const char** file2) {
- assert(NULL != *file1 && NULL != *file2, "invariant");
- int cmp = strncmp(*file1, *file2, iso8601_len);
- if (0 == cmp) {
- const char* const dot1 = strchr(*file1, '.');
- assert(NULL != dot1, "invariant");
- const char* const dot2 = strchr(*file2, '.');
- assert(NULL != dot2, "invariant");
- ptrdiff_t file1_len = dot1 - *file1;
- ptrdiff_t file2_len = dot2 - *file2;
- if (file1_len < file2_len) {
- return -1;
- }
- if (file1_len > file2_len) {
- return 1;
- }
- assert(file1_len == file2_len, "invariant");
- cmp = strncmp(*file1, *file2, file1_len);
- }
- assert(cmp != 0, "invariant");
- return cmp;
-}
-
-static void iso8601_to_date_time(char* iso8601_str) {
- assert(iso8601_str != NULL, "invariant");
- assert(strlen(iso8601_str) == iso8601_len, "invariant");
- // "YYYY-MM-DDTHH:MM:SS"
- for (size_t i = 0; i < iso8601_len; ++i) {
- switch(iso8601_str[i]) {
- case 'T' :
- case '-' :
- case ':' :
- iso8601_str[i] = '_';
- break;
- }
- }
- // "YYYY_MM_DD_HH_MM_SS"
-}
-
-static void date_time(char* buffer, size_t buffer_len) {
- assert(buffer != NULL, "invariant");
- assert(buffer_len >= iso8601_len, "buffer too small");
- os::iso8601_time(buffer, buffer_len);
- assert(strlen(buffer) >= iso8601_len + 1, "invariant");
- // "YYYY-MM-DDTHH:MM:SS"
- buffer[iso8601_len] = '\0';
- iso8601_to_date_time(buffer);
-}
-
-static int64_t file_size(fio_fd fd) {
- assert(fd != invalid_fd, "invariant");
- const int64_t current_offset = os::current_file_offset(fd);
- const int64_t size = os::lseek(fd, 0, SEEK_END);
- os::seek_to_file_offset(fd, current_offset);
- return size;
-}
-
-class RepositoryIterator : public StackObj {
- private:
- const char* const _repo;
- const size_t _repository_len;
- GrowableArray* _files;
- const char* const fully_qualified(const char* entry) const;
- mutable int _iterator;
-
- public:
- RepositoryIterator(const char* repository, size_t repository_len);
- ~RepositoryIterator() {}
- debug_only(void print_repository_files() const;)
- const char* const filter(const char* entry) const;
- bool has_next() const;
- const char* const next() const;
-};
-
-const char* const RepositoryIterator::fully_qualified(const char* entry) const {
- assert(NULL != entry, "invariant");
- char* file_path_entry = NULL;
- // only use files that have content, not placeholders
- const char* const file_separator = os::file_separator();
- if (NULL != file_separator) {
- const size_t entry_len = strlen(entry);
- const size_t file_separator_length = strlen(file_separator);
- const size_t file_path_entry_length = _repository_len + file_separator_length + entry_len;
- file_path_entry = NEW_RESOURCE_ARRAY_RETURN_NULL(char, file_path_entry_length + 1);
- if (NULL == file_path_entry) {
- return NULL;
- }
- int position = 0;
- position += jio_snprintf(&file_path_entry[position], _repository_len + 1, "%s", _repo);
- position += jio_snprintf(&file_path_entry[position], file_separator_length + 1, "%s", os::file_separator());
- position += jio_snprintf(&file_path_entry[position], entry_len + 1, "%s", entry);
- file_path_entry[position] = '\0';
- assert((size_t)position == file_path_entry_length, "invariant");
- assert(strlen(file_path_entry) == (size_t)position, "invariant");
- }
- return file_path_entry;
-}
-
-const char* const RepositoryIterator::filter(const char* entry) const {
- if (entry == NULL) {
- return NULL;
- }
- const size_t entry_len = strlen(entry);
- if (entry_len <= 2) {
- // for "." and ".."
- return NULL;
- }
- char* entry_name = NEW_RESOURCE_ARRAY_RETURN_NULL(char, entry_len + 1);
- if (entry_name == NULL) {
- return NULL;
- }
- strncpy(entry_name, entry, entry_len + 1);
- const char* const fully_qualified_path_entry = fully_qualified(entry_name);
- if (NULL == fully_qualified_path_entry) {
- return NULL;
- }
- const fio_fd entry_fd = open_existing(fully_qualified_path_entry);
- if (invalid_fd == entry_fd) {
- return NULL;
- }
- const int64_t entry_size = file_size(entry_fd);
- os::close(entry_fd);
- if (0 == entry_size) {
- return NULL;
- }
- return entry_name;
-}
-
-RepositoryIterator::RepositoryIterator(const char* repository, size_t repository_len) :
- _repo(repository),
- _repository_len(repository_len),
- _files(NULL),
- _iterator(0) {
- if (NULL != _repo) {
- assert(strlen(_repo) == _repository_len, "invariant");
- _files = new GrowableArray(10);
- DIR* dirp = os::opendir(_repo);
- if (dirp == NULL) {
- log_error(jfr, system)("Unable to open repository %s", _repo);
- return;
- }
- struct dirent* dentry;
- while ((dentry = os::readdir(dirp)) != NULL) {
- const char* const entry_path = filter(dentry->d_name);
- if (NULL != entry_path) {
- _files->append(entry_path);
- }
- }
- os::closedir(dirp);
- if (_files->length() > 1) {
- _files->sort(file_sort);
- }
- }
-}
-
-#ifdef ASSERT
-void RepositoryIterator::print_repository_files() const {
- while (has_next()) {
- log_error(jfr, system)( "%s", next());
- }
-}
-#endif
-
-bool RepositoryIterator::has_next() const {
- return (_files != NULL && _iterator < _files->length());
-}
-
-const char* const RepositoryIterator::next() const {
- return _iterator >= _files->length() ? NULL : fully_qualified(_files->at(_iterator++));
-}
-
-static void write_emergency_file(fio_fd emergency_fd, const RepositoryIterator& iterator) {
- assert(emergency_fd != invalid_fd, "invariant");
- const size_t size_of_file_copy_block = 1 * M; // 1 mb
- jbyte* const file_copy_block = NEW_RESOURCE_ARRAY_RETURN_NULL(jbyte, size_of_file_copy_block);
- if (file_copy_block == NULL) {
- return;
- }
- int64_t bytes_written_total = 0;
- while (iterator.has_next()) {
- fio_fd current_fd = invalid_fd;
- const char* const fqn = iterator.next();
- if (fqn != NULL) {
- current_fd = open_existing(fqn);
- if (current_fd != invalid_fd) {
- const int64_t current_filesize = file_size(current_fd);
- assert(current_filesize > 0, "invariant");
- int64_t bytes_read = 0;
- int64_t bytes_written = 0;
- while (bytes_read < current_filesize) {
- const ssize_t read_result = os::read_at(current_fd, file_copy_block, size_of_file_copy_block, bytes_read);
- if (-1 == read_result) {
- log_info(jfr) ( // For user, should not be "jfr, system"
- "Unable to recover JFR data");
- break;
- }
- bytes_read += (int64_t)read_result;
- assert(bytes_read - bytes_written <= (int64_t)size_of_file_copy_block, "invariant");
- bytes_written += (int64_t)os::write(emergency_fd, file_copy_block, bytes_read - bytes_written);
- assert(bytes_read == bytes_written, "invariant");
- }
- os::close(current_fd);
- bytes_written_total += bytes_written;
- }
- }
- }
-}
-
-static const char* create_emergency_dump_path() {
- assert(JfrStream_lock->owned_by_self(), "invariant");
- char* buffer = NEW_RESOURCE_ARRAY_RETURN_NULL(char, O_BUFLEN);
- if (NULL == buffer) {
- return NULL;
- }
- const char* const cwd = os::get_current_directory(buffer, O_BUFLEN);
- if (NULL == cwd) {
- return NULL;
- }
- size_t pos = strlen(cwd);
- const int fsep_len = jio_snprintf(&buffer[pos], O_BUFLEN - pos, "%s", os::file_separator());
- const char* filename_fmt = NULL;
- // fetch specific error cause
- switch (JfrJavaSupport::cause()) {
- case JfrJavaSupport::OUT_OF_MEMORY:
- filename_fmt = vm_oom_filename_fmt;
- break;
- case JfrJavaSupport::STACK_OVERFLOW:
- filename_fmt = vm_soe_filename_fmt;
- break;
- default:
- filename_fmt = vm_error_filename_fmt;
- }
- char* emergency_dump_path = NULL;
- pos += fsep_len;
- if (Arguments::copy_expand_pid(filename_fmt, strlen(filename_fmt), &buffer[pos], O_BUFLEN - pos)) {
- const size_t emergency_filename_length = strlen(buffer);
- emergency_dump_path = NEW_RESOURCE_ARRAY_RETURN_NULL(char, emergency_filename_length + 1);
- if (NULL == emergency_dump_path) {
- return NULL;
- }
- strncpy(emergency_dump_path, buffer, emergency_filename_length + 1);
- }
- return emergency_dump_path;
-}
-
-// Caller needs ResourceMark
-static const char* create_emergency_chunk_path(const char* repository_base, size_t repository_len) {
- assert(repository_base != NULL, "invariant");
- assert(JfrStream_lock->owned_by_self(), "invariant");
- // date time
- char date_time_buffer[32] = {0};
- date_time(date_time_buffer, sizeof(date_time_buffer));
- size_t date_time_len = strlen(date_time_buffer);
- size_t chunkname_max_len = repository_len // repository_base
- + 1 // "/"
- + date_time_len // date_time
- + strlen(chunk_file_jfr_ext) // .jfr
- + 1;
- char* chunk_path = NEW_RESOURCE_ARRAY_RETURN_NULL(char, chunkname_max_len);
- if (chunk_path == NULL) {
- return NULL;
- }
- // append the individual substrings
- jio_snprintf(chunk_path, chunkname_max_len, "%s%s%s%s", repository_base, os::file_separator(), date_time_buffer, chunk_file_jfr_ext);
- return chunk_path;
-}
-
-static fio_fd emergency_dump_file() {
- assert(JfrStream_lock->owned_by_self(), "invariant");
- ResourceMark rm;
- const char* const emergency_dump_path = create_emergency_dump_path();
- if (emergency_dump_path == NULL) {
- return invalid_fd;
- }
- const fio_fd fd = open_exclusivly(emergency_dump_path);
- if (fd != invalid_fd) {
- log_info(jfr)( // For user, should not be "jfr, system"
- "Attempting to recover JFR data, emergency jfr file: %s", emergency_dump_path);
- }
- return fd;
-}
-
-static const char* emergency_path(const char* repository, size_t repository_len) {
- return repository == NULL ? create_emergency_dump_path() : create_emergency_chunk_path(repository, repository_len);
-}
-
void JfrRepository::on_vm_error() {
assert(!JfrStream_lock->owned_by_self(), "invariant");
- const char* path = _path;
- if (path == NULL) {
+ if (_path == NULL) {
// completed already
return;
}
- ResourceMark rm;
- MutexLockerEx stream_lock(JfrStream_lock, Mutex::_no_safepoint_check_flag);
- const fio_fd emergency_fd = emergency_dump_file();
- if (emergency_fd != invalid_fd) {
- RepositoryIterator iterator(path, strlen(path));
- write_emergency_file(emergency_fd, iterator);
- os::close(emergency_fd);
- }
+ JfrEmergencyDump::on_vm_error(_path);
}
bool JfrRepository::set_path(const char* path) {
@@ -467,10 +158,7 @@ bool JfrRepository::open_chunk(bool vm_error /* false */) {
assert(JfrStream_lock->owned_by_self(), "invariant");
if (vm_error) {
ResourceMark rm;
- const char* repository_path = _path;
- const size_t repository_path_len = repository_path != NULL ? strlen(repository_path) : 0;
- const char* const path = emergency_path(repository_path, repository_path_len);
- _chunkwriter->set_chunk_path(path);
+ _chunkwriter->set_chunk_path(JfrEmergencyDump::build_dump_path(_path));
}
return _chunkwriter->open();
}
diff --git a/src/hotspot/share/memory/filemap.cpp b/src/hotspot/share/memory/filemap.cpp
index b541966d75f..cdfa57d4e32 100644
--- a/src/hotspot/share/memory/filemap.cpp
+++ b/src/hotspot/share/memory/filemap.cpp
@@ -24,7 +24,9 @@
#include "precompiled.hpp"
#include "jvm.h"
+#include "classfile/classFileStream.hpp"
#include "classfile/classLoader.inline.hpp"
+#include "classfile/classLoaderData.inline.hpp"
#include "classfile/classLoaderExt.hpp"
#include "classfile/symbolTable.hpp"
#include "classfile/systemDictionaryShared.hpp"
@@ -1489,7 +1491,7 @@ ClassPathEntry* FileMapInfo::get_classpath_entry_for_jvmti(int i, TRAPS) {
return ent;
}
-ClassFileStream* FileMapInfo::open_stream_for_jvmti(InstanceKlass* ik, TRAPS) {
+ClassFileStream* FileMapInfo::open_stream_for_jvmti(InstanceKlass* ik, Handle class_loader, TRAPS) {
int path_index = ik->shared_classpath_index();
assert(path_index >= 0, "should be called for shared built-in classes only");
assert(path_index < (int)_shared_path_table_size, "sanity");
@@ -1501,7 +1503,12 @@ ClassFileStream* FileMapInfo::open_stream_for_jvmti(InstanceKlass* ik, TRAPS) {
const char* const class_name = name->as_C_string();
const char* const file_name = ClassLoader::file_name_for_class_name(class_name,
name->utf8_length());
- return cpe->open_stream(file_name, THREAD);
+ ClassLoaderData* loader_data = ClassLoaderData::class_loader_data(class_loader());
+ ClassFileStream* cfs = cpe->open_stream_for_loader(file_name, loader_data, THREAD);
+ assert(cfs != NULL, "must be able to read the classfile data of shared classes for built-in loaders.");
+ log_debug(cds, jvmti)("classfile data for %s [%d: %s] = %d bytes", class_name, path_index,
+ cfs->source(), cfs->length());
+ return cfs;
}
#endif
diff --git a/src/hotspot/share/memory/filemap.hpp b/src/hotspot/share/memory/filemap.hpp
index 8b535261a8c..4b458f6456b 100644
--- a/src/hotspot/share/memory/filemap.hpp
+++ b/src/hotspot/share/memory/filemap.hpp
@@ -303,7 +303,7 @@ public:
static void update_shared_classpath(ClassPathEntry *cpe, SharedClassPathEntry* ent, TRAPS);
#if INCLUDE_JVMTI
- static ClassFileStream* open_stream_for_jvmti(InstanceKlass* ik, TRAPS);
+ static ClassFileStream* open_stream_for_jvmti(InstanceKlass* ik, Handle class_loader, TRAPS);
#endif
static SharedClassPathEntry* shared_path(int index) {
diff --git a/src/hotspot/share/memory/heapInspection.cpp b/src/hotspot/share/memory/heapInspection.cpp
index b51ba6269c5..8fe5fc52e4d 100644
--- a/src/hotspot/share/memory/heapInspection.cpp
+++ b/src/hotspot/share/memory/heapInspection.cpp
@@ -121,6 +121,11 @@ void KlassInfoEntry::print_on(outputStream* st) const {
}
KlassInfoEntry* KlassInfoBucket::lookup(Klass* const k) {
+ // Can happen if k is an archived class that we haven't loaded yet.
+ if (k->java_mirror() == NULL) {
+ return NULL;
+ }
+
KlassInfoEntry* elt = _list;
while (elt != NULL) {
if (elt->is_equal(k)) {
@@ -202,7 +207,8 @@ KlassInfoEntry* KlassInfoTable::lookup(Klass* k) {
assert(_buckets != NULL, "Allocation failure should have been caught");
KlassInfoEntry* e = _buckets[idx].lookup(k);
// Lookup may fail if this is a new klass for which we
- // could not allocate space for an new entry.
+ // could not allocate space for an new entry, or if it's
+ // an archived class that we haven't loaded yet.
assert(e == NULL || k == e->klass(), "must be equal");
return e;
}
diff --git a/src/hotspot/share/memory/heapShared.cpp b/src/hotspot/share/memory/heapShared.cpp
index 0b3d5d30a21..3ec6830d2e9 100644
--- a/src/hotspot/share/memory/heapShared.cpp
+++ b/src/hotspot/share/memory/heapShared.cpp
@@ -68,6 +68,7 @@ static ArchivableStaticFieldInfo closed_archive_subgraph_entry_fields[] = {
{"java/lang/Byte$ByteCache", "archivedCache"},
{"java/lang/Short$ShortCache", "archivedCache"},
{"java/lang/Character$CharacterCache", "archivedCache"},
+ {"java/util/jar/Attributes$Name", "KNOWN_NAMES"},
};
// Entry fields for subgraphs archived in the open archive heap region.
static ArchivableStaticFieldInfo open_archive_subgraph_entry_fields[] = {
diff --git a/src/hotspot/share/memory/metaspace.cpp b/src/hotspot/share/memory/metaspace.cpp
index 5921125720a..ad228c41c7e 100644
--- a/src/hotspot/share/memory/metaspace.cpp
+++ b/src/hotspot/share/memory/metaspace.cpp
@@ -534,6 +534,23 @@ void MetaspaceUtils::print_vs(outputStream* out, size_t scale) {
}
}
+static void print_basic_switches(outputStream* out, size_t scale) {
+ out->print("MaxMetaspaceSize: ");
+ if (MaxMetaspaceSize >= (max_uintx) - (2 * os::vm_page_size())) {
+ // aka "very big". Default is max_uintx, but due to rounding in arg parsing the real
+ // value is smaller.
+ out->print("unlimited");
+ } else {
+ print_human_readable_size(out, MaxMetaspaceSize, scale);
+ }
+ out->cr();
+ if (Metaspace::using_class_space()) {
+ out->print("CompressedClassSpaceSize: ");
+ print_human_readable_size(out, CompressedClassSpaceSize, scale);
+ }
+ out->cr();
+}
+
// This will print out a basic metaspace usage report but
// unlike print_report() is guaranteed not to lock or to walk the CLDG.
void MetaspaceUtils::print_basic_report(outputStream* out, size_t scale) {
@@ -614,6 +631,12 @@ void MetaspaceUtils::print_basic_report(outputStream* out, size_t scale) {
Metaspace::chunk_manager_metadata()->free_chunks_total_bytes(), scale);
out->cr();
}
+
+ out->cr();
+
+ // Print basic settings
+ print_basic_switches(out, scale);
+
out->cr();
}
@@ -805,19 +828,11 @@ void MetaspaceUtils::print_report(outputStream* out, size_t scale, int flags) {
// Print some interesting settings
out->cr();
out->cr();
- out->print("MaxMetaspaceSize: ");
- print_human_readable_size(out, MaxMetaspaceSize, scale);
+ print_basic_switches(out, scale);
+
out->cr();
out->print("InitialBootClassLoaderMetaspaceSize: ");
print_human_readable_size(out, InitialBootClassLoaderMetaspaceSize, scale);
- out->cr();
-
- out->print("UseCompressedClassPointers: %s", UseCompressedClassPointers ? "true" : "false");
- out->cr();
- if (Metaspace::using_class_space()) {
- out->print("CompressedClassSpaceSize: ");
- print_human_readable_size(out, CompressedClassSpaceSize, scale);
- }
out->cr();
out->cr();
diff --git a/src/hotspot/share/memory/metaspaceShared.cpp b/src/hotspot/share/memory/metaspaceShared.cpp
index 6ce300fcce3..3dfaaff051a 100644
--- a/src/hotspot/share/memory/metaspaceShared.cpp
+++ b/src/hotspot/share/memory/metaspaceShared.cpp
@@ -36,6 +36,7 @@
#include "classfile/systemDictionary.hpp"
#include "classfile/systemDictionaryShared.hpp"
#include "code/codeCache.hpp"
+#include "gc/shared/softRefPolicy.hpp"
#include "interpreter/bytecodeStream.hpp"
#include "interpreter/bytecodes.hpp"
#include "logging/log.hpp"
diff --git a/src/hotspot/share/memory/oopFactory.cpp b/src/hotspot/share/memory/oopFactory.cpp
index c46a5601992..c9eda7da39f 100644
--- a/src/hotspot/share/memory/oopFactory.cpp
+++ b/src/hotspot/share/memory/oopFactory.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2019, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -37,6 +37,7 @@
#include "oops/oop.inline.hpp"
#include "oops/typeArrayOop.inline.hpp"
#include "runtime/handles.inline.hpp"
+#include "utilities/utf8.hpp"
typeArrayOop oopFactory::new_charArray(const char* utf8_str, TRAPS) {
diff --git a/src/hotspot/share/oops/arrayKlass.cpp b/src/hotspot/share/oops/arrayKlass.cpp
index 0169037178c..facf2baec04 100644
--- a/src/hotspot/share/oops/arrayKlass.cpp
+++ b/src/hotspot/share/oops/arrayKlass.cpp
@@ -24,6 +24,7 @@
#include "precompiled.hpp"
#include "classfile/javaClasses.hpp"
+#include "classfile/moduleEntry.hpp"
#include "classfile/systemDictionary.hpp"
#include "classfile/vmSymbols.hpp"
#include "gc/shared/collectedHeap.inline.hpp"
diff --git a/src/hotspot/share/oops/instanceKlass.cpp b/src/hotspot/share/oops/instanceKlass.cpp
index 19e43423ab9..5d802f4bf77 100644
--- a/src/hotspot/share/oops/instanceKlass.cpp
+++ b/src/hotspot/share/oops/instanceKlass.cpp
@@ -2438,6 +2438,23 @@ bool InstanceKlass::check_sharing_error_state() {
return (old_state != is_in_error_state());
}
+void InstanceKlass::set_class_loader_type(s2 loader_type) {
+ switch (loader_type) {
+ case ClassLoader::BOOT_LOADER:
+ _misc_flags |= _misc_is_shared_boot_class;
+ break;
+ case ClassLoader::PLATFORM_LOADER:
+ _misc_flags |= _misc_is_shared_platform_class;
+ break;
+ case ClassLoader::APP_LOADER:
+ _misc_flags |= _misc_is_shared_app_class;
+ break;
+ default:
+ ShouldNotReachHere();
+ break;
+ }
+}
+
#if INCLUDE_JVMTI
static void clear_all_breakpoints(Method* m) {
m->clear_all_breakpoints();
@@ -3367,7 +3384,9 @@ void InstanceKlass::print_class_load_logging(ClassLoaderData* loader_data,
if (cfs != NULL) {
if (cfs->source() != NULL) {
if (module_name != NULL) {
- if (ClassLoader::is_modules_image(cfs->source())) {
+ // When the boot loader created the stream, it didn't know the module name
+ // yet. Let's format it now.
+ if (cfs->from_boot_loader_modules_image()) {
info_stream.print(" source: jrt:/%s", module_name);
} else {
info_stream.print(" source: %s", cfs->source());
diff --git a/src/hotspot/share/oops/instanceKlass.hpp b/src/hotspot/share/oops/instanceKlass.hpp
index 13029ca4111..7e44865009e 100644
--- a/src/hotspot/share/oops/instanceKlass.hpp
+++ b/src/hotspot/share/oops/instanceKlass.hpp
@@ -25,10 +25,7 @@
#ifndef SHARE_OOPS_INSTANCEKLASS_HPP
#define SHARE_OOPS_INSTANCEKLASS_HPP
-#include "classfile/classLoader.hpp"
#include "classfile/classLoaderData.hpp"
-#include "classfile/moduleEntry.hpp"
-#include "classfile/packageEntry.hpp"
#include "memory/referenceType.hpp"
#include "oops/annotations.hpp"
#include "oops/constMethod.hpp"
@@ -63,6 +60,7 @@
class BreakpointInfo;
#endif
class ClassFileParser;
+class ClassFileStream;
class KlassDepChange;
class DependencyContext;
class fieldDescriptor;
@@ -70,9 +68,10 @@ class jniIdMapBase;
class JNIid;
class JvmtiCachedClassFieldMap;
class nmethodBucket;
-class SuperTypeClosure;
class OopMapCache;
class InterpreterOopMap;
+class PackageEntry;
+class ModuleEntry;
// This is used in iterators below.
class FieldClosure: public StackObj {
@@ -349,22 +348,7 @@ class InstanceKlass: public Klass {
_misc_flags &= ~loader_type_bits();
}
- void set_class_loader_type(s2 loader_type) {
- switch (loader_type) {
- case ClassLoader::BOOT_LOADER:
- _misc_flags |= _misc_is_shared_boot_class;
- break;
- case ClassLoader::PLATFORM_LOADER:
- _misc_flags |= _misc_is_shared_platform_class;
- break;
- case ClassLoader::APP_LOADER:
- _misc_flags |= _misc_is_shared_app_class;
- break;
- default:
- ShouldNotReachHere();
- break;
- }
- }
+ void set_class_loader_type(s2 loader_type);
bool has_nonstatic_fields() const {
return (_misc_flags & _misc_has_nonstatic_fields) != 0;
@@ -1025,7 +1009,6 @@ public:
void methods_do(void f(Method* method));
void array_klasses_do(void f(Klass* k));
void array_klasses_do(void f(Klass* k, TRAPS), TRAPS);
- bool super_types_do(SuperTypeClosure* blk);
static InstanceKlass* cast(Klass* k) {
return const_cast(cast(const_cast(k)));
diff --git a/src/hotspot/share/oops/klass.cpp b/src/hotspot/share/oops/klass.cpp
index f6931eb1be3..2c5b3aab767 100644
--- a/src/hotspot/share/oops/klass.cpp
+++ b/src/hotspot/share/oops/klass.cpp
@@ -27,6 +27,7 @@
#include "classfile/classLoaderDataGraph.inline.hpp"
#include "classfile/dictionary.hpp"
#include "classfile/javaClasses.hpp"
+#include "classfile/moduleEntry.hpp"
#include "classfile/systemDictionary.hpp"
#include "classfile/vmSymbols.hpp"
#include "gc/shared/collectedHeap.inline.hpp"
diff --git a/src/hotspot/share/oops/markOop.hpp b/src/hotspot/share/oops/markOop.hpp
index 4873df39900..43f2ad823e3 100644
--- a/src/hotspot/share/oops/markOop.hpp
+++ b/src/hotspot/share/oops/markOop.hpp
@@ -138,23 +138,15 @@ class markOopDesc: public oopDesc {
epoch_mask_in_place = epoch_mask << epoch_shift,
cms_mask = right_n_bits(cms_bits),
cms_mask_in_place = cms_mask << cms_shift
-#ifndef _WIN64
- ,hash_mask = right_n_bits(hash_bits),
- hash_mask_in_place = (address_word)hash_mask << hash_shift
-#endif
};
+ const static uintptr_t hash_mask = right_n_bits(hash_bits);
+ const static uintptr_t hash_mask_in_place = hash_mask << hash_shift;
+
// Alignment of JavaThread pointers encoded in object header required by biased locking
enum { biased_lock_alignment = 2 << (epoch_shift + epoch_bits)
};
-#ifdef _WIN64
- // These values are too big for Win64
- const static uintptr_t hash_mask = right_n_bits(hash_bits);
- const static uintptr_t hash_mask_in_place =
- (address_word)hash_mask << hash_shift;
-#endif
-
enum { locked_value = 0,
unlocked_value = 1,
monitor_value = 2,
diff --git a/src/hotspot/share/oops/symbol.cpp b/src/hotspot/share/oops/symbol.cpp
index 0b2a043acfb..76f6d7b2e01 100644
--- a/src/hotspot/share/oops/symbol.cpp
+++ b/src/hotspot/share/oops/symbol.cpp
@@ -34,6 +34,7 @@
#include "oops/symbol.hpp"
#include "runtime/atomic.hpp"
#include "runtime/os.hpp"
+#include "utilities/utf8.hpp"
uint32_t Symbol::pack_length_and_refcount(int length, int refcount) {
STATIC_ASSERT(max_symbol_length == ((1 << 16) - 1));
diff --git a/src/hotspot/share/oops/symbol.hpp b/src/hotspot/share/oops/symbol.hpp
index 5958f6b9c95..ddaf57b2c10 100644
--- a/src/hotspot/share/oops/symbol.hpp
+++ b/src/hotspot/share/oops/symbol.hpp
@@ -28,7 +28,6 @@
#include "memory/allocation.hpp"
#include "utilities/exceptions.hpp"
#include "utilities/macros.hpp"
-#include "utilities/utf8.hpp"
// A Symbol is a canonicalized string.
// All Symbols reside in global SymbolTable and are reference counted.
diff --git a/src/hotspot/share/opto/callnode.cpp b/src/hotspot/share/opto/callnode.cpp
index 68c51c99957..212b585c7b0 100644
--- a/src/hotspot/share/opto/callnode.cpp
+++ b/src/hotspot/share/opto/callnode.cpp
@@ -49,7 +49,7 @@
//=============================================================================
uint StartNode::size_of() const { return sizeof(*this); }
-uint StartNode::cmp( const Node &n ) const
+bool StartNode::cmp( const Node &n ) const
{ return _domain == ((StartNode&)n)._domain; }
const Type *StartNode::bottom_type() const { return _domain; }
const Type* StartNode::Value(PhaseGVN* phase) const { return _domain; }
@@ -666,7 +666,7 @@ int JVMState::interpreter_frame_size() const {
}
//=============================================================================
-uint CallNode::cmp( const Node &n ) const
+bool CallNode::cmp( const Node &n ) const
{ return _tf == ((CallNode&)n)._tf && _jvms == ((CallNode&)n)._jvms; }
#ifndef PRODUCT
void CallNode::dump_req(outputStream *st) const {
@@ -962,7 +962,7 @@ bool CallNode::is_call_to_arraycopystub() const {
//=============================================================================
uint CallJavaNode::size_of() const { return sizeof(*this); }
-uint CallJavaNode::cmp( const Node &n ) const {
+bool CallJavaNode::cmp( const Node &n ) const {
CallJavaNode &call = (CallJavaNode&)n;
return CallNode::cmp(call) && _method == call._method &&
_override_symbolic_info == call._override_symbolic_info;
@@ -999,7 +999,7 @@ void CallJavaNode::dump_compact_spec(outputStream* st) const {
//=============================================================================
uint CallStaticJavaNode::size_of() const { return sizeof(*this); }
-uint CallStaticJavaNode::cmp( const Node &n ) const {
+bool CallStaticJavaNode::cmp( const Node &n ) const {
CallStaticJavaNode &call = (CallStaticJavaNode&)n;
return CallJavaNode::cmp(call);
}
@@ -1056,7 +1056,7 @@ void CallStaticJavaNode::dump_compact_spec(outputStream* st) const {
//=============================================================================
uint CallDynamicJavaNode::size_of() const { return sizeof(*this); }
-uint CallDynamicJavaNode::cmp( const Node &n ) const {
+bool CallDynamicJavaNode::cmp( const Node &n ) const {
CallDynamicJavaNode &call = (CallDynamicJavaNode&)n;
return CallJavaNode::cmp(call);
}
@@ -1069,7 +1069,7 @@ void CallDynamicJavaNode::dump_spec(outputStream *st) const {
//=============================================================================
uint CallRuntimeNode::size_of() const { return sizeof(*this); }
-uint CallRuntimeNode::cmp( const Node &n ) const {
+bool CallRuntimeNode::cmp( const Node &n ) const {
CallRuntimeNode &call = (CallRuntimeNode&)n;
return CallNode::cmp(call) && !strcmp(_name,call._name);
}
@@ -1118,7 +1118,7 @@ void SafePointNode::set_local(JVMState* jvms, uint idx, Node *c) {
}
uint SafePointNode::size_of() const { return sizeof(*this); }
-uint SafePointNode::cmp( const Node &n ) const {
+bool SafePointNode::cmp( const Node &n ) const {
return (&n == this); // Always fail except on self
}
@@ -1314,7 +1314,7 @@ SafePointScalarObjectNode::SafePointScalarObjectNode(const TypeOopPtr* tp,
// Do not allow value-numbering for SafePointScalarObject node.
uint SafePointScalarObjectNode::hash() const { return NO_HASH; }
-uint SafePointScalarObjectNode::cmp( const Node &n ) const {
+bool SafePointScalarObjectNode::cmp( const Node &n ) const {
return (&n == this); // Always fail except on self
}
@@ -2084,4 +2084,3 @@ bool CallNode::may_modify_arraycopy_helper(const TypeOopPtr* dest_t, const TypeO
return true;
}
-
diff --git a/src/hotspot/share/opto/callnode.hpp b/src/hotspot/share/opto/callnode.hpp
index d356d2b9bda..703360e4fd9 100644
--- a/src/hotspot/share/opto/callnode.hpp
+++ b/src/hotspot/share/opto/callnode.hpp
@@ -63,7 +63,7 @@ class FastLockNode;
//------------------------------StartNode--------------------------------------
// The method start node
class StartNode : public MultiNode {
- virtual uint cmp( const Node &n ) const;
+ virtual bool cmp( const Node &n ) const;
virtual uint size_of() const; // Size is bigger
public:
const TypeTuple *_domain;
@@ -321,7 +321,7 @@ public:
// potential code sharing) only - conceptually it is independent of
// the Node semantics.
class SafePointNode : public MultiNode {
- virtual uint cmp( const Node &n ) const;
+ virtual bool cmp( const Node &n ) const;
virtual uint size_of() const; // Size is bigger
public:
@@ -497,7 +497,7 @@ class SafePointScalarObjectNode: public TypeNode {
DEBUG_ONLY(AllocateNode* _alloc;)
virtual uint hash() const ; // { return NO_HASH; }
- virtual uint cmp( const Node &n ) const;
+ virtual bool cmp( const Node &n ) const;
uint first_index() const { return _first_index; }
@@ -598,7 +598,7 @@ public:
virtual const Type* Value(PhaseGVN* phase) const;
virtual Node *Ideal(PhaseGVN *phase, bool can_reshape);
virtual Node* Identity(PhaseGVN* phase) { return this; }
- virtual uint cmp( const Node &n ) const;
+ virtual bool cmp( const Node &n ) const;
virtual uint size_of() const = 0;
virtual void calling_convention( BasicType* sig_bt, VMRegPair *parm_regs, uint argcnt ) const;
virtual Node *match( const ProjNode *proj, const Matcher *m );
@@ -654,7 +654,7 @@ public:
class CallJavaNode : public CallNode {
friend class VMStructs;
protected:
- virtual uint cmp( const Node &n ) const;
+ virtual bool cmp( const Node &n ) const;
virtual uint size_of() const; // Size is bigger
bool _optimized_virtual;
@@ -696,7 +696,7 @@ public:
// calls and optimized virtual calls, plus calls to wrappers for run-time
// routines); generates static stub.
class CallStaticJavaNode : public CallJavaNode {
- virtual uint cmp( const Node &n ) const;
+ virtual bool cmp( const Node &n ) const;
virtual uint size_of() const; // Size is bigger
public:
CallStaticJavaNode(Compile* C, const TypeFunc* tf, address addr, ciMethod* method, int bci)
@@ -750,7 +750,7 @@ public:
//------------------------------CallDynamicJavaNode----------------------------
// Make a dispatched call using Java calling convention.
class CallDynamicJavaNode : public CallJavaNode {
- virtual uint cmp( const Node &n ) const;
+ virtual bool cmp( const Node &n ) const;
virtual uint size_of() const; // Size is bigger
public:
CallDynamicJavaNode( const TypeFunc *tf , address addr, ciMethod* method, int vtable_index, int bci ) : CallJavaNode(tf,addr,method,bci), _vtable_index(vtable_index) {
@@ -767,7 +767,7 @@ public:
//------------------------------CallRuntimeNode--------------------------------
// Make a direct subroutine call node into compiled C++ code.
class CallRuntimeNode : public CallNode {
- virtual uint cmp( const Node &n ) const;
+ virtual bool cmp( const Node &n ) const;
virtual uint size_of() const; // Size is bigger
public:
CallRuntimeNode(const TypeFunc* tf, address addr, const char* name,
diff --git a/src/hotspot/share/opto/castnode.cpp b/src/hotspot/share/opto/castnode.cpp
index 7450d84c749..26f3cb1345c 100644
--- a/src/hotspot/share/opto/castnode.cpp
+++ b/src/hotspot/share/opto/castnode.cpp
@@ -81,7 +81,7 @@ Node *ConstraintCastNode::Ideal(PhaseGVN *phase, bool can_reshape) {
return (in(0) && remove_dead_region(phase, can_reshape)) ? this : NULL;
}
-uint ConstraintCastNode::cmp(const Node &n) const {
+bool ConstraintCastNode::cmp(const Node &n) const {
return TypeNode::cmp(n) && ((ConstraintCastNode&)n)._carry_dependency == _carry_dependency;
}
@@ -262,7 +262,7 @@ Node *CastIINode::Ideal(PhaseGVN *phase, bool can_reshape) {
return NULL;
}
-uint CastIINode::cmp(const Node &n) const {
+bool CastIINode::cmp(const Node &n) const {
return ConstraintCastNode::cmp(n) && ((CastIINode&)n)._range_check_dependency == _range_check_dependency;
}
diff --git a/src/hotspot/share/opto/castnode.hpp b/src/hotspot/share/opto/castnode.hpp
index 906e74faec7..e4fe29a438e 100644
--- a/src/hotspot/share/opto/castnode.hpp
+++ b/src/hotspot/share/opto/castnode.hpp
@@ -35,7 +35,7 @@ class ConstraintCastNode: public TypeNode {
protected:
// Can this node be removed post CCP or does it carry a required dependency?
const bool _carry_dependency;
- virtual uint cmp( const Node &n ) const;
+ virtual bool cmp( const Node &n ) const;
virtual uint size_of() const;
public:
@@ -65,7 +65,7 @@ class CastIINode: public ConstraintCastNode {
protected:
// Is this node dependent on a range check?
const bool _range_check_dependency;
- virtual uint cmp(const Node &n) const;
+ virtual bool cmp(const Node &n) const;
virtual uint size_of() const;
public:
diff --git a/src/hotspot/share/opto/cfgnode.cpp b/src/hotspot/share/opto/cfgnode.cpp
index 245940cd64a..ec8d4961c23 100644
--- a/src/hotspot/share/opto/cfgnode.cpp
+++ b/src/hotspot/share/opto/cfgnode.cpp
@@ -883,7 +883,7 @@ uint PhiNode::hash() const {
const Type* at = _adr_type;
return TypeNode::hash() + (at ? at->hash() : 0);
}
-uint PhiNode::cmp( const Node &n ) const {
+bool PhiNode::cmp( const Node &n ) const {
return TypeNode::cmp(n) && _adr_type == ((PhiNode&)n)._adr_type;
}
static inline
@@ -2353,7 +2353,7 @@ const RegMask &CProjNode::out_RegMask() const {
//=============================================================================
uint PCTableNode::hash() const { return Node::hash() + _size; }
-uint PCTableNode::cmp( const Node &n ) const
+bool PCTableNode::cmp( const Node &n ) const
{ return _size == ((PCTableNode&)n)._size; }
const Type *PCTableNode::bottom_type() const {
@@ -2383,7 +2383,7 @@ uint JumpProjNode::hash() const {
return Node::hash() + _dest_bci;
}
-uint JumpProjNode::cmp( const Node &n ) const {
+bool JumpProjNode::cmp( const Node &n ) const {
return ProjNode::cmp(n) &&
_dest_bci == ((JumpProjNode&)n)._dest_bci;
}
@@ -2446,7 +2446,7 @@ uint CatchProjNode::hash() const {
}
-uint CatchProjNode::cmp( const Node &n ) const {
+bool CatchProjNode::cmp( const Node &n ) const {
return ProjNode::cmp(n) &&
_handler_bci == ((CatchProjNode&)n)._handler_bci;
}
diff --git a/src/hotspot/share/opto/cfgnode.hpp b/src/hotspot/share/opto/cfgnode.hpp
index 479fc89fb47..37b2c7267b6 100644
--- a/src/hotspot/share/opto/cfgnode.hpp
+++ b/src/hotspot/share/opto/cfgnode.hpp
@@ -131,7 +131,7 @@ class PhiNode : public TypeNode {
const int _inst_offset; // Offset of the instance memory slice.
// Size is bigger to hold the _adr_type field.
virtual uint hash() const; // Check the type
- virtual uint cmp( const Node &n ) const;
+ virtual bool cmp( const Node &n ) const;
virtual uint size_of() const { return sizeof(*this); }
// Determine if CMoveNode::is_cmove_id can be used at this join point.
@@ -465,7 +465,7 @@ protected:
// Undefined behavior if passed-in index is not inside the table.
class PCTableNode : public MultiBranchNode {
virtual uint hash() const; // Target count; table size
- virtual uint cmp( const Node &n ) const;
+ virtual bool cmp( const Node &n ) const;
virtual uint size_of() const { return sizeof(*this); }
public:
@@ -507,7 +507,7 @@ public:
class JumpProjNode : public JProjNode {
virtual uint hash() const;
- virtual uint cmp( const Node &n ) const;
+ virtual bool cmp( const Node &n ) const;
virtual uint size_of() const { return sizeof(*this); }
private:
@@ -550,7 +550,7 @@ public:
// the projection doesn't lead to an exception handler.
class CatchProjNode : public CProjNode {
virtual uint hash() const;
- virtual uint cmp( const Node &n ) const;
+ virtual bool cmp( const Node &n ) const;
virtual uint size_of() const { return sizeof(*this); }
private:
diff --git a/src/hotspot/share/opto/graphKit.cpp b/src/hotspot/share/opto/graphKit.cpp
index ac2b91117fe..7a6eaa95a6f 100644
--- a/src/hotspot/share/opto/graphKit.cpp
+++ b/src/hotspot/share/opto/graphKit.cpp
@@ -2450,6 +2450,8 @@ Node* GraphKit::make_runtime_call(int flags,
Node* parm2, Node* parm3,
Node* parm4, Node* parm5,
Node* parm6, Node* parm7) {
+ assert(call_addr != NULL, "must not call NULL targets");
+
// Slow-path call
bool is_leaf = !(flags & RC_NO_LEAF);
bool has_io = (!is_leaf && !(flags & RC_NO_IO));
diff --git a/src/hotspot/share/opto/library_call.cpp b/src/hotspot/share/opto/library_call.cpp
index 70a5675ceed..bd3daf55db6 100644
--- a/src/hotspot/share/opto/library_call.cpp
+++ b/src/hotspot/share/opto/library_call.cpp
@@ -6353,6 +6353,9 @@ bool LibraryCallKit::inline_sha_implCompress(vmIntrinsics::ID id) {
}
if (state == NULL) return false;
+ assert(stubAddr != NULL, "Stub is generated");
+ if (stubAddr == NULL) return false;
+
// Call the stub.
Node* call = make_runtime_call(RC_LEAF|RC_NO_FP, OptoRuntime::sha_implCompress_Type(),
stubAddr, stubName, TypePtr::BOTTOM,
@@ -6425,6 +6428,9 @@ bool LibraryCallKit::inline_digestBase_implCompressMB(int predicate) {
fatal("unknown SHA intrinsic predicate: %d", predicate);
}
if (klass_SHA_name != NULL) {
+ assert(stub_addr != NULL, "Stub is generated");
+ if (stub_addr == NULL) return false;
+
// get DigestBase klass to lookup for SHA klass
const TypeInstPtr* tinst = _gvn.type(digestBase_obj)->isa_instptr();
assert(tinst != NULL, "digestBase_obj is not instance???");
diff --git a/src/hotspot/share/opto/locknode.cpp b/src/hotspot/share/opto/locknode.cpp
index 426ed9a67d2..7cb97f0d205 100644
--- a/src/hotspot/share/opto/locknode.cpp
+++ b/src/hotspot/share/opto/locknode.cpp
@@ -55,7 +55,7 @@ uint BoxLockNode::hash() const {
}
//------------------------------cmp--------------------------------------------
-uint BoxLockNode::cmp( const Node &n ) const {
+bool BoxLockNode::cmp( const Node &n ) const {
if (EliminateNestedLocks)
return (&n == this); // Always fail except on self
const BoxLockNode &bn = (const BoxLockNode &)n;
@@ -139,7 +139,7 @@ uint FastLockNode::hash() const { return NO_HASH; }
uint FastLockNode::size_of() const { return sizeof(*this); }
//------------------------------cmp--------------------------------------------
-uint FastLockNode::cmp( const Node &n ) const {
+bool FastLockNode::cmp( const Node &n ) const {
return (&n == this); // Always fail except on self
}
@@ -148,7 +148,7 @@ uint FastLockNode::cmp( const Node &n ) const {
uint FastUnlockNode::hash() const { return NO_HASH; }
//------------------------------cmp--------------------------------------------
-uint FastUnlockNode::cmp( const Node &n ) const {
+bool FastUnlockNode::cmp( const Node &n ) const {
return (&n == this); // Always fail except on self
}
diff --git a/src/hotspot/share/opto/locknode.hpp b/src/hotspot/share/opto/locknode.hpp
index ab7083c368e..ec47f41da26 100644
--- a/src/hotspot/share/opto/locknode.hpp
+++ b/src/hotspot/share/opto/locknode.hpp
@@ -47,7 +47,7 @@ public:
virtual const RegMask &out_RegMask() const;
virtual uint size_of() const;
virtual uint hash() const;
- virtual uint cmp( const Node &n ) const;
+ virtual bool cmp( const Node &n ) const;
virtual const class Type *bottom_type() const { return TypeRawPtr::BOTTOM; }
virtual uint ideal_reg() const { return Op_RegP; }
@@ -94,7 +94,7 @@ public:
// LockNode/UnLockNode to avoid creating Phi's.
virtual uint hash() const ; // { return NO_HASH; }
virtual uint size_of() const;
- virtual uint cmp( const Node &n ) const ; // Always fail, except on self
+ virtual bool cmp( const Node &n ) const ; // Always fail, except on self
virtual int Opcode() const;
virtual const Type* Value(PhaseGVN* phase) const { return TypeInt::CC; }
const Type *sub(const Type *t1, const Type *t2) const { return TypeInt::CC;}
@@ -121,7 +121,7 @@ public:
// FastLock and FastUnlockNode do not hash, we need one for each correspoding
// LockNode/UnLockNode to avoid creating Phi's.
virtual uint hash() const ; // { return NO_HASH; }
- virtual uint cmp( const Node &n ) const ; // Always fail, except on self
+ virtual bool cmp( const Node &n ) const ; // Always fail, except on self
virtual int Opcode() const;
virtual const Type* Value(PhaseGVN* phase) const { return TypeInt::CC; }
const Type *sub(const Type *t1, const Type *t2) const { return TypeInt::CC;}
diff --git a/src/hotspot/share/opto/machnode.cpp b/src/hotspot/share/opto/machnode.cpp
index 737cca80b1f..247ace88284 100644
--- a/src/hotspot/share/opto/machnode.cpp
+++ b/src/hotspot/share/opto/machnode.cpp
@@ -93,7 +93,7 @@ uint MachOper::hash() const {
//------------------------------cmp--------------------------------------------
// Print any per-operand special info
-uint MachOper::cmp( const MachOper &oper ) const {
+bool MachOper::cmp( const MachOper &oper ) const {
ShouldNotCallThis();
return opcode() == oper.opcode();
}
@@ -106,7 +106,7 @@ uint labelOper::hash() const {
//------------------------------cmp--------------------------------------------
// Print any per-operand special info
-uint labelOper::cmp( const MachOper &oper ) const {
+bool labelOper::cmp( const MachOper &oper ) const {
return (opcode() == oper.opcode()) && (_label == oper.label());
}
@@ -118,7 +118,7 @@ uint methodOper::hash() const {
//------------------------------cmp--------------------------------------------
// Print any per-operand special info
-uint methodOper::cmp( const MachOper &oper ) const {
+bool methodOper::cmp( const MachOper &oper ) const {
return (opcode() == oper.opcode()) && (_method == oper.method());
}
@@ -167,15 +167,15 @@ uint MachNode::hash() const {
}
//-----------------------------cmp---------------------------------------------
-uint MachNode::cmp( const Node &node ) const {
+bool MachNode::cmp( const Node &node ) const {
MachNode& n = *((Node&)node).as_Mach();
uint no = num_opnds();
- if( no != n.num_opnds() ) return 0;
- if( rule() != n.rule() ) return 0;
+ if( no != n.num_opnds() ) return false;
+ if( rule() != n.rule() ) return false;
for( uint i=0; icmp( *n._opnds[i] ) )
- return 0; // mis-matched operands
- return 1; // match
+ return false; // mis-matched operands
+ return true; // match
}
// Return an equivalent instruction using memory for cisc_operand position
@@ -651,7 +651,7 @@ const RegMask &MachSafePointNode::in_RegMask( uint idx ) const {
//=============================================================================
-uint MachCallNode::cmp( const Node &n ) const
+bool MachCallNode::cmp( const Node &n ) const
{ return _tf == ((MachCallNode&)n)._tf; }
const Type *MachCallNode::bottom_type() const { return tf()->range(); }
const Type* MachCallNode::Value(PhaseGVN* phase) const { return tf()->range(); }
@@ -707,7 +707,7 @@ const RegMask &MachCallNode::in_RegMask(uint idx) const {
//=============================================================================
uint MachCallJavaNode::size_of() const { return sizeof(*this); }
-uint MachCallJavaNode::cmp( const Node &n ) const {
+bool MachCallJavaNode::cmp( const Node &n ) const {
MachCallJavaNode &call = (MachCallJavaNode&)n;
return MachCallNode::cmp(call) && _method->equals(call._method) &&
_override_symbolic_info == call._override_symbolic_info;
@@ -745,7 +745,7 @@ const RegMask &MachCallJavaNode::in_RegMask(uint idx) const {
//=============================================================================
uint MachCallStaticJavaNode::size_of() const { return sizeof(*this); }
-uint MachCallStaticJavaNode::cmp( const Node &n ) const {
+bool MachCallStaticJavaNode::cmp( const Node &n ) const {
MachCallStaticJavaNode &call = (MachCallStaticJavaNode&)n;
return MachCallJavaNode::cmp(call) && _name == call._name;
}
@@ -791,7 +791,7 @@ void MachCallDynamicJavaNode::dump_spec(outputStream *st) const {
#endif
//=============================================================================
uint MachCallRuntimeNode::size_of() const { return sizeof(*this); }
-uint MachCallRuntimeNode::cmp( const Node &n ) const {
+bool MachCallRuntimeNode::cmp( const Node &n ) const {
MachCallRuntimeNode &call = (MachCallRuntimeNode&)n;
return MachCallNode::cmp(call) && !strcmp(_name,call._name);
}
diff --git a/src/hotspot/share/opto/machnode.hpp b/src/hotspot/share/opto/machnode.hpp
index 27756834ab8..78da59e6828 100644
--- a/src/hotspot/share/opto/machnode.hpp
+++ b/src/hotspot/share/opto/machnode.hpp
@@ -161,7 +161,7 @@ public:
// Hash and compare over operands are currently identical
virtual uint hash() const;
- virtual uint cmp( const MachOper &oper ) const;
+ virtual bool cmp( const MachOper &oper ) const;
// Virtual clone, since I do not know how big the MachOper is.
virtual MachOper *clone() const = 0;
@@ -292,7 +292,7 @@ public:
// Hash and compare over operands. Used to do GVN on machine Nodes.
virtual uint hash() const;
- virtual uint cmp( const Node &n ) const;
+ virtual bool cmp( const Node &n ) const;
// Expand method for MachNode, replaces nodes representing pseudo
// instructions with a set of nodes which represent real machine
@@ -861,7 +861,7 @@ public:
class MachCallNode : public MachSafePointNode {
protected:
virtual uint hash() const { return NO_HASH; } // CFG nodes do not hash
- virtual uint cmp( const Node &n ) const;
+ virtual bool cmp( const Node &n ) const;
virtual uint size_of() const = 0; // Size is bigger
public:
const TypeFunc *_tf; // Function type
@@ -904,7 +904,7 @@ public:
// "Base" class for machine-specific versions of subroutine calls
class MachCallJavaNode : public MachCallNode {
protected:
- virtual uint cmp( const Node &n ) const;
+ virtual bool cmp( const Node &n ) const;
virtual uint size_of() const; // Size is bigger
public:
ciMethod* _method; // Method being direct called
@@ -937,7 +937,7 @@ public:
//------------------------------MachCallStaticJavaNode------------------------
// Machine-specific versions of monomorphic subroutine calls
class MachCallStaticJavaNode : public MachCallJavaNode {
- virtual uint cmp( const Node &n ) const;
+ virtual bool cmp( const Node &n ) const;
virtual uint size_of() const; // Size is bigger
public:
const char *_name; // Runtime wrapper name
@@ -973,7 +973,7 @@ public:
//------------------------------MachCallRuntimeNode----------------------------
// Machine-specific versions of subroutine calls
class MachCallRuntimeNode : public MachCallNode {
- virtual uint cmp( const Node &n ) const;
+ virtual bool cmp( const Node &n ) const;
virtual uint size_of() const; // Size is bigger
public:
const char *_name; // Printable name, if _method is NULL
@@ -1066,7 +1066,7 @@ public:
virtual uint opcode() const;
virtual uint hash() const;
- virtual uint cmp( const MachOper &oper ) const;
+ virtual bool cmp( const MachOper &oper ) const;
#ifndef PRODUCT
virtual const char *Name() const { return "Label";}
@@ -1093,7 +1093,7 @@ public:
virtual uint opcode() const;
virtual uint hash() const;
- virtual uint cmp( const MachOper &oper ) const;
+ virtual bool cmp( const MachOper &oper ) const;
#ifndef PRODUCT
virtual const char *Name() const { return "Method";}
diff --git a/src/hotspot/share/opto/matcher.cpp b/src/hotspot/share/opto/matcher.cpp
index d00f66ec675..53cbc6e4ce1 100644
--- a/src/hotspot/share/opto/matcher.cpp
+++ b/src/hotspot/share/opto/matcher.cpp
@@ -416,14 +416,20 @@ static RegMask *init_input_masks( uint size, RegMask &ret_adr, RegMask &fp ) {
return rms;
}
-//---------------------------init_first_stack_mask-----------------------------
+#define NOF_STACK_MASKS (3*6+5)
+
// Create the initial stack mask used by values spilling to the stack.
// Disallow any debug info in outgoing argument areas by setting the
// initial mask accordingly.
void Matcher::init_first_stack_mask() {
// Allocate storage for spill masks as masks for the appropriate load type.
- RegMask *rms = (RegMask*)C->comp_arena()->Amalloc_D(sizeof(RegMask) * (3*6+5));
+ RegMask *rms = (RegMask*)C->comp_arena()->Amalloc_D(sizeof(RegMask) * NOF_STACK_MASKS);
+
+ // Initialize empty placeholder masks into the newly allocated arena
+ for (int i = 0; i < NOF_STACK_MASKS; i++) {
+ new (rms + i) RegMask();
+ }
idealreg2spillmask [Op_RegN] = &rms[0];
idealreg2spillmask [Op_RegI] = &rms[1];
diff --git a/src/hotspot/share/opto/memnode.cpp b/src/hotspot/share/opto/memnode.cpp
index dc81f976d5c..53b9df27ca9 100644
--- a/src/hotspot/share/opto/memnode.cpp
+++ b/src/hotspot/share/opto/memnode.cpp
@@ -758,7 +758,7 @@ bool LoadNode::can_remove_control() const {
return true;
}
uint LoadNode::size_of() const { return sizeof(*this); }
-uint LoadNode::cmp( const Node &n ) const
+bool LoadNode::cmp( const Node &n ) const
{ return !Type::cmp( _type, ((LoadNode&)n)._type ); }
const Type *LoadNode::bottom_type() const { return _type; }
uint LoadNode::ideal_reg() const {
@@ -2627,7 +2627,7 @@ uint StoreNode::match_edge(uint idx) const {
//------------------------------cmp--------------------------------------------
// Do not common stores up together. They generally have to be split
// back up anyways, so do not bother.
-uint StoreNode::cmp( const Node &n ) const {
+bool StoreNode::cmp( const Node &n ) const {
return (&n == this); // Always fail except on self
}
@@ -3057,7 +3057,7 @@ MemBarNode::MemBarNode(Compile* C, int alias_idx, Node* precedent)
//------------------------------cmp--------------------------------------------
uint MemBarNode::hash() const { return NO_HASH; }
-uint MemBarNode::cmp( const Node &n ) const {
+bool MemBarNode::cmp( const Node &n ) const {
return (&n == this); // Always fail except on self
}
@@ -4438,7 +4438,7 @@ MergeMemNode* MergeMemNode::make(Node* mem) {
//------------------------------cmp--------------------------------------------
uint MergeMemNode::hash() const { return NO_HASH; }
-uint MergeMemNode::cmp( const Node &n ) const {
+bool MergeMemNode::cmp( const Node &n ) const {
return (&n == this); // Always fail except on self
}
diff --git a/src/hotspot/share/opto/memnode.hpp b/src/hotspot/share/opto/memnode.hpp
index 89c0a8c8840..de75dbccd6f 100644
--- a/src/hotspot/share/opto/memnode.hpp
+++ b/src/hotspot/share/opto/memnode.hpp
@@ -183,7 +183,7 @@ private:
const MemOrd _mo;
protected:
- virtual uint cmp(const Node &n) const;
+ virtual bool cmp(const Node &n) const;
virtual uint size_of() const; // Size is bigger
// Should LoadNode::Ideal() attempt to remove control edges?
virtual bool can_remove_control() const;
@@ -373,7 +373,7 @@ public:
// Load a long from memory
class LoadLNode : public LoadNode {
virtual uint hash() const { return LoadNode::hash() + _require_atomic_access; }
- virtual uint cmp( const Node &n ) const {
+ virtual bool cmp( const Node &n ) const {
return _require_atomic_access == ((LoadLNode&)n)._require_atomic_access
&& LoadNode::cmp(n);
}
@@ -425,7 +425,7 @@ public:
// Load a double (64 bits) from memory
class LoadDNode : public LoadNode {
virtual uint hash() const { return LoadNode::hash() + _require_atomic_access; }
- virtual uint cmp( const Node &n ) const {
+ virtual bool cmp( const Node &n ) const {
return _require_atomic_access == ((LoadDNode&)n)._require_atomic_access
&& LoadNode::cmp(n);
}
@@ -535,7 +535,7 @@ private:
// Needed for proper cloning.
virtual uint size_of() const { return sizeof(*this); }
protected:
- virtual uint cmp( const Node &n ) const;
+ virtual bool cmp( const Node &n ) const;
virtual bool depends_only_on_test() const { return false; }
Node *Ideal_masked_input (PhaseGVN *phase, uint mask);
@@ -650,7 +650,7 @@ public:
// Store long to memory
class StoreLNode : public StoreNode {
virtual uint hash() const { return StoreNode::hash() + _require_atomic_access; }
- virtual uint cmp( const Node &n ) const {
+ virtual bool cmp( const Node &n ) const {
return _require_atomic_access == ((StoreLNode&)n)._require_atomic_access
&& StoreNode::cmp(n);
}
@@ -686,7 +686,7 @@ public:
// Store double to memory
class StoreDNode : public StoreNode {
virtual uint hash() const { return StoreNode::hash() + _require_atomic_access; }
- virtual uint cmp( const Node &n ) const {
+ virtual bool cmp( const Node &n ) const {
return _require_atomic_access == ((StoreDNode&)n)._require_atomic_access
&& StoreNode::cmp(n);
}
@@ -746,7 +746,7 @@ public:
class StoreCMNode : public StoreNode {
private:
virtual uint hash() const { return StoreNode::hash() + _oop_alias_idx; }
- virtual uint cmp( const Node &n ) const {
+ virtual bool cmp( const Node &n ) const {
return _oop_alias_idx == ((StoreCMNode&)n)._oop_alias_idx
&& StoreNode::cmp(n);
}
@@ -1142,7 +1142,7 @@ public:
// separate it from any following volatile-load.
class MemBarNode: public MultiNode {
virtual uint hash() const ; // { return NO_HASH; }
- virtual uint cmp( const Node &n ) const ; // Always fail, except on self
+ virtual bool cmp( const Node &n ) const ; // Always fail, except on self
virtual uint size_of() const { return sizeof(*this); }
// Memory type this node is serializing. Usually either rawptr or bottom.
@@ -1399,7 +1399,7 @@ public:
// (See comment in memnode.cpp near MergeMemNode::MergeMemNode for semantics.)
class MergeMemNode: public Node {
virtual uint hash() const ; // { return NO_HASH; }
- virtual uint cmp( const Node &n ) const ; // Always fail, except on self
+ virtual bool cmp( const Node &n ) const ; // Always fail, except on self
friend class MergeMemStream;
MergeMemNode(Node* def); // clients use MergeMemNode::make
diff --git a/src/hotspot/share/opto/multnode.cpp b/src/hotspot/share/opto/multnode.cpp
index 389ef5fd165..c2c35e38830 100644
--- a/src/hotspot/share/opto/multnode.cpp
+++ b/src/hotspot/share/opto/multnode.cpp
@@ -76,7 +76,7 @@ uint ProjNode::hash() const {
// only one input
return (uintptr_t)in(TypeFunc::Control) + (_con << 1) + (_is_io_use ? 1 : 0);
}
-uint ProjNode::cmp( const Node &n ) const { return _con == ((ProjNode&)n)._con && ((ProjNode&)n)._is_io_use == _is_io_use; }
+bool ProjNode::cmp( const Node &n ) const { return _con == ((ProjNode&)n)._con && ((ProjNode&)n)._is_io_use == _is_io_use; }
uint ProjNode::size_of() const { return sizeof(ProjNode); }
// Test if we propagate interesting control along this projection
diff --git a/src/hotspot/share/opto/multnode.hpp b/src/hotspot/share/opto/multnode.hpp
index bb1492acb9d..291578ace2a 100644
--- a/src/hotspot/share/opto/multnode.hpp
+++ b/src/hotspot/share/opto/multnode.hpp
@@ -58,7 +58,7 @@ public:
class ProjNode : public Node {
protected:
virtual uint hash() const;
- virtual uint cmp( const Node &n ) const;
+ virtual bool cmp( const Node &n ) const;
virtual uint size_of() const;
void check_con() const; // Called from constructor.
const Type* proj_type(const Type* t) const;
diff --git a/src/hotspot/share/opto/node.cpp b/src/hotspot/share/opto/node.cpp
index f0f5b953725..ed7aac78e14 100644
--- a/src/hotspot/share/opto/node.cpp
+++ b/src/hotspot/share/opto/node.cpp
@@ -1433,8 +1433,8 @@ uint Node::hash() const {
//------------------------------cmp--------------------------------------------
// Compare special parts of simple Nodes
-uint Node::cmp( const Node &n ) const {
- return 1; // Must be same
+bool Node::cmp( const Node &n ) const {
+ return true; // Must be same
}
//------------------------------rematerialize-----------------------------------
@@ -2452,7 +2452,7 @@ void TypeNode::dump_compact_spec(outputStream *st) const {
uint TypeNode::hash() const {
return Node::hash() + _type->hash();
}
-uint TypeNode::cmp( const Node &n ) const
+bool TypeNode::cmp( const Node &n ) const
{ return !Type::cmp( _type, ((TypeNode&)n)._type ); }
const Type *TypeNode::bottom_type() const { return _type; }
const Type* TypeNode::Value(PhaseGVN* phase) const { return _type; }
diff --git a/src/hotspot/share/opto/node.hpp b/src/hotspot/share/opto/node.hpp
index d8be310a289..2f02b98bda7 100644
--- a/src/hotspot/share/opto/node.hpp
+++ b/src/hotspot/share/opto/node.hpp
@@ -1003,7 +1003,7 @@ public:
// won't go into the table and we'll lose a little optimization.
enum { NO_HASH = 0 };
virtual uint hash() const;
- virtual uint cmp( const Node &n ) const;
+ virtual bool cmp( const Node &n ) const;
// Operation appears to be iteratively computed (such as an induction variable)
// It is possible for this operation to return false for a loop-varying
@@ -1718,7 +1718,7 @@ Compile::set_node_notes_at(int idx, Node_Notes* value) {
class TypeNode : public Node {
protected:
virtual uint hash() const; // Check the type
- virtual uint cmp( const Node &n ) const;
+ virtual bool cmp( const Node &n ) const;
virtual uint size_of() const; // Size is bigger
const Type* const _type;
public:
diff --git a/src/hotspot/share/opto/opaquenode.cpp b/src/hotspot/share/opto/opaquenode.cpp
index cccd5b581af..fd9ad8a57e7 100644
--- a/src/hotspot/share/opto/opaquenode.cpp
+++ b/src/hotspot/share/opto/opaquenode.cpp
@@ -29,7 +29,7 @@
//=============================================================================
// Do not allow value-numbering
uint Opaque1Node::hash() const { return NO_HASH; }
-uint Opaque1Node::cmp( const Node &n ) const {
+bool Opaque1Node::cmp( const Node &n ) const {
return (&n == this); // Always fail except on self
}
@@ -56,7 +56,7 @@ Node* Opaque1Node::Identity(PhaseGVN* phase) {
// Do not allow value-numbering
uint Opaque2Node::hash() const { return NO_HASH; }
-uint Opaque2Node::cmp( const Node &n ) const {
+bool Opaque2Node::cmp( const Node &n ) const {
return (&n == this); // Always fail except on self
}
@@ -67,7 +67,7 @@ const Type* Opaque4Node::Value(PhaseGVN* phase) const {
//=============================================================================
uint ProfileBooleanNode::hash() const { return NO_HASH; }
-uint ProfileBooleanNode::cmp( const Node &n ) const {
+bool ProfileBooleanNode::cmp( const Node &n ) const {
return (&n == this);
}
diff --git a/src/hotspot/share/opto/opaquenode.hpp b/src/hotspot/share/opto/opaquenode.hpp
index 77f544c49f0..18cbbb08c64 100644
--- a/src/hotspot/share/opto/opaquenode.hpp
+++ b/src/hotspot/share/opto/opaquenode.hpp
@@ -33,7 +33,7 @@
// Stops value-numbering, Ideal calls or Identity functions.
class Opaque1Node : public Node {
virtual uint hash() const ; // { return NO_HASH; }
- virtual uint cmp( const Node &n ) const;
+ virtual bool cmp( const Node &n ) const;
public:
Opaque1Node(Compile* C, Node *n) : Node(NULL, n) {
// Put it on the Macro nodes list to removed during macro nodes expansion.
@@ -64,7 +64,7 @@ class Opaque1Node : public Node {
// it's OK to be slightly sloppy on optimizations here.
class Opaque2Node : public Node {
virtual uint hash() const ; // { return NO_HASH; }
- virtual uint cmp( const Node &n ) const;
+ virtual bool cmp( const Node &n ) const;
public:
Opaque2Node( Compile* C, Node *n ) : Node(0,n) {
// Put it on the Macro nodes list to removed during macro nodes expansion.
@@ -117,7 +117,7 @@ class ProfileBooleanNode : public Node {
bool _consumed;
bool _delay_removal;
virtual uint hash() const ; // { return NO_HASH; }
- virtual uint cmp( const Node &n ) const;
+ virtual bool cmp( const Node &n ) const;
public:
ProfileBooleanNode(Node *n, uint false_cnt, uint true_cnt) : Node(0, n),
_false_cnt(false_cnt), _true_cnt(true_cnt), _consumed(false), _delay_removal(true) {}
diff --git a/src/hotspot/share/opto/subnode.cpp b/src/hotspot/share/opto/subnode.cpp
index f2e416d6c61..94c9a5b629c 100644
--- a/src/hotspot/share/opto/subnode.cpp
+++ b/src/hotspot/share/opto/subnode.cpp
@@ -1279,7 +1279,7 @@ uint BoolNode::hash() const { return (Node::hash() << 3)|(_test._test+1); }
uint BoolNode::size_of() const { return sizeof(BoolNode); }
//------------------------------operator==-------------------------------------
-uint BoolNode::cmp( const Node &n ) const {
+bool BoolNode::cmp( const Node &n ) const {
const BoolNode *b = (const BoolNode *)&n; // Cast up
return (_test._test == b->_test._test);
}
diff --git a/src/hotspot/share/opto/subnode.hpp b/src/hotspot/share/opto/subnode.hpp
index e7a30e26bb7..c29d9cdffc9 100644
--- a/src/hotspot/share/opto/subnode.hpp
+++ b/src/hotspot/share/opto/subnode.hpp
@@ -300,7 +300,7 @@ struct BoolTest {
// A Node to convert a Condition Codes to a Logical result.
class BoolNode : public Node {
virtual uint hash() const;
- virtual uint cmp( const Node &n ) const;
+ virtual bool cmp( const Node &n ) const;
virtual uint size_of() const;
// Try to optimize signed integer comparison
diff --git a/src/hotspot/share/prims/jvmtiEnv.cpp b/src/hotspot/share/prims/jvmtiEnv.cpp
index 9cc31c9bf67..acebf0fecd6 100644
--- a/src/hotspot/share/prims/jvmtiEnv.cpp
+++ b/src/hotspot/share/prims/jvmtiEnv.cpp
@@ -74,6 +74,7 @@
#include "services/threadService.hpp"
#include "utilities/exceptions.hpp"
#include "utilities/preserveException.hpp"
+#include "utilities/utf8.hpp"
#define FIXLATER 0 // REMOVE this when completed.
diff --git a/src/hotspot/share/prims/jvmtiEnvBase.cpp b/src/hotspot/share/prims/jvmtiEnvBase.cpp
index 7bac414eb74..39b8238862f 100644
--- a/src/hotspot/share/prims/jvmtiEnvBase.cpp
+++ b/src/hotspot/share/prims/jvmtiEnvBase.cpp
@@ -24,6 +24,7 @@
#include "precompiled.hpp"
#include "classfile/classLoaderDataGraph.hpp"
+#include "classfile/moduleEntry.hpp"
#include "classfile/systemDictionary.hpp"
#include "jvmtifiles/jvmtiEnv.hpp"
#include "memory/resourceArea.hpp"
diff --git a/src/hotspot/share/prims/jvmtiExport.cpp b/src/hotspot/share/prims/jvmtiExport.cpp
index 5a5bb069730..d10f568f176 100644
--- a/src/hotspot/share/prims/jvmtiExport.cpp
+++ b/src/hotspot/share/prims/jvmtiExport.cpp
@@ -24,6 +24,7 @@
#include "precompiled.hpp"
#include "classfile/javaClasses.inline.hpp"
+#include "classfile/moduleEntry.hpp"
#include "classfile/systemDictionary.hpp"
#include "code/nmethod.hpp"
#include "code/pcDesc.hpp"
diff --git a/src/hotspot/share/prims/jvmtiRedefineClasses.cpp b/src/hotspot/share/prims/jvmtiRedefineClasses.cpp
index 56e82986f1d..abe6a3b0eff 100644
--- a/src/hotspot/share/prims/jvmtiRedefineClasses.cpp
+++ b/src/hotspot/share/prims/jvmtiRedefineClasses.cpp
@@ -207,7 +207,7 @@ void VM_RedefineClasses::doit() {
// Mark methods seen on stack and everywhere else so old methods are not
// cleaned up if they're on the stack.
- MetadataOnStackMark md_on_stack(true);
+ MetadataOnStackMark md_on_stack(/*walk_all_metadata*/true, /*redefinition_walk*/true);
HandleMark hm(thread); // make sure any handles created are deleted
// before the stack walk again.
@@ -3842,7 +3842,7 @@ void VM_RedefineClasses::flush_dependent_code() {
// This is the first redefinition, mark all the nmethods for deoptimization
if (!JvmtiExport::all_dependencies_are_recorded()) {
log_debug(redefine, class, nmethod)("Marked all nmethods for deopt");
- CodeCache::mark_all_nmethods_for_deoptimization();
+ CodeCache::mark_all_nmethods_for_evol_deoptimization();
deopt_needed = true;
} else {
int deopt = CodeCache::mark_dependents_for_evol_deoptimization();
diff --git a/src/hotspot/share/prims/nativeLookup.cpp b/src/hotspot/share/prims/nativeLookup.cpp
index 0df8871754b..690e23738ea 100644
--- a/src/hotspot/share/prims/nativeLookup.cpp
+++ b/src/hotspot/share/prims/nativeLookup.cpp
@@ -43,6 +43,7 @@
#include "runtime/sharedRuntime.hpp"
#include "runtime/signature.hpp"
#include "utilities/macros.hpp"
+#include "utilities/utf8.hpp"
#if INCLUDE_JFR
#include "jfr/jfr.hpp"
#endif
diff --git a/src/hotspot/share/prims/unsafe.cpp b/src/hotspot/share/prims/unsafe.cpp
index ef241cb4f36..4f5404f5ca3 100644
--- a/src/hotspot/share/prims/unsafe.cpp
+++ b/src/hotspot/share/prims/unsafe.cpp
@@ -26,6 +26,7 @@
#include "jni.h"
#include "jvm.h"
#include "classfile/classFileStream.hpp"
+#include "classfile/classLoader.hpp"
#include "classfile/vmSymbols.hpp"
#include "jfr/jfrEvents.hpp"
#include "memory/allocation.inline.hpp"
diff --git a/src/hotspot/share/runtime/arguments.cpp b/src/hotspot/share/runtime/arguments.cpp
index 95a0d93ab6a..18d9f7663fb 100644
--- a/src/hotspot/share/runtime/arguments.cpp
+++ b/src/hotspot/share/runtime/arguments.cpp
@@ -2875,6 +2875,20 @@ jint Arguments::parse_each_vm_init_arg(const JavaVMInitArgs* args, bool* patch_m
if (FLAG_SET_CMDLINE(bool, DisplayVMOutputToStdout, true) != JVMFlag::SUCCESS) {
return JNI_EINVAL;
}
+ } else if (match_option(option, "-XX:+ErrorFileToStderr")) {
+ if (FLAG_SET_CMDLINE(bool, ErrorFileToStdout, false) != JVMFlag::SUCCESS) {
+ return JNI_EINVAL;
+ }
+ if (FLAG_SET_CMDLINE(bool, ErrorFileToStderr, true) != JVMFlag::SUCCESS) {
+ return JNI_EINVAL;
+ }
+ } else if (match_option(option, "-XX:+ErrorFileToStdout")) {
+ if (FLAG_SET_CMDLINE(bool, ErrorFileToStderr, false) != JVMFlag::SUCCESS) {
+ return JNI_EINVAL;
+ }
+ if (FLAG_SET_CMDLINE(bool, ErrorFileToStdout, true) != JVMFlag::SUCCESS) {
+ return JNI_EINVAL;
+ }
} else if (match_option(option, "-XX:+ExtendedDTraceProbes")) {
#if defined(DTRACE_ENABLED)
if (FLAG_SET_CMDLINE(bool, ExtendedDTraceProbes, true) != JVMFlag::SUCCESS) {
diff --git a/src/hotspot/share/runtime/frame.cpp b/src/hotspot/share/runtime/frame.cpp
index 6a74f484291..a12d4cb7d14 100644
--- a/src/hotspot/share/runtime/frame.cpp
+++ b/src/hotspot/share/runtime/frame.cpp
@@ -23,6 +23,7 @@
*/
#include "precompiled.hpp"
+#include "classfile/moduleEntry.hpp"
#include "code/codeCache.hpp"
#include "code/vmreg.inline.hpp"
#include "compiler/abstractCompiler.hpp"
diff --git a/src/hotspot/share/runtime/globals.hpp b/src/hotspot/share/runtime/globals.hpp
index 23a36ea3dbb..44cd98dca5a 100644
--- a/src/hotspot/share/runtime/globals.hpp
+++ b/src/hotspot/share/runtime/globals.hpp
@@ -371,6 +371,10 @@ define_pd_global(uint64_t,MaxRAM, 1ULL*G);
"Generate a lot of safepoints. This works with " \
"GuaranteedSafepointInterval") \
\
+ diagnostic(bool, HandshakeALot, false, \
+ "Generate a lot of handshakes. This works with " \
+ "GuaranteedSafepointInterval") \
+ \
product_pd(bool, BackgroundCompilation, \
"A thread requesting compilation is not blocked during " \
"compilation") \
@@ -1263,6 +1267,12 @@ define_pd_global(uint64_t,MaxRAM, 1ULL*G);
product(bool, DisplayVMOutputToStdout, false, \
"If DisplayVMOutput is true, display all VM output to stdout") \
\
+ product(bool, ErrorFileToStderr, false, \
+ "If true, error data is printed to stderr instead of a file") \
+ \
+ product(bool, ErrorFileToStdout, false, \
+ "If true, error data is printed to stdout instead of a file") \
+ \
product(bool, UseHeavyMonitors, false, \
"use heavyweight instead of lightweight Java monitors") \
\
diff --git a/src/hotspot/share/runtime/handshake.cpp b/src/hotspot/share/runtime/handshake.cpp
index cbe5ebe5b04..887c4d9d024 100644
--- a/src/hotspot/share/runtime/handshake.cpp
+++ b/src/hotspot/share/runtime/handshake.cpp
@@ -281,7 +281,7 @@ void HandshakeState::set_operation(JavaThread* target, HandshakeOperation* op) {
void HandshakeState::clear_handshake(JavaThread* target) {
_operation = NULL;
- SafepointMechanism::disarm_local_poll_release(target);
+ SafepointMechanism::disarm_if_needed(target, true /* release */);
}
void HandshakeState::process_self_inner(JavaThread* thread) {
diff --git a/src/hotspot/share/runtime/init.cpp b/src/hotspot/share/runtime/init.cpp
index 772987c02fb..2149aef1173 100644
--- a/src/hotspot/share/runtime/init.cpp
+++ b/src/hotspot/share/runtime/init.cpp
@@ -36,6 +36,7 @@
#include "runtime/handles.inline.hpp"
#include "runtime/icache.hpp"
#include "runtime/init.hpp"
+#include "runtime/orderAccess.hpp"
#include "runtime/safepoint.hpp"
#include "runtime/sharedRuntime.hpp"
#include "services/memTracker.hpp"
@@ -186,11 +187,19 @@ void exit_globals() {
static volatile bool _init_completed = false;
bool is_init_completed() {
- return _init_completed;
+ return OrderAccess::load_acquire(&_init_completed);
}
+void wait_init_completed() {
+ MonitorLockerEx ml(InitCompleted_lock, Monitor::_no_safepoint_check_flag);
+ while (!_init_completed) {
+ ml.wait(Monitor::_no_safepoint_check_flag);
+ }
+}
void set_init_completed() {
assert(Universe::is_fully_initialized(), "Should have completed initialization");
- _init_completed = true;
+ MonitorLockerEx ml(InitCompleted_lock, Monitor::_no_safepoint_check_flag);
+ OrderAccess::release_store(&_init_completed, true);
+ ml.notify_all();
}
diff --git a/src/hotspot/share/runtime/init.hpp b/src/hotspot/share/runtime/init.hpp
index 005ee3872e3..e32e1f7d96c 100644
--- a/src/hotspot/share/runtime/init.hpp
+++ b/src/hotspot/share/runtime/init.hpp
@@ -40,6 +40,7 @@ void vm_init_globals(); // call constructors at startup (VM thread)
void exit_globals(); // call destructors before exit
bool is_init_completed(); // returns true when bootstrapping has completed
+void wait_init_completed(); // wait until set_init_completed() has been called
void set_init_completed(); // set basic init to completed
#endif // SHARE_RUNTIME_INIT_HPP
diff --git a/src/hotspot/share/runtime/interfaceSupport.inline.hpp b/src/hotspot/share/runtime/interfaceSupport.inline.hpp
index a0df8244f18..b4c69eb7a1d 100644
--- a/src/hotspot/share/runtime/interfaceSupport.inline.hpp
+++ b/src/hotspot/share/runtime/interfaceSupport.inline.hpp
@@ -34,6 +34,7 @@
#include "runtime/thread.hpp"
#include "runtime/vmOperations.hpp"
#include "utilities/globalDefinitions.hpp"
+#include "utilities/histogram.hpp"
#include "utilities/macros.hpp"
#include "utilities/preserveException.hpp"
@@ -282,6 +283,7 @@ class ThreadBlockInVM : public ThreadStateTransition {
}
~ThreadBlockInVM() {
trans_and_fence(_thread_blocked, _thread_in_vm);
+ OrderAccess::cross_modify_fence();
// We don't need to clear_walkable because it will happen automagically when we return to java
}
};
@@ -336,6 +338,8 @@ class ThreadBlockInVMWithDeadlockCheck : public ThreadStateTransition {
_thread->set_thread_state(_thread_in_vm);
CHECK_UNHANDLED_OOPS_ONLY(_thread->clear_unhandled_oops();)
+
+ OrderAccess::cross_modify_fence();
}
};
diff --git a/src/hotspot/share/runtime/mutex.hpp b/src/hotspot/share/runtime/mutex.hpp
index 91751c6d212..b0d6c57a89f 100644
--- a/src/hotspot/share/runtime/mutex.hpp
+++ b/src/hotspot/share/runtime/mutex.hpp
@@ -27,8 +27,6 @@
#include "memory/allocation.hpp"
#include "runtime/os.hpp"
-#include "utilities/histogram.hpp"
-
// A Mutex/Monitor is a simple wrapper around a native lock plus condition
// variable that supports lock ownership tracking, lock ranking for deadlock
diff --git a/src/hotspot/share/runtime/mutexLocker.cpp b/src/hotspot/share/runtime/mutexLocker.cpp
index 8b950c99f0a..a53681e1111 100644
--- a/src/hotspot/share/runtime/mutexLocker.cpp
+++ b/src/hotspot/share/runtime/mutexLocker.cpp
@@ -76,6 +76,7 @@ Monitor* VMOperationRequest_lock = NULL;
Monitor* SerializePage_lock = NULL;
Monitor* Threads_lock = NULL;
Mutex* NonJavaThreadsList_lock = NULL;
+Mutex* NonJavaThreadsListSync_lock = NULL;
Monitor* CGC_lock = NULL;
Monitor* STS_lock = NULL;
Monitor* FullGCCount_lock = NULL;
@@ -97,6 +98,7 @@ Mutex* CompileStatistics_lock = NULL;
Mutex* DirectivesStack_lock = NULL;
Mutex* MultiArray_lock = NULL;
Monitor* Terminator_lock = NULL;
+Monitor* InitCompleted_lock = NULL;
Monitor* BeforeExit_lock = NULL;
Monitor* Notify_lock = NULL;
Mutex* ProfilePrint_lock = NULL;
@@ -278,11 +280,13 @@ void mutex_init() {
def(Threads_lock , PaddedMonitor, barrier, true, Monitor::_safepoint_check_sometimes);
def(NonJavaThreadsList_lock , PaddedMutex, leaf, true, Monitor::_safepoint_check_never);
+ def(NonJavaThreadsListSync_lock , PaddedMutex, leaf, true, Monitor::_safepoint_check_never);
def(VMOperationQueue_lock , PaddedMonitor, nonleaf, true, Monitor::_safepoint_check_sometimes); // VM_thread allowed to block on these
def(VMOperationRequest_lock , PaddedMonitor, nonleaf, true, Monitor::_safepoint_check_sometimes);
def(RetData_lock , PaddedMutex , nonleaf, false, Monitor::_safepoint_check_always);
def(Terminator_lock , PaddedMonitor, nonleaf, true, Monitor::_safepoint_check_sometimes);
+ def(InitCompleted_lock , PaddedMonitor, leaf, true, Monitor::_safepoint_check_never);
def(VtableStubs_lock , PaddedMutex , nonleaf, true, Monitor::_safepoint_check_never);
def(Notify_lock , PaddedMonitor, nonleaf, true, Monitor::_safepoint_check_always);
def(JNIGlobalAlloc_lock , PaddedMutex , nonleaf, true, Monitor::_safepoint_check_never);
diff --git a/src/hotspot/share/runtime/mutexLocker.hpp b/src/hotspot/share/runtime/mutexLocker.hpp
index 34e552a9c7f..f85ad674223 100644
--- a/src/hotspot/share/runtime/mutexLocker.hpp
+++ b/src/hotspot/share/runtime/mutexLocker.hpp
@@ -72,6 +72,7 @@ extern Monitor* VMOperationRequest_lock; // a lock on Threads waiting fo
extern Monitor* Threads_lock; // a lock on the Threads table of active Java threads
// (also used by Safepoints too to block threads creation/destruction)
extern Mutex* NonJavaThreadsList_lock; // a lock on the NonJavaThreads list
+extern Mutex* NonJavaThreadsListSync_lock; // a lock for NonJavaThreads list synchronization
extern Monitor* CGC_lock; // used for coordination between
// fore- & background GC threads.
extern Monitor* STS_lock; // used for joining/leaving SuspendibleThreadSet.
@@ -96,6 +97,7 @@ extern Mutex* CompileStatistics_lock; // a lock held when updating co
extern Mutex* DirectivesStack_lock; // a lock held when mutating the dirstack and ref counting directives
extern Mutex* MultiArray_lock; // a lock used to guard allocation of multi-dim arrays
extern Monitor* Terminator_lock; // a lock used to guard termination of the vm
+extern Monitor* InitCompleted_lock; // a lock used to signal threads waiting on init completed
extern Monitor* BeforeExit_lock; // a lock used to guard cleanups and shutdown hooks
extern Monitor* Notify_lock; // a lock used to synchronize the start-up of the vm
extern Mutex* ProfilePrint_lock; // a lock used to serialize the printing of profiles
diff --git a/src/hotspot/share/runtime/orderAccess.hpp b/src/hotspot/share/runtime/orderAccess.hpp
index bd0d3f294bb..442b9d67c94 100644
--- a/src/hotspot/share/runtime/orderAccess.hpp
+++ b/src/hotspot/share/runtime/orderAccess.hpp
@@ -266,6 +266,8 @@ class OrderAccess : private Atomic {
static void release();
static void fence();
+ static void cross_modify_fence();
+
template
static T load_acquire(const volatile T* p);
diff --git a/src/hotspot/share/runtime/os.cpp b/src/hotspot/share/runtime/os.cpp
index 31a557dcf15..8e2ddff79b0 100644
--- a/src/hotspot/share/runtime/os.cpp
+++ b/src/hotspot/share/runtime/os.cpp
@@ -704,12 +704,15 @@ void* os::malloc(size_t size, MEMFLAGS memflags, const NativeCallStack& stack) {
// Wrap memory with guard
GuardedMemory guarded(ptr, size + nmt_header_size);
ptr = guarded.get_user_ptr();
-#endif
+
if ((intptr_t)ptr == (intptr_t)MallocCatchPtr) {
log_warning(malloc, free)("os::malloc caught, " SIZE_FORMAT " bytes --> " PTR_FORMAT, size, p2i(ptr));
breakpoint();
}
- debug_only(if (paranoid) verify_memory(ptr));
+ if (paranoid) {
+ verify_memory(ptr);
+ }
+#endif
// we do not track guard memory
return MemTracker::record_malloc((address)ptr, size, memflags, stack, level);
@@ -760,10 +763,8 @@ void* os::realloc(void *memblock, size_t size, MEMFLAGS memflags, const NativeCa
// Guard's user data contains NMT header
size_t memblock_size = guarded.get_user_size() - MemTracker::malloc_header_size(memblock);
memcpy(ptr, memblock, MIN2(size, memblock_size));
- if (paranoid) verify_memory(MemTracker::malloc_base(ptr));
- if ((intptr_t)ptr == (intptr_t)MallocCatchPtr) {
- log_warning(malloc, free)("os::realloc caught, " SIZE_FORMAT " bytes --> " PTR_FORMAT, size, p2i(ptr));
- breakpoint();
+ if (paranoid) {
+ verify_memory(MemTracker::malloc_base(ptr));
}
os::free(memblock);
}
diff --git a/src/hotspot/share/runtime/safepoint.cpp b/src/hotspot/share/runtime/safepoint.cpp
index c838f0ec929..43e058628fb 100644
--- a/src/hotspot/share/runtime/safepoint.cpp
+++ b/src/hotspot/share/runtime/safepoint.cpp
@@ -477,7 +477,8 @@ void SafepointSynchronize::disarm_safepoint() {
assert(!cur_state->is_running(), "Thread not suspended at safepoint");
cur_state->restart(); // TSS _running
assert(cur_state->is_running(), "safepoint state has not been reset");
- SafepointMechanism::disarm_local_poll(current);
+
+ SafepointMechanism::disarm_if_needed(current, false /* NO release */);
}
} // ~JavaThreadIteratorWithHandle
@@ -716,8 +717,6 @@ static bool safepoint_safe_with(JavaThread *thread, JavaThreadState state) {
}
bool SafepointSynchronize::handshake_safe(JavaThread *thread) {
- // The polls must be armed otherwise the safe state can change to unsafe at any time.
- assert(SafepointMechanism::should_block(thread), "Must be armed");
// This function must be called with the Threads_lock held so an externally
// suspended thread cannot be resumed thus it is safe.
assert(Threads_lock->owned_by_self() && Thread::current()->is_VM_thread(),
@@ -851,6 +850,9 @@ void SafepointSynchronize::block(JavaThread *thread) {
thread->handle_special_runtime_exit_condition(
!thread->is_at_poll_safepoint() && (state != _thread_in_native_trans));
}
+
+ // cross_modify_fence is done by SafepointMechanism::block_if_requested_slow
+ // which is the only caller here.
}
// ------------------------------------------------------------------------------------------------------
diff --git a/src/hotspot/share/runtime/safepointMechanism.cpp b/src/hotspot/share/runtime/safepointMechanism.cpp
index 4cf957e3717..ec2f71dcbe9 100644
--- a/src/hotspot/share/runtime/safepointMechanism.cpp
+++ b/src/hotspot/share/runtime/safepointMechanism.cpp
@@ -83,8 +83,7 @@ void SafepointMechanism::default_initialize() {
}
}
-void SafepointMechanism::block_if_requested_slow(JavaThread *thread) {
- // local poll already checked, if used.
+void SafepointMechanism::block_or_handshake(JavaThread *thread) {
if (global_poll()) {
// Any load in ::block must not pass the global poll load.
// Otherwise we might load an old safepoint counter (for example).
@@ -92,10 +91,31 @@ void SafepointMechanism::block_if_requested_slow(JavaThread *thread) {
SafepointSynchronize::block(thread);
}
if (uses_thread_local_poll() && thread->has_handshake()) {
- thread->handshake_process_by_self();
+ thread->handshake_process_by_self();
}
}
+void SafepointMechanism::block_if_requested_slow(JavaThread *thread) {
+ // Read global poll and has_handshake after local poll
+ OrderAccess::loadload();
+
+ // local poll already checked, if used.
+ block_or_handshake(thread);
+
+ OrderAccess::loadload();
+
+ if (uses_thread_local_poll() && local_poll_armed(thread)) {
+ disarm_local_poll_release(thread);
+ // We might have disarmed next safepoint/handshake
+ OrderAccess::storeload();
+ if (global_poll() || thread->has_handshake()) {
+ arm_local_poll(thread);
+ }
+ }
+
+ OrderAccess::cross_modify_fence();
+}
+
void SafepointMechanism::initialize_header(JavaThread* thread) {
disarm_local_poll(thread);
}
diff --git a/src/hotspot/share/runtime/safepointMechanism.hpp b/src/hotspot/share/runtime/safepointMechanism.hpp
index 6f15b9ab196..b54e85588d8 100644
--- a/src/hotspot/share/runtime/safepointMechanism.hpp
+++ b/src/hotspot/share/runtime/safepointMechanism.hpp
@@ -46,9 +46,13 @@ class SafepointMechanism : public AllStatic {
static inline bool local_poll_armed(JavaThread* thread);
+ static inline void disarm_local_poll(JavaThread* thread);
+ static inline void disarm_local_poll_release(JavaThread* thread);
+
static inline bool local_poll(Thread* thread);
static inline bool global_poll();
+ static void block_or_handshake(JavaThread *thread);
static void block_if_requested_slow(JavaThread *thread);
static void default_initialize();
@@ -80,10 +84,10 @@ public:
// Caller is responsible for using a memory barrier if needed.
static inline void arm_local_poll(JavaThread* thread);
- static inline void disarm_local_poll(JavaThread* thread);
-
+ // Release semantics
static inline void arm_local_poll_release(JavaThread* thread);
- static inline void disarm_local_poll_release(JavaThread* thread);
+ // Optional release
+ static inline void disarm_if_needed(JavaThread* thread, bool memory_order_release);
// Setup the selected safepoint mechanism
static void initialize();
diff --git a/src/hotspot/share/runtime/safepointMechanism.inline.hpp b/src/hotspot/share/runtime/safepointMechanism.inline.hpp
index f44fdf8ca49..46c3685dc97 100644
--- a/src/hotspot/share/runtime/safepointMechanism.inline.hpp
+++ b/src/hotspot/share/runtime/safepointMechanism.inline.hpp
@@ -56,7 +56,7 @@ bool SafepointMechanism::should_block(Thread* thread) {
}
void SafepointMechanism::block_if_requested(JavaThread *thread) {
- if (uses_thread_local_poll() && !SafepointMechanism::local_poll_armed(thread)) {
+ if (uses_thread_local_poll() && !local_poll_armed(thread)) {
return;
}
block_if_requested_slow(thread);
@@ -70,6 +70,19 @@ void SafepointMechanism::disarm_local_poll(JavaThread* thread) {
thread->set_polling_page(poll_disarmed_value());
}
+void SafepointMechanism::disarm_if_needed(JavaThread* thread, bool memory_order_release) {
+ JavaThreadState jts = thread->thread_state();
+ if (jts == _thread_in_native || jts == _thread_in_native_trans) {
+ // JavaThread will disarm itself and execute cross_modify_fence() before continuing
+ return;
+ }
+ if (memory_order_release) {
+ thread->set_polling_page_release(poll_disarmed_value());
+ } else {
+ thread->set_polling_page(poll_disarmed_value());
+ }
+}
+
void SafepointMechanism::arm_local_poll_release(JavaThread* thread) {
thread->set_polling_page_release(poll_armed_value());
}
diff --git a/src/hotspot/share/runtime/synchronizer.cpp b/src/hotspot/share/runtime/synchronizer.cpp
index ecd4b648c79..9ec3f4963b3 100644
--- a/src/hotspot/share/runtime/synchronizer.cpp
+++ b/src/hotspot/share/runtime/synchronizer.cpp
@@ -1270,6 +1270,21 @@ void ObjectSynchronizer::omFlush(Thread * Self) {
}
Thread::muxRelease(&gListLock);
+
+ LogStreamHandle(Debug, monitorinflation) lsh_debug;
+ LogStreamHandle(Info, monitorinflation) lsh_info;
+ LogStream * ls = NULL;
+ if (log_is_enabled(Debug, monitorinflation)) {
+ ls = &lsh_debug;
+ } else if ((tally != 0 || inUseTally != 0) &&
+ log_is_enabled(Info, monitorinflation)) {
+ ls = &lsh_info;
+ }
+ if (ls != NULL) {
+ ls->print_cr("omFlush: jt=" INTPTR_FORMAT ", free_monitor_tally=%d"
+ ", in_use_monitor_tally=%d" ", omFreeProvision=%d",
+ p2i(Self), tally, inUseTally, Self->omFreeProvision);
+ }
}
static void post_monitor_inflate_event(EventJavaMonitorInflate* event,
@@ -1665,24 +1680,18 @@ void ObjectSynchronizer::finish_deflate_idle_monitors(DeflateMonitorCounters* co
// than a beginning to end measurement of the phase.
log_info(safepoint, cleanup)("deflating per-thread idle monitors, %3.7f secs, monitors=%d", counters->perThreadTimes, counters->perThreadScavenged);
- LogStreamHandle(Debug, monitorinflation) lsh_debug;
- LogStreamHandle(Info, monitorinflation) lsh_info;
- LogStream * ls = NULL;
- if (log_is_enabled(Debug, monitorinflation)) {
- ls = &lsh_debug;
- } else if (counters->perThreadScavenged != 0 && log_is_enabled(Info, monitorinflation)) {
- ls = &lsh_info;
- }
- if (ls != NULL) {
- ls->print_cr("deflating per-thread idle monitors, %3.7f secs, %d monitors", counters->perThreadTimes, counters->perThreadScavenged);
- }
-
gMonitorFreeCount += counters->nScavenged;
if (log_is_enabled(Debug, monitorinflation)) {
// exit_globals()'s call to audit_and_print_stats() is done
// at the Info level.
ObjectSynchronizer::audit_and_print_stats(false /* on_exit */);
+ } else if (log_is_enabled(Info, monitorinflation)) {
+ Thread::muxAcquire(&gListLock, "finish_deflate_idle_monitors");
+ log_info(monitorinflation)("gMonitorPopulation=%d, gOmInUseCount=%d, "
+ "gMonitorFreeCount=%d", gMonitorPopulation,
+ gOmInUseCount, gMonitorFreeCount);
+ Thread::muxRelease(&gListLock);
}
ForceMonitorScavenge = 0; // Reset
@@ -1708,8 +1717,6 @@ void ObjectSynchronizer::deflate_thread_local_monitors(Thread* thread, DeflateMo
int deflated_count = deflate_monitor_list(thread->omInUseList_addr(), &freeHeadp, &freeTailp);
- timer.stop();
-
Thread::muxAcquire(&gListLock, "deflate_thread_local_monitors");
// Adjust counters
@@ -1718,8 +1725,6 @@ void ObjectSynchronizer::deflate_thread_local_monitors(Thread* thread, DeflateMo
counters->nScavenged += deflated_count;
counters->nInuse += thread->omInUseCount;
counters->perThreadScavenged += deflated_count;
- // For now, we only care about cumulative per-thread deflation time.
- counters->perThreadTimes += timer.seconds();
// Move the scavenged monitors back to the global free list.
if (freeHeadp != NULL) {
@@ -1730,7 +1735,26 @@ void ObjectSynchronizer::deflate_thread_local_monitors(Thread* thread, DeflateMo
freeTailp->FreeNext = gFreeList;
gFreeList = freeHeadp;
}
+
+ timer.stop();
+ // Safepoint logging cares about cumulative perThreadTimes and
+ // we'll capture most of the cost, but not the muxRelease() which
+ // should be cheap.
+ counters->perThreadTimes += timer.seconds();
+
Thread::muxRelease(&gListLock);
+
+ LogStreamHandle(Debug, monitorinflation) lsh_debug;
+ LogStreamHandle(Info, monitorinflation) lsh_info;
+ LogStream * ls = NULL;
+ if (log_is_enabled(Debug, monitorinflation)) {
+ ls = &lsh_debug;
+ } else if (deflated_count != 0 && log_is_enabled(Info, monitorinflation)) {
+ ls = &lsh_info;
+ }
+ if (ls != NULL) {
+ ls->print_cr("jt=" INTPTR_FORMAT ": deflating per-thread idle monitors, %3.7f secs, %d monitors", p2i(thread), timer.seconds(), deflated_count);
+ }
}
// Monitor cleanup on JavaThread::exit
@@ -1839,13 +1863,13 @@ void ObjectSynchronizer::audit_and_print_stats(bool on_exit) {
// Check gMonitorPopulation:
if (gMonitorPopulation == chkMonitorPopulation) {
- ls->print_cr("gMonitorPopulation=%d equals chkMonitorPopulation=%d",
- gMonitorPopulation, chkMonitorPopulation);
+ ls->print_cr("gMonitorPopulation=%d equals chkMonitorPopulation=%d",
+ gMonitorPopulation, chkMonitorPopulation);
} else {
- ls->print_cr("ERROR: gMonitorPopulation=%d is not equal to "
- "chkMonitorPopulation=%d", gMonitorPopulation,
- chkMonitorPopulation);
- error_cnt++;
+ ls->print_cr("ERROR: gMonitorPopulation=%d is not equal to "
+ "chkMonitorPopulation=%d", gMonitorPopulation,
+ chkMonitorPopulation);
+ error_cnt++;
}
// Check gOmInUseList and gOmInUseCount:
diff --git a/src/hotspot/share/runtime/synchronizer.hpp b/src/hotspot/share/runtime/synchronizer.hpp
index 387447325f0..09e8de90d57 100644
--- a/src/hotspot/share/runtime/synchronizer.hpp
+++ b/src/hotspot/share/runtime/synchronizer.hpp
@@ -199,11 +199,11 @@ class ObjectSynchronizer : AllStatic {
static u_char* get_gvars_stwRandom_addr();
};
-// ObjectLocker enforced balanced locking and can never thrown an
+// ObjectLocker enforces balanced locking and can never throw an
// IllegalMonitorStateException. However, a pending exception may
// have to pass through, and we must also be able to deal with
// asynchronous exceptions. The caller is responsible for checking
-// the threads pending exception if needed.
+// the thread's pending exception if needed.
class ObjectLocker : public StackObj {
private:
Thread* _thread;
diff --git a/src/hotspot/share/runtime/thread.cpp b/src/hotspot/share/runtime/thread.cpp
index 07baa46cc20..847688ea136 100644
--- a/src/hotspot/share/runtime/thread.cpp
+++ b/src/hotspot/share/runtime/thread.cpp
@@ -1291,29 +1291,35 @@ NonJavaThread::NonJavaThread() : Thread(), _next(NULL) {
NonJavaThread::~NonJavaThread() { }
void NonJavaThread::add_to_the_list() {
- MutexLockerEx lock(NonJavaThreadsList_lock, Mutex::_no_safepoint_check_flag);
- _next = _the_list._head;
+ MutexLockerEx ml(NonJavaThreadsList_lock, Mutex::_no_safepoint_check_flag);
+ // Initialize BarrierSet-related data before adding to list.
+ BarrierSet::barrier_set()->on_thread_attach(this);
+ OrderAccess::release_store(&_next, _the_list._head);
OrderAccess::release_store(&_the_list._head, this);
}
void NonJavaThread::remove_from_the_list() {
- MutexLockerEx lock(NonJavaThreadsList_lock, Mutex::_no_safepoint_check_flag);
- NonJavaThread* volatile* p = &_the_list._head;
- for (NonJavaThread* t = *p; t != NULL; p = &t->_next, t = *p) {
- if (t == this) {
- *p = this->_next;
- // Wait for any in-progress iterators. Concurrent synchronize is
- // not allowed, so do it while holding the list lock.
- _the_list._protect.synchronize();
- break;
+ {
+ MutexLockerEx ml(NonJavaThreadsList_lock, Mutex::_no_safepoint_check_flag);
+ // Cleanup BarrierSet-related data before removing from list.
+ BarrierSet::barrier_set()->on_thread_detach(this);
+ NonJavaThread* volatile* p = &_the_list._head;
+ for (NonJavaThread* t = *p; t != NULL; p = &t->_next, t = *p) {
+ if (t == this) {
+ *p = _next;
+ break;
+ }
}
}
+ // Wait for any in-progress iterators. Concurrent synchronize is not
+ // allowed, so do it while holding a dedicated lock. Outside and distinct
+ // from NJTList_lock in case an iteration attempts to lock it.
+ MutexLockerEx ml(NonJavaThreadsListSync_lock, Mutex::_no_safepoint_check_flag);
+ _the_list._protect.synchronize();
+ _next = NULL; // Safe to drop the link now.
}
void NonJavaThread::pre_run() {
- // Initialize BarrierSet-related data before adding to list.
- assert(BarrierSet::barrier_set() != NULL, "invariant");
- BarrierSet::barrier_set()->on_thread_attach(this);
add_to_the_list();
// This is slightly odd in that NamedThread is a subclass, but
@@ -1324,8 +1330,6 @@ void NonJavaThread::pre_run() {
void NonJavaThread::post_run() {
JFR_ONLY(Jfr::on_thread_exit(this);)
- // Clean up BarrierSet data before removing from list.
- BarrierSet::barrier_set()->on_thread_detach(this);
remove_from_the_list();
// Ensure thread-local-storage is cleared before termination.
Thread::clear_thread_current();
@@ -1506,7 +1510,7 @@ void WatcherThread::run() {
{
MutexLockerEx mu(Terminator_lock, Mutex::_no_safepoint_check_flag);
_watcher_thread = NULL;
- Terminator_lock->notify();
+ Terminator_lock->notify_all();
}
}
@@ -1836,6 +1840,10 @@ void JavaThread::run() {
// Thread is now sufficiently initialized to be handled by the safepoint code as being
// in the VM. Change thread state from _thread_new to _thread_in_vm
ThreadStateTransition::transition_and_fence(this, _thread_new, _thread_in_vm);
+ // Before a thread is on the threads list it is always safe, so after leaving the
+ // _thread_new we should emit a instruction barrier. The distance to modified code
+ // from here is probably far enough, but this is consistent and safe.
+ OrderAccess::cross_modify_fence();
assert(JavaThread::current() == this, "sanity check");
assert(!Thread::current()->owns_locks(), "sanity check");
@@ -2264,48 +2272,19 @@ void JavaThread::check_and_handle_async_exceptions(bool check_unsafe_error) {
void JavaThread::handle_special_runtime_exit_condition(bool check_asyncs) {
//
- // Check for pending external suspend. Internal suspend requests do
- // not use handle_special_runtime_exit_condition().
+ // Check for pending external suspend.
// If JNIEnv proxies are allowed, don't self-suspend if the target
// thread is not the current thread. In older versions of jdbx, jdbx
// threads could call into the VM with another thread's JNIEnv so we
// can be here operating on behalf of a suspended thread (4432884).
bool do_self_suspend = is_external_suspend_with_lock();
if (do_self_suspend && (!AllowJNIEnvProxy || this == JavaThread::current())) {
- //
- // Because thread is external suspended the safepoint code will count
- // thread as at a safepoint. This can be odd because we can be here
- // as _thread_in_Java which would normally transition to _thread_blocked
- // at a safepoint. We would like to mark the thread as _thread_blocked
- // before calling java_suspend_self like all other callers of it but
- // we must then observe proper safepoint protocol. (We can't leave
- // _thread_blocked with a safepoint in progress). However we can be
- // here as _thread_in_native_trans so we can't use a normal transition
- // constructor/destructor pair because they assert on that type of
- // transition. We could do something like:
- //
- // JavaThreadState state = thread_state();
- // set_thread_state(_thread_in_vm);
- // {
- // ThreadBlockInVM tbivm(this);
- // java_suspend_self()
- // }
- // set_thread_state(_thread_in_vm_trans);
- // if (safepoint) block;
- // set_thread_state(state);
- //
- // but that is pretty messy. Instead we just go with the way the
- // code has worked before and note that this is the only path to
- // java_suspend_self that doesn't put the thread in _thread_blocked
- // mode.
-
frame_anchor()->make_walkable(this);
- java_suspend_self();
-
- // We might be here for reasons in addition to the self-suspend request
- // so check for other async requests.
+ java_suspend_self_with_safepoint_check();
}
+ // We might be here for reasons in addition to the self-suspend request
+ // so check for other async requests.
if (check_asyncs) {
check_and_handle_async_exceptions();
}
@@ -2424,6 +2403,7 @@ void JavaThread::java_suspend() {
// to complete an external suspend request.
//
int JavaThread::java_suspend_self() {
+ assert(thread_state() == _thread_blocked, "wrong state for java_suspend_self()");
int ret = 0;
// we are in the process of exiting so don't suspend
@@ -2467,10 +2447,42 @@ int JavaThread::java_suspend_self() {
this->SR_lock()->wait(Mutex::_no_safepoint_check_flag);
}
}
-
return ret;
}
+// Helper routine to set up the correct thread state before calling java_suspend_self.
+// This is called when regular thread-state transition helpers can't be used because
+// we can be in various states, in particular _thread_in_native_trans.
+// Because this thread is external suspended the safepoint code will count it as at
+// a safepoint, regardless of what its actual current thread-state is. But
+// is_ext_suspend_completed() may be waiting to see a thread transition from
+// _thread_in_native_trans to _thread_blocked. So we set the thread state directly
+// to _thread_blocked. The problem with setting thread state directly is that a
+// safepoint could happen just after java_suspend_self() returns after being resumed,
+// and the VM thread will see the _thread_blocked state. So we must check for a safepoint
+// after restoring the state to make sure we won't leave while a safepoint is in progress.
+// However, not all initial-states are allowed when performing a safepoint check, as we
+// should never be blocking at a safepoint whilst in those states. Of these 'bad' states
+// only _thread_in_native is possible when executing this code (based on our two callers).
+// A thread that is _thread_in_native is already safepoint-safe and so it doesn't matter
+// whether the VMThread sees the _thread_blocked state, or the _thread_in_native state,
+// and so we don't need the explicit safepoint check.
+
+void JavaThread::java_suspend_self_with_safepoint_check() {
+ assert(this == Thread::current(), "invariant");
+ JavaThreadState state = thread_state();
+ set_thread_state(_thread_blocked);
+ java_suspend_self();
+ set_thread_state(state);
+ // Since we are not using a regular thread-state transition helper here,
+ // we must manually emit the instruction barrier after leaving a safe state.
+ OrderAccess::cross_modify_fence();
+ InterfaceSupport::serialize_thread_state_with_handler(this);
+ if (state != _thread_in_native) {
+ SafepointMechanism::block_if_requested(this);
+ }
+}
+
#ifdef ASSERT
// Verify the JavaThread has not yet been published in the Threads::list, and
// hence doesn't need protection from concurrent access at this stage.
@@ -2502,33 +2514,11 @@ void JavaThread::check_safepoint_and_suspend_for_native_trans(JavaThread *thread
// threads could call into the VM with another thread's JNIEnv so we
// can be here operating on behalf of a suspended thread (4432884).
if (do_self_suspend && (!AllowJNIEnvProxy || curJT == thread)) {
- JavaThreadState state = thread->thread_state();
-
- // We mark this thread_blocked state as a suspend-equivalent so
- // that a caller to is_ext_suspend_completed() won't be confused.
- // The suspend-equivalent state is cleared by java_suspend_self().
- thread->set_suspend_equivalent();
-
- // If the safepoint code sees the _thread_in_native_trans state, it will
- // wait until the thread changes to other thread state. There is no
- // guarantee on how soon we can obtain the SR_lock and complete the
- // self-suspend request. It would be a bad idea to let safepoint wait for
- // too long. Temporarily change the state to _thread_blocked to
- // let the VM thread know that this thread is ready for GC. The problem
- // of changing thread state is that safepoint could happen just after
- // java_suspend_self() returns after being resumed, and VM thread will
- // see the _thread_blocked state. We must check for safepoint
- // after restoring the state and make sure we won't leave while a safepoint
- // is in progress.
- thread->set_thread_state(_thread_blocked);
- thread->java_suspend_self();
- thread->set_thread_state(state);
-
- InterfaceSupport::serialize_thread_state_with_handler(thread);
+ thread->java_suspend_self_with_safepoint_check();
+ } else {
+ SafepointMechanism::block_if_requested(curJT);
}
- SafepointMechanism::block_if_requested(curJT);
-
if (thread->is_deopt_suspend()) {
thread->clear_deopt_suspend();
RegisterMap map(thread, false);
@@ -2948,9 +2938,21 @@ void JavaThread::oops_do(OopClosure* f, CodeBlobClosure* cf) {
}
}
+#ifdef ASSERT
+void JavaThread::verify_states_for_handshake() {
+ // This checks that the thread has a correct frame state during a handshake.
+ assert((!has_last_Java_frame() && java_call_counter() == 0) ||
+ (has_last_Java_frame() && java_call_counter() > 0),
+ "unexpected frame info: has_last_frame=%d, java_call_counter=%d",
+ has_last_Java_frame(), java_call_counter());
+}
+#endif
+
void JavaThread::nmethods_do(CodeBlobClosure* cf) {
assert((!has_last_Java_frame() && java_call_counter() == 0) ||
- (has_last_Java_frame() && java_call_counter() > 0), "wrong java_sp info!");
+ (has_last_Java_frame() && java_call_counter() > 0),
+ "unexpected frame info: has_last_frame=%d, java_call_counter=%d",
+ has_last_Java_frame(), java_call_counter());
if (has_last_Java_frame()) {
// Traverse the execution stack
@@ -4457,7 +4459,7 @@ void Threads::add(JavaThread* p, bool force_daemon) {
void Threads::remove(JavaThread* p) {
- // Reclaim the objectmonitors from the omInUseList and omFreeList of the moribund thread.
+ // Reclaim the ObjectMonitors from the omInUseList and omFreeList of the moribund thread.
ObjectSynchronizer::omFlush(p);
// Extra scope needed for Thread_lock, so we can check
diff --git a/src/hotspot/share/runtime/thread.hpp b/src/hotspot/share/runtime/thread.hpp
index 4db0d7e4324..b71b28d21e4 100644
--- a/src/hotspot/share/runtime/thread.hpp
+++ b/src/hotspot/share/runtime/thread.hpp
@@ -1348,10 +1348,16 @@ class JavaThread: public Thread {
inline void clear_ext_suspended();
public:
- void java_suspend();
- void java_resume();
- int java_suspend_self();
+ void java_suspend(); // higher-level suspension logic called by the public APIs
+ void java_resume(); // higher-level resume logic called by the public APIs
+ int java_suspend_self(); // low-level self-suspension mechanics
+ private:
+ // mid-level wrapper around java_suspend_self to set up correct state and
+ // check for a pending safepoint at the end
+ void java_suspend_self_with_safepoint_check();
+
+ public:
void check_and_wait_while_suspended() {
assert(JavaThread::current() == this, "sanity check");
@@ -1868,6 +1874,9 @@ class JavaThread: public Thread {
// RedefineClasses Support
void metadata_do(MetadataClosure* f);
+ // Debug method asserting thread states are correct during a handshake operation.
+ DEBUG_ONLY(void verify_states_for_handshake();)
+
// Misc. operations
char* name() const { return (char*)get_thread_name(); }
void print_on(outputStream* st, bool print_extended_info) const;
diff --git a/src/hotspot/share/runtime/vmThread.cpp b/src/hotspot/share/runtime/vmThread.cpp
index d5d5b523470..036ca703684 100644
--- a/src/hotspot/share/runtime/vmThread.cpp
+++ b/src/hotspot/share/runtime/vmThread.cpp
@@ -434,22 +434,35 @@ void VMThread::evaluate_operation(VM_Operation* op) {
static VM_None safepointALot_op("SafepointALot");
static VM_Cleanup cleanup_op;
-VM_Operation* VMThread::no_op_safepoint(bool check_time) {
+class HandshakeALotTC : public ThreadClosure {
+ public:
+ virtual void do_thread(Thread* thread) {
+#ifdef ASSERT
+ assert(thread->is_Java_thread(), "must be");
+ JavaThread* jt = (JavaThread*)thread;
+ jt->verify_states_for_handshake();
+#endif
+ }
+};
+
+VM_Operation* VMThread::no_op_safepoint() {
+ // Check for handshakes first since we may need to return a VMop.
+ if (HandshakeALot) {
+ HandshakeALotTC haltc;
+ Handshake::execute(&haltc);
+ }
+ // Check for a cleanup before SafepointALot to keep stats correct.
+ long interval_ms = SafepointTracing::time_since_last_safepoint_ms();
+ bool max_time_exceeded = GuaranteedSafepointInterval != 0 &&
+ (interval_ms >= GuaranteedSafepointInterval);
+ if (max_time_exceeded && SafepointSynchronize::is_cleanup_needed()) {
+ return &cleanup_op;
+ }
if (SafepointALot) {
return &safepointALot_op;
}
- if (!SafepointSynchronize::is_cleanup_needed()) {
- return NULL;
- }
- if (check_time) {
- long interval_ms = SafepointTracing::time_since_last_safepoint_ms();
- bool max_time_exceeded = GuaranteedSafepointInterval != 0 &&
- (interval_ms > GuaranteedSafepointInterval);
- if (!max_time_exceeded) {
- return NULL;
- }
- }
- return &cleanup_op;
+ // Nothing to be done.
+ return NULL;
}
void VMThread::loop() {
@@ -491,19 +504,22 @@ void VMThread::loop() {
exit(-1);
}
- if (timedout && (_cur_vm_operation = VMThread::no_op_safepoint(false)) != NULL) {
- MutexUnlockerEx mul(VMOperationQueue_lock,
- Mutex::_no_safepoint_check_flag);
- // Force a safepoint since we have not had one for at least
- // 'GuaranteedSafepointInterval' milliseconds. This will run all
- // the clean-up processing that needs to be done regularly at a
- // safepoint
- SafepointSynchronize::begin();
- #ifdef ASSERT
+ if (timedout) {
+ // Have to unlock VMOperationQueue_lock just in case no_op_safepoint()
+ // has to do a handshake.
+ MutexUnlockerEx mul(VMOperationQueue_lock, Mutex::_no_safepoint_check_flag);
+ if ((_cur_vm_operation = VMThread::no_op_safepoint()) != NULL) {
+ // Force a safepoint since we have not had one for at least
+ // 'GuaranteedSafepointInterval' milliseconds and we need to clean
+ // something. This will run all the clean-up processing that needs
+ // to be done at a safepoint.
+ SafepointSynchronize::begin();
+ #ifdef ASSERT
if (GCALotAtAllSafepoints) InterfaceSupport::check_gc_alot();
- #endif
- SafepointSynchronize::end();
- _cur_vm_operation = NULL;
+ #endif
+ SafepointSynchronize::end();
+ _cur_vm_operation = NULL;
+ }
}
_cur_vm_operation = _vm_queue->remove_next();
@@ -615,10 +631,9 @@ void VMThread::loop() {
VMOperationRequest_lock->notify_all();
}
- //
- // We want to make sure that we get to a safepoint regularly.
- //
- if ((_cur_vm_operation = VMThread::no_op_safepoint(false)) != NULL) {
+ // We want to make sure that we get to a safepoint regularly
+ // even when executing VMops that don't require safepoints.
+ if ((_cur_vm_operation = VMThread::no_op_safepoint()) != NULL) {
HandleMark hm(VMThread::vm_thread());
SafepointSynchronize::begin();
SafepointSynchronize::end();
diff --git a/src/hotspot/share/runtime/vmThread.hpp b/src/hotspot/share/runtime/vmThread.hpp
index 36648e714da..b7de162927a 100644
--- a/src/hotspot/share/runtime/vmThread.hpp
+++ b/src/hotspot/share/runtime/vmThread.hpp
@@ -123,7 +123,7 @@ class VMThread: public NamedThread {
static VMOperationTimeoutTask* _timeout_task;
- static VM_Operation* no_op_safepoint(bool check_time);
+ static VM_Operation* no_op_safepoint();
void evaluate_operation(VM_Operation* op);
diff --git a/src/hotspot/share/services/heapDumper.cpp b/src/hotspot/share/services/heapDumper.cpp
index 4f2ff5898e5..9b9868c2f42 100644
--- a/src/hotspot/share/services/heapDumper.cpp
+++ b/src/hotspot/share/services/heapDumper.cpp
@@ -958,6 +958,11 @@ void DumperSupport::dump_instance_field_descriptors(DumpWriter* writer, Klass* k
// creates HPROF_GC_INSTANCE_DUMP record for the given object
void DumperSupport::dump_instance(DumpWriter* writer, oop o) {
Klass* k = o->klass();
+ if (k->java_mirror() == NULL) {
+ // Ignoring this object since the corresponding java mirror is not loaded.
+ // Might be a dormant archive object.
+ return;
+ }
writer->write_u1(HPROF_GC_INSTANCE_DUMP);
writer->write_objectID(o);
diff --git a/src/hotspot/share/services/management.cpp b/src/hotspot/share/services/management.cpp
index 5c0f8187b45..bf36fd40af9 100644
--- a/src/hotspot/share/services/management.cpp
+++ b/src/hotspot/share/services/management.cpp
@@ -24,6 +24,7 @@
#include "precompiled.hpp"
#include "jmm.h"
+#include "classfile/classLoader.hpp"
#include "classfile/systemDictionary.hpp"
#include "compiler/compileBroker.hpp"
#include "memory/allocation.inline.hpp"
diff --git a/src/hotspot/share/services/memBaseline.cpp b/src/hotspot/share/services/memBaseline.cpp
index b0a8b20ea0b..8fc191822d2 100644
--- a/src/hotspot/share/services/memBaseline.cpp
+++ b/src/hotspot/share/services/memBaseline.cpp
@@ -156,6 +156,11 @@ bool MemBaseline::baseline_allocation_sites() {
return false;
}
+ // Walk simple thread stacks
+ if (!ThreadStackTracker::walk_simple_thread_stack_site(&malloc_walker)) {
+ return false;
+ }
+
_malloc_sites.move(malloc_walker.malloc_sites());
// The malloc sites are collected in size order
_malloc_sites_order = by_size;
diff --git a/src/hotspot/share/services/memReporter.cpp b/src/hotspot/share/services/memReporter.cpp
index a6e815d4f86..5bd5f7b0117 100644
--- a/src/hotspot/share/services/memReporter.cpp
+++ b/src/hotspot/share/services/memReporter.cpp
@@ -26,6 +26,7 @@
#include "memory/allocation.hpp"
#include "services/mallocTracker.hpp"
#include "services/memReporter.hpp"
+#include "services/threadStackTracker.hpp"
#include "services/virtualMemoryTracker.hpp"
#include "utilities/globalDefinitions.hpp"
@@ -46,11 +47,13 @@ void MemReporterBase::print_total(size_t reserved, size_t committed) const {
void MemReporterBase::print_malloc(size_t amount, size_t count, MEMFLAGS flag) const {
const char* scale = current_scale();
outputStream* out = output();
+ const char* alloc_type = (flag == mtThreadStack) ? "" : "malloc=";
+
if (flag != mtNone) {
- out->print("(malloc=" SIZE_FORMAT "%s type=%s",
+ out->print("(%s" SIZE_FORMAT "%s type=%s", alloc_type,
amount_in_current_scale(amount), scale, NMTUtil::flag_to_name(flag));
} else {
- out->print("(malloc=" SIZE_FORMAT "%s",
+ out->print("(%s" SIZE_FORMAT "%s", alloc_type,
amount_in_current_scale(amount), scale);
}
@@ -126,10 +129,17 @@ void MemSummaryReporter::report_summary_of_type(MEMFLAGS flag,
// Count thread's native stack in "Thread" category
if (flag == mtThread) {
- const VirtualMemory* thread_stack_usage =
- (const VirtualMemory*)_vm_snapshot->by_type(mtThreadStack);
- reserved_amount += thread_stack_usage->reserved();
- committed_amount += thread_stack_usage->committed();
+ if (ThreadStackTracker::track_as_vm()) {
+ const VirtualMemory* thread_stack_usage =
+ (const VirtualMemory*)_vm_snapshot->by_type(mtThreadStack);
+ reserved_amount += thread_stack_usage->reserved();
+ committed_amount += thread_stack_usage->committed();
+ } else {
+ const MallocMemory* thread_stack_usage =
+ (const MallocMemory*)_malloc_snapshot->by_type(mtThreadStack);
+ reserved_amount += thread_stack_usage->malloc_size();
+ committed_amount += thread_stack_usage->malloc_size();
+ }
} else if (flag == mtNMT) {
// Count malloc headers in "NMT" category
reserved_amount += _malloc_snapshot->malloc_overhead()->size();
@@ -150,12 +160,22 @@ void MemSummaryReporter::report_summary_of_type(MEMFLAGS flag,
out->print_cr("%27s ( instance classes #" SIZE_FORMAT ", array classes #" SIZE_FORMAT ")",
" ", _instance_class_count, _array_class_count);
} else if (flag == mtThread) {
- // report thread count
- out->print_cr("%27s (thread #" SIZE_FORMAT ")", " ", _malloc_snapshot->thread_count());
- const VirtualMemory* thread_stack_usage =
- _vm_snapshot->by_type(mtThreadStack);
- out->print("%27s (stack: ", " ");
- print_total(thread_stack_usage->reserved(), thread_stack_usage->committed());
+ if (ThreadStackTracker::track_as_vm()) {
+ const VirtualMemory* thread_stack_usage =
+ _vm_snapshot->by_type(mtThreadStack);
+ // report thread count
+ out->print_cr("%27s (thread #" SIZE_FORMAT ")", " ", ThreadStackTracker::thread_count());
+ out->print("%27s (stack: ", " ");
+ print_total(thread_stack_usage->reserved(), thread_stack_usage->committed());
+ } else {
+ MallocMemory* thread_stack_memory = _malloc_snapshot->by_type(mtThreadStack);
+ const char* scale = current_scale();
+ // report thread count
+ assert(ThreadStackTracker::thread_count() == 0, "Not used");
+ out->print_cr("%27s (thread #" SIZE_FORMAT ")", " ", thread_stack_memory->malloc_count());
+ out->print("%27s (Stack: " SIZE_FORMAT "%s", " ",
+ amount_in_current_scale(thread_stack_memory->malloc_size()), scale);
+ }
out->print_cr(")");
}
@@ -368,10 +388,11 @@ void MemSummaryDiffReporter::print_malloc_diff(size_t current_amount, size_t cur
size_t early_amount, size_t early_count, MEMFLAGS flags) const {
const char* scale = current_scale();
outputStream* out = output();
+ const char* alloc_type = (flags == mtThread) ? "" : "malloc=";
- out->print("malloc=" SIZE_FORMAT "%s", amount_in_current_scale(current_amount), scale);
- // Report type only if it is valid
- if (flags != mtNone) {
+ out->print("%s" SIZE_FORMAT "%s", alloc_type, amount_in_current_scale(current_amount), scale);
+ // Report type only if it is valid and not under "thread" category
+ if (flags != mtNone && flags != mtThread) {
out->print(" type=%s", NMTUtil::flag_to_name(flags));
}
@@ -497,15 +518,25 @@ void MemSummaryDiffReporter::diff_summary_of_type(MEMFLAGS flag,
}
out->print_cr(")");
- // report thread stack
- const VirtualMemory* current_thread_stack =
- _current_baseline.virtual_memory(mtThreadStack);
- const VirtualMemory* early_thread_stack =
- _early_baseline.virtual_memory(mtThreadStack);
-
out->print("%27s (stack: ", " ");
- print_virtual_memory_diff(current_thread_stack->reserved(), current_thread_stack->committed(),
- early_thread_stack->reserved(), early_thread_stack->committed());
+ if (ThreadStackTracker::track_as_vm()) {
+ // report thread stack
+ const VirtualMemory* current_thread_stack =
+ _current_baseline.virtual_memory(mtThreadStack);
+ const VirtualMemory* early_thread_stack =
+ _early_baseline.virtual_memory(mtThreadStack);
+
+ print_virtual_memory_diff(current_thread_stack->reserved(), current_thread_stack->committed(),
+ early_thread_stack->reserved(), early_thread_stack->committed());
+ } else {
+ const MallocMemory* current_thread_stack =
+ _current_baseline.malloc_memory(mtThreadStack);
+ const MallocMemory* early_thread_stack =
+ _early_baseline.malloc_memory(mtThreadStack);
+
+ print_malloc_diff(current_thread_stack->malloc_size(), current_thread_stack->malloc_count(),
+ early_thread_stack->malloc_size(), early_thread_stack->malloc_count(), flag);
+ }
out->print_cr(")");
}
diff --git a/src/hotspot/share/services/memTracker.cpp b/src/hotspot/share/services/memTracker.cpp
index 42683393060..0f9be340b18 100644
--- a/src/hotspot/share/services/memTracker.cpp
+++ b/src/hotspot/share/services/memTracker.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2012, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2019, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -31,6 +31,7 @@
#include "services/memReporter.hpp"
#include "services/mallocTracker.inline.hpp"
#include "services/memTracker.hpp"
+#include "services/threadStackTracker.hpp"
#include "utilities/debug.hpp"
#include "utilities/defaultStream.hpp"
#include "utilities/vmError.hpp"
@@ -92,7 +93,8 @@ NMT_TrackingLevel MemTracker::init_tracking_level() {
void MemTracker::init() {
NMT_TrackingLevel level = tracking_level();
if (level >= NMT_summary) {
- if (!VirtualMemoryTracker::late_initialize(level)) {
+ if (!VirtualMemoryTracker::late_initialize(level) ||
+ !ThreadStackTracker::late_initialize(level)) {
shutdown();
return;
}
@@ -164,6 +166,7 @@ bool MemTracker::transition_to(NMT_TrackingLevel level) {
OrderAccess::fence();
VirtualMemoryTracker::transition(current_level, level);
MallocTracker::transition(current_level, level);
+ ThreadStackTracker::transition(current_level, level);
} else {
// Upgrading tracking level is not supported and has never been supported.
// Allocating and deallocating malloc tracking structures is not thread safe and
diff --git a/src/hotspot/share/services/memTracker.hpp b/src/hotspot/share/services/memTracker.hpp
index 2047c3ad150..04648f14d0b 100644
--- a/src/hotspot/share/services/memTracker.hpp
+++ b/src/hotspot/share/services/memTracker.hpp
@@ -82,6 +82,7 @@ class MemTracker : AllStatic {
#include "runtime/mutexLocker.hpp"
#include "runtime/threadCritical.hpp"
#include "services/mallocTracker.hpp"
+#include "services/threadStackTracker.hpp"
#include "services/virtualMemoryTracker.hpp"
extern volatile bool NMT_stack_walkable;
@@ -241,31 +242,19 @@ class MemTracker : AllStatic {
}
}
-#ifdef _AIX
- // See JDK-8202772 - temporarily disable thread stack tracking on AIX.
- static inline void record_thread_stack(void* addr, size_t size) {}
- static inline void release_thread_stack(void* addr, size_t size) {}
-#else
- static inline void record_thread_stack(void* addr, size_t size) {
+ static void record_thread_stack(void* addr, size_t size) {
if (tracking_level() < NMT_summary) return;
if (addr != NULL) {
- // uses thread stack malloc slot for book keeping number of threads
- MallocMemorySummary::record_malloc(0, mtThreadStack);
- record_virtual_memory_reserve(addr, size, CALLER_PC, mtThreadStack);
+ ThreadStackTracker::new_thread_stack((address)addr, size, CALLER_PC);
}
}
static inline void release_thread_stack(void* addr, size_t size) {
if (tracking_level() < NMT_summary) return;
if (addr != NULL) {
- // uses thread stack malloc slot for book keeping number of threads
- MallocMemorySummary::record_free(0, mtThreadStack);
- ThreadCritical tc;
- if (tracking_level() < NMT_summary) return;
- VirtualMemoryTracker::remove_released_region((address)addr, size);
+ ThreadStackTracker::delete_thread_stack((address)addr, size);
}
}
-#endif
// Query lock is used to synchronize the access to tracking data.
// So far, it is only used by JCmd query, but it may be used by
diff --git a/src/hotspot/share/services/threadStackTracker.cpp b/src/hotspot/share/services/threadStackTracker.cpp
new file mode 100644
index 00000000000..d09963b45b1
--- /dev/null
+++ b/src/hotspot/share/services/threadStackTracker.cpp
@@ -0,0 +1,133 @@
+/*
+ * Copyright (c) 2019, Red Hat, Inc. All rights reserved.
+ *
+ * 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 "runtime/atomic.hpp"
+#include "runtime/threadCritical.hpp"
+#include "services/mallocTracker.hpp"
+#include "services/memTracker.hpp"
+#include "services/virtualMemoryTracker.hpp"
+#include "services/threadStackTracker.hpp"
+
+volatile size_t ThreadStackTracker::_thread_count = 0;
+SortedLinkedList* ThreadStackTracker::_simple_thread_stacks = NULL;
+
+bool ThreadStackTracker::late_initialize(NMT_TrackingLevel level) {
+ if (level == NMT_detail && !track_as_vm()) {
+ _simple_thread_stacks = new (std::nothrow, ResourceObj::C_HEAP, mtNMT)
+ SortedLinkedList();
+ return (_simple_thread_stacks != NULL);
+ }
+ return true;
+}
+
+bool ThreadStackTracker::transition(NMT_TrackingLevel from, NMT_TrackingLevel to) {
+ assert (from != NMT_minimal, "cannot convert from the lowest tracking level to anything");
+ if (to == NMT_minimal) {
+ assert(from == NMT_summary || from == NMT_detail, "Just check");
+ ThreadCritical tc;
+ if (_simple_thread_stacks != NULL) {
+ delete _simple_thread_stacks;
+ _simple_thread_stacks = NULL;
+ }
+ }
+ return true;
+}
+
+int ThreadStackTracker::compare_thread_stack_base(const SimpleThreadStackSite& s1, const SimpleThreadStackSite& s2) {
+ return s1.base() - s2.base();
+}
+
+void ThreadStackTracker::new_thread_stack(void* base, size_t size, const NativeCallStack& stack) {
+ assert(MemTracker::tracking_level() >= NMT_summary, "Must be");
+ assert(base != NULL, "Should have been filtered");
+ if (track_as_vm()) {
+ ThreadCritical tc;
+ VirtualMemoryTracker::add_reserved_region((address)base, size, stack, mtThreadStack);
+ _thread_count ++;
+ } else {
+ // Use a slot in mallocMemorySummary for thread stack bookkeeping
+ MallocMemorySummary::record_malloc(size, mtThreadStack);
+ if (MemTracker::tracking_level() == NMT_detail) {
+ ThreadCritical tc;
+ assert(_simple_thread_stacks != NULL, "Must be initialized");
+ SimpleThreadStackSite site((address)base, size, stack);
+ _simple_thread_stacks->add(site);
+ }
+ }
+}
+
+void ThreadStackTracker::delete_thread_stack(void* base, size_t size) {
+ assert(MemTracker::tracking_level() >= NMT_summary, "Must be");
+ assert(base != NULL, "Should have been filtered");
+ if(track_as_vm()) {
+ ThreadCritical tc;
+ VirtualMemoryTracker::remove_released_region((address)base, size);
+ _thread_count--;
+ } else {
+ // Use a slot in mallocMemorySummary for thread stack bookkeeping
+ MallocMemorySummary::record_free(size, mtThreadStack);
+ if (MemTracker::tracking_level() == NMT_detail) {
+ ThreadCritical tc;
+ assert(_simple_thread_stacks != NULL, "Must be initialized");
+ SimpleThreadStackSite site((address)base, size);
+ bool removed = _simple_thread_stacks->remove(site);
+ assert(removed, "Must exist");
+ }
+ }
+}
+
+bool ThreadStackTracker::walk_simple_thread_stack_site(MallocSiteWalker* walker) {
+ if (!track_as_vm()) {
+ LinkedListImpl _sites;
+ {
+ ThreadCritical tc;
+ assert(_simple_thread_stacks != NULL, "Must be initialized");
+ LinkedListIterator itr(_simple_thread_stacks->head());
+ const SimpleThreadStackSite* ts = itr.next();
+ // Consolidate sites and convert to MallocSites, so we can piggyback into
+ // malloc snapshot
+ while (ts != NULL) {
+ MallocSite site(*ts->call_stack(), mtThreadStack);
+ MallocSite* exist = _sites.find(site);
+ if (exist != NULL) {
+ exist->allocate(ts->size());
+ } else {
+ site.allocate(ts->size());
+ _sites.add(site);
+ }
+ ts = itr.next();
+ }
+ }
+
+ // Piggyback to malloc snapshot
+ LinkedListIterator site_itr(_sites.head());
+ const MallocSite* s = site_itr.next();
+ while (s != NULL) {
+ walker->do_malloc_site(s);
+ s = site_itr.next();
+ }
+ }
+ return true;
+}
diff --git a/src/hotspot/share/services/threadStackTracker.hpp b/src/hotspot/share/services/threadStackTracker.hpp
new file mode 100644
index 00000000000..3615c8b27b1
--- /dev/null
+++ b/src/hotspot/share/services/threadStackTracker.hpp
@@ -0,0 +1,114 @@
+/*
+ * Copyright (c) 2019, Red Hat, Inc. All rights reserved.
+ *
+ * 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_SERVICES_THREADSTACKTRACKER_HPP
+#define SHARE_SERVICES_THREADSTACKTRACKER_HPP
+
+#if INCLUDE_NMT
+
+#include "services/allocationSite.hpp"
+#include "services/mallocSiteTable.hpp"
+#include "services/nmtCommon.hpp"
+#include "utilities/nativeCallStack.hpp"
+#include "utilities/linkedlist.hpp"
+
+class SimpleThreadStackSite;
+
+class SimpleThreadStack {
+ friend class SimpleThreadStackSite;
+private:
+ address _base;
+ size_t _size;
+public:
+ SimpleThreadStack() : _base(NULL), _size(0) { }
+ bool equals(const SimpleThreadStack& s) const {
+ return base() == s.base();
+ }
+
+ size_t size() const { return _size; }
+ address base() const { return _base; }
+private:
+ void set_size(size_t size) { _size = size; }
+ void set_base(address base) { _base = base; }
+};
+
+class SimpleThreadStackSite : public AllocationSite {
+public:
+ SimpleThreadStackSite(address base, size_t size, const NativeCallStack& stack) :
+ AllocationSite(stack, mtThreadStack) {
+ data()->set_size(size);
+ data()->set_base(base);
+ }
+
+ SimpleThreadStackSite(address base, size_t size) :
+ AllocationSite(NativeCallStack::empty_stack(), mtThreadStack) {
+ data()->set_base(base);
+ data()->set_size(size);
+ }
+
+ bool equals(const SimpleThreadStackSite& mts) const {
+ bool eq = base() == mts.base();
+ assert(!eq || size() == mts.size(), "Must match");
+ return eq;
+ }
+
+ size_t size() const { return peek()->size(); }
+ address base() const { return peek()->base(); }
+};
+
+ /*
+ * Most of platforms, that hotspot support, have their thread stacks backed by
+ * virtual memory by default. For these cases, thread stack tracker simply
+ * delegates tracking to virtual memory tracker.
+ * However, there are exceptions, (e.g. AIX), that platforms can provide stacks
+ * that are not page aligned. A hypothetical VM implementation, it can provide
+ * it own stacks. In these case, track_as_vm() should return false and manage
+ * stack tracking by this tracker internally.
+ * During memory snapshot, tracked thread stacks memory data is walked and stored
+ * along with malloc'd data inside baseline. The regions are not scanned and assumed
+ * all committed for now. Can add scanning phase when there is a need.
+ */
+class ThreadStackTracker : AllStatic {
+private:
+ static volatile size_t _thread_count;
+
+ static int compare_thread_stack_base(const SimpleThreadStackSite& s1, const SimpleThreadStackSite& s2);
+ static SortedLinkedList* _simple_thread_stacks;
+public:
+ // Late phase initialization
+ static bool late_initialize(NMT_TrackingLevel level);
+ static bool transition(NMT_TrackingLevel from, NMT_TrackingLevel to);
+
+ static void new_thread_stack(void* base, size_t size, const NativeCallStack& stack);
+ static void delete_thread_stack(void* base, size_t size);
+
+ static bool track_as_vm() { return AIX_ONLY(false) NOT_AIX(true); }
+ static size_t thread_count() { return _thread_count; }
+
+ // Snapshot support. Piggyback thread stack data in malloc slot, NMT always handles
+ // thread stack slot specially since beginning.
+ static bool walk_simple_thread_stack_site(MallocSiteWalker* walker);
+};
+
+#endif // INCLUDE_NMT
+#endif // SHARE_SERVICES_THREADSTACKTRACKER_HPP
diff --git a/src/hotspot/share/services/virtualMemoryTracker.cpp b/src/hotspot/share/services/virtualMemoryTracker.cpp
index fd4daf3f992..7651d08af98 100644
--- a/src/hotspot/share/services/virtualMemoryTracker.cpp
+++ b/src/hotspot/share/services/virtualMemoryTracker.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2013, 2019, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -29,6 +29,7 @@
#include "runtime/os.hpp"
#include "runtime/threadCritical.hpp"
#include "services/memTracker.hpp"
+#include "services/threadStackTracker.hpp"
#include "services/virtualMemoryTracker.hpp"
size_t VirtualMemorySummary::_snapshot[CALC_OBJ_SIZE_IN_TYPE(VirtualMemorySnapshot, size_t)];
@@ -40,9 +41,12 @@ void VirtualMemorySummary::initialize() {
}
void VirtualMemorySummary::snapshot(VirtualMemorySnapshot* s) {
- // Snapshot current thread stacks
- VirtualMemoryTracker::snapshot_thread_stacks();
- as_snapshot()->copy_to(s);
+ // Only if thread stack is backed by virtual memory
+ if (ThreadStackTracker::track_as_vm()) {
+ // Snapshot current thread stacks
+ VirtualMemoryTracker::snapshot_thread_stacks();
+ as_snapshot()->copy_to(s);
+ }
}
SortedLinkedList* VirtualMemoryTracker::_reserved_regions;
diff --git a/src/hotspot/share/utilities/vmError.cpp b/src/hotspot/share/utilities/vmError.cpp
index 23ebcdd81e9..f4d7d66ef25 100644
--- a/src/hotspot/share/utilities/vmError.cpp
+++ b/src/hotspot/share/utilities/vmError.cpp
@@ -1445,9 +1445,13 @@ void VMError::report_and_die(int id, const char* message, const char* detail_fmt
}
}
- // print to screen
+ // Part 1: print an abbreviated version (the '#' section) to stdout.
if (!out_done) {
- report(&out, false);
+ // Suppress this output if we plan to print Part 2 to stdout too.
+ // No need to have the "#" section twice.
+ if (!(ErrorFileToStdout && out.fd() == 1)) {
+ report(&out, false);
+ }
out_done = true;
@@ -1455,21 +1459,27 @@ void VMError::report_and_die(int id, const char* message, const char* detail_fmt
_current_step_info = "";
}
+ // Part 2: print a full error log file (optionally to stdout or stderr).
// print to error log file
if (!log_done) {
// see if log file is already open
if (!log.is_open()) {
// open log file
- fd_log = prepare_log_file(ErrorFile, "hs_err_pid%p.log", buffer, sizeof(buffer));
- if (fd_log != -1) {
- out.print_raw("# An error report file with more information is saved as:\n# ");
- out.print_raw_cr(buffer);
-
- log.set_fd(fd_log);
+ if (ErrorFileToStdout) {
+ fd_log = 1;
+ } else if (ErrorFileToStderr) {
+ fd_log = 2;
} else {
- out.print_raw_cr("# Can not save log file, dump to screen..");
- log.set_fd(fd_out);
+ fd_log = prepare_log_file(ErrorFile, "hs_err_pid%p.log", buffer, sizeof(buffer));
+ if (fd_log != -1) {
+ out.print_raw("# An error report file with more information is saved as:\n# ");
+ out.print_raw_cr(buffer);
+ } else {
+ out.print_raw_cr("# Can not save log file, dump to screen..");
+ fd_log = 1;
+ }
}
+ log.set_fd(fd_log);
}
report(&log, true);
@@ -1477,7 +1487,7 @@ void VMError::report_and_die(int id, const char* message, const char* detail_fmt
_current_step = 0;
_current_step_info = "";
- if (fd_log != -1) {
+ if (fd_log > 3) {
close(fd_log);
fd_log = -1;
}
@@ -1725,7 +1735,16 @@ void VMError::controlled_crash(int how) {
const char* const eol = os::line_separator();
const char* const msg = "this message should be truncated during formatting";
char * const dataPtr = NULL; // bad data pointer
- const void (*funcPtr)(void) = (const void(*)()) 0xF; // bad function pointer
+ const void (*funcPtr)(void); // bad function pointer
+
+#if defined(PPC64) && !defined(ABI_ELFv2)
+ struct FunctionDescriptor functionDescriptor;
+
+ functionDescriptor.set_entry((address) 0xF);
+ funcPtr = (const void(*)()) &functionDescriptor;
+#else
+ funcPtr = (const void(*)()) 0xF;
+#endif
// Keep this in sync with test/hotspot/jtreg/runtime/ErrorHandling/ErrorHandler.java
// which tests cases 1 thru 13.
diff --git a/src/java.base/share/classes/java/io/DataOutputStream.java b/src/java.base/share/classes/java/io/DataOutputStream.java
index 392abba9260..580612232e0 100644
--- a/src/java.base/share/classes/java/io/DataOutputStream.java
+++ b/src/java.base/share/classes/java/io/DataOutputStream.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1994, 2004, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1994, 2019, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -317,7 +317,10 @@ class DataOutputStream extends FilterOutputStream implements DataOutput {
* thrice the length of str.
*
* @param str a string to be written.
- * @exception IOException if an I/O error occurs.
+ * @throws UTFDataFormatException if the modified UTF-8 encoding of
+ * {@code str} would exceed 65535 bytes in length
+ * @throws IOException if some other I/O error occurs.
+ * @see #writeChars(String)
*/
public final void writeUTF(String str) throws IOException {
writeUTF(str, this);
@@ -341,55 +344,49 @@ class DataOutputStream extends FilterOutputStream implements DataOutput {
* @param str a string to be written.
* @param out destination to write to
* @return The number of bytes written out.
- * @exception IOException if an I/O error occurs.
+ * @throws UTFDataFormatException if the modified UTF-8 encoding of
+ * {@code str} would exceed 65535 bytes in length
+ * @throws IOException if some other I/O error occurs.
*/
static int writeUTF(String str, DataOutput out) throws IOException {
- int strlen = str.length();
- int utflen = 0;
- int c, count = 0;
+ final int strlen = str.length();
+ int utflen = strlen; // optimized for ASCII
- /* use charAt instead of copying String to char array */
for (int i = 0; i < strlen; i++) {
- c = str.charAt(i);
- if ((c >= 0x0001) && (c <= 0x007F)) {
- utflen++;
- } else if (c > 0x07FF) {
- utflen += 3;
- } else {
- utflen += 2;
- }
+ int c = str.charAt(i);
+ if (c >= 0x80 || c == 0)
+ utflen += (c >= 0x800) ? 2 : 1;
}
- if (utflen > 65535)
- throw new UTFDataFormatException(
- "encoded string too long: " + utflen + " bytes");
+ if (utflen > 65535 || /* overflow */ utflen < strlen)
+ throw new UTFDataFormatException(tooLongMsg(str, utflen));
- byte[] bytearr = null;
+ final byte[] bytearr;
if (out instanceof DataOutputStream) {
DataOutputStream dos = (DataOutputStream)out;
- if(dos.bytearr == null || (dos.bytearr.length < (utflen+2)))
+ if (dos.bytearr == null || (dos.bytearr.length < (utflen + 2)))
dos.bytearr = new byte[(utflen*2) + 2];
bytearr = dos.bytearr;
} else {
- bytearr = new byte[utflen+2];
+ bytearr = new byte[utflen + 2];
}
+ int count = 0;
bytearr[count++] = (byte) ((utflen >>> 8) & 0xFF);
bytearr[count++] = (byte) ((utflen >>> 0) & 0xFF);
- int i=0;
- for (i=0; i= 0x0001) && (c <= 0x007F))) break;
- bytearr[count++] = (byte) c;
+ int i = 0;
+ for (i = 0; i < strlen; i++) { // optimized for initial run of ASCII
+ int c = str.charAt(i);
+ if (c >= 0x80 || c == 0) break;
+ bytearr[count++] = (byte) c;
}
- for (;i < strlen; i++){
- c = str.charAt(i);
- if ((c >= 0x0001) && (c <= 0x007F)) {
+ for (; i < strlen; i++) {
+ int c = str.charAt(i);
+ if (c < 0x80 && c != 0) {
bytearr[count++] = (byte) c;
-
- } else if (c > 0x07FF) {
+ } else if (c >= 0x800) {
bytearr[count++] = (byte) (0xE0 | ((c >> 12) & 0x0F));
bytearr[count++] = (byte) (0x80 | ((c >> 6) & 0x3F));
bytearr[count++] = (byte) (0x80 | ((c >> 0) & 0x3F));
@@ -398,10 +395,20 @@ class DataOutputStream extends FilterOutputStream implements DataOutput {
bytearr[count++] = (byte) (0x80 | ((c >> 0) & 0x3F));
}
}
- out.write(bytearr, 0, utflen+2);
+ out.write(bytearr, 0, utflen + 2);
return utflen + 2;
}
+ private static String tooLongMsg(String s, int bits32) {
+ int slen = s.length();
+ String head = s.substring(0, 8);
+ String tail = s.substring(slen - 8, slen);
+ // handle int overflow with max 3x expansion
+ long actualLength = (long)slen + Integer.toUnsignedLong(bits32 - slen);
+ return "encoded string (" + head + "..." + tail + ") too long: "
+ + actualLength + " bytes";
+ }
+
/**
* Returns the current value of the counter written,
* the number of bytes written to this data output stream so far.
diff --git a/src/java.base/share/classes/java/io/InputStream.java b/src/java.base/share/classes/java/io/InputStream.java
index 938f041bbb7..66dcac4a1d4 100644
--- a/src/java.base/share/classes/java/io/InputStream.java
+++ b/src/java.base/share/classes/java/io/InputStream.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1994, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1994, 2019, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -237,7 +237,7 @@ public abstract class InputStream implements Closeable {
* b[off+len-1] unaffected.
*
* In every case, elements b[0] through
- * b[off] and elements b[off+len] through
+ * b[off-1] and elements b[off+len] through
* b[b.length-1] are unaffected.
*
*
The read(b, off, len) method
diff --git a/src/java.base/share/classes/java/lang/invoke/MethodHandles.java b/src/java.base/share/classes/java/lang/invoke/MethodHandles.java
index acadf988382..9c95890ce6a 100644
--- a/src/java.base/share/classes/java/lang/invoke/MethodHandles.java
+++ b/src/java.base/share/classes/java/lang/invoke/MethodHandles.java
@@ -422,6 +422,10 @@ public class MethodHandles {
* because the desired class member is missing, or because the
* desired class member is not accessible to the lookup class, or
* because the lookup object is not trusted enough to access the member.
+ * In the case of a field setter function on a {@code final} field,
+ * finality enforcement is treated as a kind of access control,
+ * and the lookup will fail, except in special cases of
+ * {@link Lookup#unreflectSetter Lookup.unreflectSetter}.
* In any of these cases, a {@code ReflectiveOperationException} will be
* thrown from the attempted lookup. The exact class will be one of
* the following:
@@ -1438,6 +1442,7 @@ assertEquals(""+l, (String) MH_this.invokeExact(subl)); // Listie method
* @return a method handle which can store values into the field
* @throws NoSuchFieldException if the field does not exist
* @throws IllegalAccessException if access checking fails, or if the field is {@code static}
+ * or {@code final}
* @exception SecurityException if a security manager is present and it
* refuses access
* @throws NullPointerException if any argument is null
@@ -1561,6 +1566,7 @@ assertEquals(""+l, (String) MH_this.invokeExact(subl)); // Listie method
* @return a method handle which can store values into the field
* @throws NoSuchFieldException if the field does not exist
* @throws IllegalAccessException if access checking fails, or if the field is not {@code static}
+ * or is {@code final}
* @exception SecurityException if a security manager is present and it
* refuses access
* @throws NullPointerException if any argument is null
@@ -1840,10 +1846,10 @@ return mh1;
* Produces a method handle giving read access to a reflected field.
* The type of the method handle will have a return type of the field's
* value type.
- * If the field is static, the method handle will take no arguments.
+ * If the field is {@code static}, the method handle will take no arguments.
* Otherwise, its single argument will be the instance containing
* the field.
- * If the field's {@code accessible} flag is not set,
+ * If the {@code Field} object's {@code accessible} flag is not set,
* access checking is performed immediately on behalf of the lookup class.
*
* If the field is static, and
@@ -1857,8 +1863,43 @@ return mh1;
public MethodHandle unreflectGetter(Field f) throws IllegalAccessException {
return unreflectField(f, false);
}
+
+ /**
+ * Produces a method handle giving write access to a reflected field.
+ * The type of the method handle will have a void return type.
+ * If the field is {@code static}, the method handle will take a single
+ * argument, of the field's value type, the value to be stored.
+ * Otherwise, the two arguments will be the instance containing
+ * the field, and the value to be stored.
+ * If the {@code Field} object's {@code accessible} flag is not set,
+ * access checking is performed immediately on behalf of the lookup class.
+ *
+ * If the field is {@code final}, write access will not be
+ * allowed and access checking will fail, except under certain
+ * narrow circumstances documented for {@link Field#set Field.set}.
+ * A method handle is returned only if a corresponding call to
+ * the {@code Field} object's {@code set} method could return
+ * normally. In particular, fields which are both {@code static}
+ * and {@code final} may never be set.
+ *
+ * If the field is {@code static}, and
+ * if the returned method handle is invoked, the field's class will
+ * be initialized, if it has not already been initialized.
+ * @param f the reflected field
+ * @return a method handle which can store values into the reflected field
+ * @throws IllegalAccessException if access checking fails,
+ * or if the field is {@code final} and write access
+ * is not enabled on the {@code Field} object
+ * @throws NullPointerException if the argument is null
+ */
+ public MethodHandle unreflectSetter(Field f) throws IllegalAccessException {
+ return unreflectField(f, true);
+ }
+
private MethodHandle unreflectField(Field f, boolean isSetter) throws IllegalAccessException {
MemberName field = new MemberName(f, isSetter);
+ if (isSetter && field.isStatic() && field.isFinal())
+ throw field.makeAccessException("static final field has no write access", this);
assert(isSetter
? MethodHandleNatives.refKindIsSetter(field.getReferenceKind())
: MethodHandleNatives.refKindIsGetter(field.getReferenceKind()));
@@ -1867,28 +1908,6 @@ return mh1;
return lookup.getDirectFieldNoSecurityManager(field.getReferenceKind(), f.getDeclaringClass(), field);
}
- /**
- * Produces a method handle giving write access to a reflected field.
- * The type of the method handle will have a void return type.
- * If the field is static, the method handle will take a single
- * argument, of the field's value type, the value to be stored.
- * Otherwise, the two arguments will be the instance containing
- * the field, and the value to be stored.
- * If the field's {@code accessible} flag is not set,
- * access checking is performed immediately on behalf of the lookup class.
- *
- * If the field is static, and
- * if the returned method handle is invoked, the field's class will
- * be initialized, if it has not already been initialized.
- * @param f the reflected field
- * @return a method handle which can store values into the reflected field
- * @throws IllegalAccessException if access checking fails
- * @throws NullPointerException if the argument is null
- */
- public MethodHandle unreflectSetter(Field f) throws IllegalAccessException {
- return unreflectField(f, true);
- }
-
/**
* Produces a VarHandle giving access to a reflected field {@code f}
* of type {@code T} declared in a class of type {@code R}.
diff --git a/src/java.base/share/classes/java/lang/module/Configuration.java b/src/java.base/share/classes/java/lang/module/Configuration.java
index 6e0a6ccd901..c6fc3631b33 100644
--- a/src/java.base/share/classes/java/lang/module/Configuration.java
+++ b/src/java.base/share/classes/java/lang/module/Configuration.java
@@ -575,7 +575,8 @@ public final class Configuration {
}
Set reads(ResolvedModule m) {
- return Collections.unmodifiableSet(graph.get(m));
+ // The sets stored in the graph are already immutable sets
+ return Set.copyOf(graph.get(m));
}
/**
diff --git a/src/java.base/share/classes/java/net/ServerSocket.java b/src/java.base/share/classes/java/net/ServerSocket.java
index 40f2199476c..7e59ab23f46 100644
--- a/src/java.base/share/classes/java/net/ServerSocket.java
+++ b/src/java.base/share/classes/java/net/ServerSocket.java
@@ -749,14 +749,17 @@ class ServerSocket implements java.io.Closeable {
* timeout must be {@code > 0}.
* A timeout of zero is interpreted as an infinite timeout.
* @param timeout the specified timeout, in milliseconds
- * @exception SocketException if there is an error in
- * the underlying protocol, such as a TCP error.
+ * @throws SocketException if there is an error in the underlying protocol,
+ * such as a TCP error
+ * @throws IllegalArgumentException if {@code timeout} is negative
* @since 1.1
* @see #getSoTimeout()
*/
public synchronized void setSoTimeout(int timeout) throws SocketException {
if (isClosed())
throw new SocketException("Socket is closed");
+ if (timeout < 0)
+ throw new IllegalArgumentException("timeout < 0");
getImpl().setOption(SocketOptions.SO_TIMEOUT, timeout);
}
diff --git a/src/java.base/share/classes/java/net/Socket.java b/src/java.base/share/classes/java/net/Socket.java
index 53d9131e8ce..df43a848f66 100644
--- a/src/java.base/share/classes/java/net/Socket.java
+++ b/src/java.base/share/classes/java/net/Socket.java
@@ -581,7 +581,8 @@ class Socket implements java.io.Closeable {
* if this socket has an associated channel,
* and the channel is in non-blocking mode
* @throws IllegalArgumentException if endpoint is null or is a
- * SocketAddress subclass not supported by this socket
+ * SocketAddress subclass not supported by this socket, or
+ * if {@code timeout} is negative
* @since 1.4
* @spec JSR-51
*/
@@ -1212,8 +1213,9 @@ class Socket implements java.io.Closeable {
* A timeout of zero is interpreted as an infinite timeout.
*
* @param timeout the specified timeout, in milliseconds.
- * @exception SocketException if there is an error
- * in the underlying protocol, such as a TCP error.
+ * @throws SocketException if there is an error in the underlying protocol,
+ * such as a TCP error
+ * @throws IllegalArgumentException if {@code timeout} is negative
* @since 1.1
* @see #getSoTimeout()
*/
diff --git a/src/java.base/share/classes/java/text/CompactNumberFormat.java b/src/java.base/share/classes/java/text/CompactNumberFormat.java
index 1ce8caa38b8..448f8dfcc76 100644
--- a/src/java.base/share/classes/java/text/CompactNumberFormat.java
+++ b/src/java.base/share/classes/java/text/CompactNumberFormat.java
@@ -836,7 +836,8 @@ public final class CompactNumberFormat extends NumberFormat {
if (ch == QUOTE) {
ch = pattern.charAt(index++);
if (ch == MINUS_SIGN) {
- ch = symbols.getMinusSign();
+ sb.append(symbols.getMinusSignText());
+ continue;
}
}
sb.append(ch);
@@ -859,11 +860,14 @@ public final class CompactNumberFormat extends NumberFormat {
if (ch == QUOTE) {
ch = pattern.charAt(index++);
if (ch == MINUS_SIGN) {
- ch = symbols.getMinusSign();
+ String minusText = symbols.getMinusSignText();
FieldPosition fp = new FieldPosition(NumberFormat.Field.SIGN);
fp.setBeginIndex(stringIndex);
- fp.setEndIndex(stringIndex + 1);
+ fp.setEndIndex(stringIndex + minusText.length());
positions.add(fp);
+ stringIndex += minusText.length();
+ affix.append(minusText);
+ continue;
}
}
stringIndex++;
diff --git a/src/java.base/share/classes/java/text/DecimalFormat.java b/src/java.base/share/classes/java/text/DecimalFormat.java
index 059fa5b6bdd..371323c7c1f 100644
--- a/src/java.base/share/classes/java/text/DecimalFormat.java
+++ b/src/java.base/share/classes/java/text/DecimalFormat.java
@@ -54,20 +54,20 @@ import sun.util.locale.provider.LocaleProviderAdapter;
import sun.util.locale.provider.ResourceBundleBasedAdapter;
/**
- * DecimalFormat is a concrete subclass of
- * NumberFormat that formats decimal numbers. It has a variety of
+ * {@code DecimalFormat} is a concrete subclass of
+ * {@code NumberFormat} that formats decimal numbers. It has a variety of
* features designed to make it possible to parse and format numbers in any
* locale, including support for Western, Arabic, and Indic digits. It also
* supports different kinds of numbers, including integers (123), fixed-point
* numbers (123.4), scientific notation (1.23E4), percentages (12%), and
* currency amounts ($123). All of these can be localized.
*
- * To obtain a NumberFormat for a specific locale, including the
- * default locale, call one of NumberFormat's factory methods, such
- * as getInstance(). In general, do not call the
- * DecimalFormat constructors directly, since the
- * NumberFormat factory methods may return subclasses other than
- * DecimalFormat. If you need to customize the format object, do
+ *
To obtain a {@code NumberFormat} for a specific locale, including the
+ * default locale, call one of {@code NumberFormat}'s factory methods, such
+ * as {@code getInstance()}. In general, do not call the
+ * {@code DecimalFormat} constructors directly, since the
+ * {@code NumberFormat} factory methods may return subclasses other than
+ * {@code DecimalFormat}. If you need to customize the format object, do
* something like this:
*
*
@@ -77,16 +77,16 @@ import sun.util.locale.provider.ResourceBundleBasedAdapter;
* }
*
*
- * A DecimalFormat comprises a pattern and a set of
+ *
A {@code DecimalFormat} comprises a pattern and a set of
* symbols. The pattern may be set directly using
- * applyPattern(), or indirectly using the API methods. The
- * symbols are stored in a DecimalFormatSymbols object. When using
- * the NumberFormat factory methods, the pattern and symbols are
- * read from localized ResourceBundles.
+ * {@code applyPattern()}, or indirectly using the API methods. The
+ * symbols are stored in a {@code DecimalFormatSymbols} object. When using
+ * the {@code NumberFormat} factory methods, the pattern and symbols are
+ * read from localized {@code ResourceBundle}s.
*
*
Patterns
*
- * DecimalFormat patterns have the following syntax:
+ * {@code DecimalFormat} patterns have the following syntax:
*
* Pattern:
* PositivePattern
@@ -123,26 +123,26 @@ import sun.util.locale.provider.ResourceBundleBasedAdapter;
* 0 MinimumExponentopt
*
*
- * A DecimalFormat pattern contains a positive and negative
- * subpattern, for example, "#,##0.00;(#,##0.00)". Each
+ *
A {@code DecimalFormat} pattern contains a positive and negative
+ * subpattern, for example, {@code "#,##0.00;(#,##0.00)"}. Each
* subpattern has a prefix, numeric part, and suffix. The negative subpattern
* is optional; if absent, then the positive subpattern prefixed with the
- * localized minus sign ('-' in most locales) is used as the
- * negative subpattern. That is, "0.00" alone is equivalent to
- * "0.00;-0.00". If there is an explicit negative subpattern, it
+ * localized minus sign ({@code '-'} in most locales) is used as the
+ * negative subpattern. That is, {@code "0.00"} alone is equivalent to
+ * {@code "0.00;-0.00"}. If there is an explicit negative subpattern, it
* serves only to specify the negative prefix and suffix; the number of digits,
* minimal digits, and other characteristics are all the same as the positive
- * pattern. That means that "#,##0.0#;(#)" produces precisely
- * the same behavior as "#,##0.0#;(#,##0.0#)".
+ * pattern. That means that {@code "#,##0.0#;(#)"} produces precisely
+ * the same behavior as {@code "#,##0.0#;(#,##0.0#)"}.
*
*
The prefixes, suffixes, and various symbols used for infinity, digits,
* thousands separators, decimal separators, etc. may be set to arbitrary
* values, and they will appear properly during formatting. However, care must
* be taken that the symbols and strings do not conflict, or parsing will be
* unreliable. For example, either the positive and negative prefixes or the
- * suffixes must be distinct for DecimalFormat.parse() to be able
+ * suffixes must be distinct for {@code DecimalFormat.parse()} to be able
* to distinguish positive from negative values. (If they are identical, then
- * DecimalFormat will behave as if no negative subpattern was
+ * {@code DecimalFormat} will behave as if no negative subpattern was
* specified.) Another example is that the decimal separator and thousands
* separator should be distinct characters, or parsing will be impossible.
*
@@ -151,8 +151,8 @@ import sun.util.locale.provider.ResourceBundleBasedAdapter;
* of digits between the grouping characters, such as 3 for 100,000,000 or 4 for
* 1,0000,0000. If you supply a pattern with multiple grouping characters, the
* interval between the last one and the end of the integer is the one that is
- * used. So "#,##,###,####" == "######,####" ==
- * "##,####,####".
+ * used. So {@code "#,##,###,####"} == {@code "######,####"} ==
+ * {@code "##,####,####"}.
*
*
Special Pattern Characters
*
@@ -164,7 +164,7 @@ import sun.util.locale.provider.ResourceBundleBasedAdapter;
*
* The characters listed here are used in non-localized patterns. Localized
* patterns use the corresponding characters taken from this formatter's
- * DecimalFormatSymbols object instead, and these characters lose
+ * {@code DecimalFormatSymbols} object instead, and these characters lose
* their special status. Two exceptions are the currency sign and quote, which
* are not localized.
*
@@ -180,53 +180,53 @@ import sun.util.locale.provider.ResourceBundleBasedAdapter;
*
*
*
- * 0
+ * {@code 0}
* Number
* Yes
* Digit
*
- * #
+ * {@code #}
* Number
* Yes
* Digit, zero shows as absent
*
- * .
+ * {@code .}
* Number
* Yes
* Decimal separator or monetary decimal separator
*
- * -
+ * {@code -}
* Number
* Yes
* Minus sign
*
- * ,
+ * {@code ,}
* Number
* Yes
* Grouping separator
*
- * E
+ * {@code E}
* Number
* Yes
* Separates mantissa and exponent in scientific notation.
* Need not be quoted in prefix or suffix.
*
- * ;
+ * {@code ;}
* Subpattern boundary
* Yes
* Separates positive and negative subpatterns
*
- * %
+ * {@code %}
* Prefix or suffix
* Yes
* Multiply by 100 and show as percentage
*
- * \u2030
+ * {@code \u2030}
* Prefix or suffix
* Yes
* Multiply by 1000 and show as per mille value
*
- * ¤ (\u00A4)
+ * {@code ¤} ({@code \u00A4})
* Prefix or suffix
* No
* Currency sign, replaced by currency symbol. If
@@ -234,13 +234,13 @@ import sun.util.locale.provider.ResourceBundleBasedAdapter;
* If present in a pattern, the monetary decimal separator
* is used instead of the decimal separator.
*
- * '
+ * {@code '}
* Prefix or suffix
* No
* Used to quote special characters in a prefix or suffix,
- * for example, "'#'#" formats 123 to
- * "#123". To create a single quote
- * itself, use two in a row: "# o''clock".
+ * for example, {@code "'#'#"} formats 123 to
+ * {@code "#123"}. To create a single quote
+ * itself, use two in a row: {@code "# o''clock"}.
*
*
*
@@ -251,18 +251,18 @@ import sun.util.locale.provider.ResourceBundleBasedAdapter;
* and a power of ten, for example, 1234 can be expressed as 1.234 x 10^3. The
* mantissa is often in the range 1.0 ≤ x {@literal <} 10.0, but it need not
* be.
- * DecimalFormat can be instructed to format and parse scientific
+ * {@code DecimalFormat} can be instructed to format and parse scientific
* notation only via a pattern; there is currently no factory method
* that creates a scientific notation format. In a pattern, the exponent
* character immediately followed by one or more digit characters indicates
- * scientific notation. Example: "0.###E0" formats the number
- * 1234 as "1.234E3".
+ * scientific notation. Example: {@code "0.###E0"} formats the number
+ * 1234 as {@code "1.234E3"}.
*
*
* - The number of digit characters after the exponent character gives the
* minimum exponent digit count. There is no maximum. Negative exponents are
* formatted using the localized minus sign, not the prefix and suffix
- * from the pattern. This allows patterns such as
"0.###E0 m/s".
+ * from the pattern. This allows patterns such as {@code "0.###E0 m/s"}.
*
* - The minimum and maximum number of integer digits are interpreted
* together:
@@ -273,19 +273,19 @@ import sun.util.locale.provider.ResourceBundleBasedAdapter;
* number of integer digits, and the minimum number of integer digits to be
* interpreted as 1. The most common use of this is to generate
* engineering notation, in which the exponent is a multiple of three,
- * e.g.,
"##0.#####E0". Using this pattern, the number 12345
- * formats to "12.345E3", and 123456 formats to
- * "123.456E3".
+ * e.g., {@code "##0.#####E0"}. Using this pattern, the number 12345
+ * formats to {@code "12.345E3"}, and 123456 formats to
+ * {@code "123.456E3"}.
*
* - Otherwise, the minimum number of integer digits is achieved by adjusting the
- * exponent. Example: 0.00123 formatted with
"00.###E0" yields
- * "12.3E-4".
+ * exponent. Example: 0.00123 formatted with {@code "00.###E0"} yields
+ * {@code "12.3E-4"}.
*
*
* The number of significant digits in the mantissa is the sum of the
* minimum integer and maximum fraction digits, and is
* unaffected by the maximum integer digits. For example, 12345 formatted with
- * "##0.##E0" is "12.3E3". To show all digits, set
+ * {@code "##0.##E0"} is {@code "12.3E3"}. To show all digits, set
* the significant digits count to zero. The number of significant digits
* does not affect parsing.
*
@@ -294,38 +294,38 @@ import sun.util.locale.provider.ResourceBundleBasedAdapter;
*
* Rounding
*
- * DecimalFormat provides rounding modes defined in
+ * {@code DecimalFormat} provides rounding modes defined in
* {@link java.math.RoundingMode} for formatting. By default, it uses
* {@link java.math.RoundingMode#HALF_EVEN RoundingMode.HALF_EVEN}.
*
* Digits
*
- * For formatting, DecimalFormat uses the ten consecutive
+ * For formatting, {@code DecimalFormat} uses the ten consecutive
* characters starting with the localized zero digit defined in the
- * DecimalFormatSymbols object as digits. For parsing, these
+ * {@code DecimalFormatSymbols} object as digits. For parsing, these
* digits as well as all Unicode decimal digits, as defined by
* {@link Character#digit Character.digit}, are recognized.
*
* Special Values
*
- * NaN is formatted as a string, which typically has a single character
- * \uFFFD. This string is determined by the
- * DecimalFormatSymbols object. This is the only value for which
+ *
{@code NaN} is formatted as a string, which typically has a single character
+ * {@code \uFFFD}. This string is determined by the
+ * {@code DecimalFormatSymbols} object. This is the only value for which
* the prefixes and suffixes are not used.
*
*
Infinity is formatted as a string, which typically has a single character
- * \u221E, with the positive or negative prefixes and suffixes
+ * {@code \u221E}, with the positive or negative prefixes and suffixes
* applied. The infinity string is determined by the
- * DecimalFormatSymbols object.
+ * {@code DecimalFormatSymbols} object.
*
- *
Negative zero ("-0") parses to
+ *
Negative zero ({@code "-0"}) parses to
*
- * BigDecimal(0) if isParseBigDecimal() is
+ * - {@code BigDecimal(0)} if {@code isParseBigDecimal()} is
* true,
- *
Long(0) if isParseBigDecimal() is false
- * and isParseIntegerOnly() is true,
- * Double(-0.0) if both isParseBigDecimal()
- * and isParseIntegerOnly() are false.
+ * - {@code Long(0)} if {@code isParseBigDecimal()} is false
+ * and {@code isParseIntegerOnly()} is true,
+ *
- {@code Double(-0.0)} if both {@code isParseBigDecimal()}
+ * and {@code isParseIntegerOnly()} are false.
*
*
* Synchronization
@@ -425,7 +425,7 @@ public class DecimalFormat extends NumberFormat {
* locale.
*
* @param pattern a non-localized pattern string.
- * @exception NullPointerException if pattern is null
+ * @exception NullPointerException if {@code pattern} is null
* @exception IllegalArgumentException if the given pattern is invalid.
* @see java.text.NumberFormat#getInstance
* @see java.text.NumberFormat#getNumberInstance
@@ -475,7 +475,7 @@ public class DecimalFormat extends NumberFormat {
*
* This implementation uses the maximum precision permitted.
* @param number the number to format
- * @param toAppendTo the StringBuffer to which the formatted
+ * @param toAppendTo the {@code StringBuffer} to which the formatted
* text is to be appended
* @param pos keeps track on the position of the field within the
* returned string. For example, for formatting a number
@@ -485,11 +485,11 @@ public class DecimalFormat extends NumberFormat {
* and end index of {@code fieldPosition} will be set
* to 0 and 9, respectively for the output string
* {@code 1,234,567.89}.
- * @return the value passed in as toAppendTo
- * @exception IllegalArgumentException if number is
- * null or not an instance of Number.
- * @exception NullPointerException if toAppendTo or
- * pos is null
+ * @return the value passed in as {@code toAppendTo}
+ * @exception IllegalArgumentException if {@code number} is
+ * null or not an instance of {@code Number}.
+ * @exception NullPointerException if {@code toAppendTo} or
+ * {@code pos} is null
* @exception ArithmeticException if rounding is needed with rounding
* mode being set to RoundingMode.UNNECESSARY
* @see java.text.FieldPosition
@@ -914,13 +914,13 @@ public class DecimalFormat extends NumberFormat {
}
/**
- * Formats an Object producing an AttributedCharacterIterator.
- * You can use the returned AttributedCharacterIterator
+ * Formats an Object producing an {@code AttributedCharacterIterator}.
+ * You can use the returned {@code AttributedCharacterIterator}
* to build the resulting String, as well as to determine information
* about the resulting String.
*
* Each attribute key of the AttributedCharacterIterator will be of type
- * NumberFormat.Field, with the attribute value being the
+ * {@code NumberFormat.Field}, with the attribute value being the
* same as the attribute key.
*
* @exception NullPointerException if obj is null.
@@ -1916,7 +1916,7 @@ public class DecimalFormat extends NumberFormat {
if (negativeExponent) {
exponent = -exponent;
fieldStart = result.length();
- result.append(symbols.getMinusSign());
+ result.append(symbols.getMinusSignText());
delegate.formatted(Field.EXPONENT_SIGN, Field.EXPONENT_SIGN,
fieldStart, result.length(), result);
}
@@ -2042,17 +2042,17 @@ public class DecimalFormat extends NumberFormat {
}
/**
- * Appends the String string to result.
- * delegate is notified of all the
- * FieldPositions in positions.
+ * Appends the String {@code string} to {@code result}.
+ * {@code delegate} is notified of all the
+ * {@code FieldPosition}s in {@code positions}.
*
- * If one of the FieldPositions in positions
- * identifies a SIGN attribute, it is mapped to
- * signAttribute. This is used
- * to map the SIGN attribute to the EXPONENT
+ * If one of the {@code FieldPosition}s in {@code positions}
+ * identifies a {@code SIGN} attribute, it is mapped to
+ * {@code signAttribute}. This is used
+ * to map the {@code SIGN} attribute to the {@code EXPONENT}
* attribute as necessary.
*
- * This is used by subformat to add the prefix/suffix.
+ * This is used by {@code subformat} to add the prefix/suffix.
*/
private void append(StringBuffer result, String string,
FieldDelegate delegate,
@@ -2078,60 +2078,60 @@ public class DecimalFormat extends NumberFormat {
}
/**
- * Parses text from a string to produce a Number.
+ * Parses text from a string to produce a {@code Number}.
*
* The method attempts to parse text starting at the index given by
- * pos.
- * If parsing succeeds, then the index of pos is updated
+ * {@code pos}.
+ * If parsing succeeds, then the index of {@code pos} is updated
* to the index after the last character used (parsing does not necessarily
* use all characters up to the end of the string), and the parsed
- * number is returned. The updated pos can be used to
+ * number is returned. The updated {@code pos} can be used to
* indicate the starting point for the next call to this method.
- * If an error occurs, then the index of pos is not
- * changed, the error index of pos is set to the index of
+ * If an error occurs, then the index of {@code pos} is not
+ * changed, the error index of {@code pos} is set to the index of
* the character where the error occurred, and null is returned.
*
* The subclass returned depends on the value of {@link #isParseBigDecimal}
* as well as on the string being parsed.
*
- * - If
isParseBigDecimal() is false (the default),
- * most integer values are returned as Long
- * objects, no matter how they are written: "17" and
- * "17.000" both parse to Long(17).
- * Values that cannot fit into a Long are returned as
- * Doubles. This includes values with a fractional part,
- * infinite values, NaN, and the value -0.0.
- * DecimalFormat does not decide whether to
- * return a Double or a Long based on the
+ * - If {@code isParseBigDecimal()} is false (the default),
+ * most integer values are returned as {@code Long}
+ * objects, no matter how they are written: {@code "17"} and
+ * {@code "17.000"} both parse to {@code Long(17)}.
+ * Values that cannot fit into a {@code Long} are returned as
+ * {@code Double}s. This includes values with a fractional part,
+ * infinite values, {@code NaN}, and the value -0.0.
+ * {@code DecimalFormat} does not decide whether to
+ * return a {@code Double} or a {@code Long} based on the
* presence of a decimal separator in the source string. Doing so
* would prevent integers that overflow the mantissa of a double,
- * such as
"-9,223,372,036,854,775,808.00", from being
+ * such as {@code "-9,223,372,036,854,775,808.00"}, from being
* parsed accurately.
*
- * Callers may use the Number methods
- * doubleValue, longValue, etc., to obtain
+ * Callers may use the {@code Number} methods
+ * {@code doubleValue}, {@code longValue}, etc., to obtain
* the type they want.
- *
- If
isParseBigDecimal() is true, values are returned
- * as BigDecimal objects. The values are the ones
+ * - If {@code isParseBigDecimal()} is true, values are returned
+ * as {@code BigDecimal} objects. The values are the ones
* constructed by {@link java.math.BigDecimal#BigDecimal(String)}
* for corresponding strings in locale-independent format. The
* special cases negative and positive infinity and NaN are returned
- * as
Double instances holding the values of the
- * corresponding Double constants.
+ * as {@code Double} instances holding the values of the
+ * corresponding {@code Double} constants.
*
*
- * DecimalFormat parses all Unicode characters that represent
- * decimal digits, as defined by Character.digit(). In
- * addition, DecimalFormat also recognizes as digits the ten
+ * {@code DecimalFormat} parses all Unicode characters that represent
+ * decimal digits, as defined by {@code Character.digit()}. In
+ * addition, {@code DecimalFormat} also recognizes as digits the ten
* consecutive characters starting with the localized zero digit defined in
- * the DecimalFormatSymbols object.
+ * the {@code DecimalFormatSymbols} object.
*
* @param text the string to be parsed
- * @param pos A ParsePosition object with index and error
+ * @param pos A {@code ParsePosition} object with index and error
* index information as described above.
- * @return the parsed value, or null if the parse fails
- * @exception NullPointerException if text or
- * pos is null.
+ * @return the parsed value, or {@code null} if the parse fails
+ * @exception NullPointerException if {@code text} or
+ * {@code pos} is null.
*/
@Override
public Number parse(String text, ParsePosition pos) {
@@ -2475,7 +2475,7 @@ public class DecimalFormat extends NumberFormat {
boolean[] stat = new boolean[STATUS_LENGTH];
DigitList exponentDigits = new DigitList();
- if (subparse(text, pos, "", Character.toString(symbols.getMinusSign()), exponentDigits, true, stat) &&
+ if (subparse(text, pos, "", symbols.getMinusSignText(), exponentDigits, true, stat) &&
exponentDigits.fitsIntoLong(stat[STATUS_POSITIVE], true)) {
position = pos.index; // Advance past the exponent
exponent = (int)exponentDigits.getLong();
@@ -2573,7 +2573,7 @@ public class DecimalFormat extends NumberFormat {
/**
* Returns the FieldPositions of the fields in the prefix used for
* positive numbers. This is not used if the user has explicitly set
- * a positive prefix via setPositivePrefix. This is
+ * a positive prefix via {@code setPositivePrefix}. This is
* lazily created.
*
* @return FieldPositions in positive prefix
@@ -2614,7 +2614,7 @@ public class DecimalFormat extends NumberFormat {
/**
* Returns the FieldPositions of the fields in the prefix used for
* negative numbers. This is not used if the user has explicitly set
- * a negative prefix via setNegativePrefix. This is
+ * a negative prefix via {@code setNegativePrefix}. This is
* lazily created.
*
* @return FieldPositions in positive prefix
@@ -2655,7 +2655,7 @@ public class DecimalFormat extends NumberFormat {
/**
* Returns the FieldPositions of the fields in the suffix used for
* positive numbers. This is not used if the user has explicitly set
- * a positive suffix via setPositiveSuffix. This is
+ * a positive suffix via {@code setPositiveSuffix}. This is
* lazily created.
*
* @return FieldPositions in positive prefix
@@ -2696,7 +2696,7 @@ public class DecimalFormat extends NumberFormat {
/**
* Returns the FieldPositions of the fields in the suffix used for
* negative numbers. This is not used if the user has explicitly set
- * a negative suffix via setNegativeSuffix. This is
+ * a negative suffix via {@code setNegativeSuffix}. This is
* lazily created.
*
* @return FieldPositions in positive prefix
@@ -2811,7 +2811,7 @@ public class DecimalFormat extends NumberFormat {
/**
* Returns whether the {@link #parse(java.lang.String, java.text.ParsePosition)}
- * method returns BigDecimal. The default value is false.
+ * method returns {@code BigDecimal}. The default value is false.
*
* @return {@code true} if the parse method returns BigDecimal;
* {@code false} otherwise
@@ -2824,7 +2824,7 @@ public class DecimalFormat extends NumberFormat {
/**
* Sets whether the {@link #parse(java.lang.String, java.text.ParsePosition)}
- * method returns BigDecimal.
+ * method returns {@code BigDecimal}.
*
* @param newValue {@code true} if the parse method returns BigDecimal;
* {@code false} otherwise
@@ -2991,14 +2991,14 @@ public class DecimalFormat extends NumberFormat {
}
continue;
case PATTERN_PERCENT:
- c = symbols.getPercent();
- break;
+ buffer.append(symbols.getPercentText());
+ continue;
case PATTERN_PER_MILLE:
- c = symbols.getPerMill();
- break;
+ buffer.append(symbols.getPerMillText());
+ continue;
case PATTERN_MINUS:
- c = symbols.getMinusSign();
- break;
+ buffer.append(symbols.getMinusSignText());
+ continue;
}
}
buffer.append(c);
@@ -3027,12 +3027,11 @@ public class DecimalFormat extends NumberFormat {
for (int i=0; i(2);
- }
- FieldPosition fp = new FieldPosition(Field.CURRENCY);
- fp.setBeginIndex(stringIndex);
- fp.setEndIndex(stringIndex + string.length());
- positions.add(fp);
- stringIndex += string.length();
- }
- continue;
+ fieldID = Field.CURRENCY;
+ break;
case PATTERN_PERCENT:
- c = symbols.getPercent();
- field = -1;
+ string = symbols.getPercentText();
fieldID = Field.PERCENT;
break;
case PATTERN_PER_MILLE:
- c = symbols.getPerMill();
- field = -1;
+ string = symbols.getPerMillText();
fieldID = Field.PERMILLE;
break;
case PATTERN_MINUS:
- c = symbols.getMinusSign();
- field = -1;
+ string = symbols.getMinusSignText();
fieldID = Field.SIGN;
break;
}
- if (fieldID != null) {
+
+ if (fieldID != null && !string.isEmpty()) {
if (positions == null) {
positions = new ArrayList<>(2);
}
- FieldPosition fp = new FieldPosition(fieldID, field);
+ FieldPosition fp = new FieldPosition(fieldID);
fp.setBeginIndex(stringIndex);
- fp.setEndIndex(stringIndex + 1);
+ fp.setEndIndex(stringIndex + string.length());
positions.add(fp);
+ stringIndex += string.length();
+ continue;
}
}
stringIndex++;
@@ -3129,14 +3119,14 @@ public class DecimalFormat extends NumberFormat {
} else if (localized) {
switch (c) {
case PATTERN_PERCENT:
- c = symbols.getPercent();
- break;
+ buffer.append(symbols.getPercentText());
+ continue;
case PATTERN_PER_MILLE:
- c = symbols.getPerMill();
- break;
+ buffer.append(symbols.getPerMillText());
+ continue;
case PATTERN_MINUS:
- c = symbols.getMinusSign();
- break;
+ buffer.append(symbols.getMinusSignText());
+ continue;
}
}
buffer.append(c);
@@ -3155,11 +3145,11 @@ public class DecimalFormat extends NumberFormat {
needQuote = affix.indexOf(symbols.getZeroDigit()) >= 0
|| affix.indexOf(symbols.getGroupingSeparator()) >= 0
|| affix.indexOf(symbols.getDecimalSeparator()) >= 0
- || affix.indexOf(symbols.getPercent()) >= 0
- || affix.indexOf(symbols.getPerMill()) >= 0
+ || affix.indexOf(symbols.getPercentText()) >= 0
+ || affix.indexOf(symbols.getPerMillText()) >= 0
|| affix.indexOf(symbols.getDigit()) >= 0
|| affix.indexOf(symbols.getPatternSeparator()) >= 0
- || affix.indexOf(symbols.getMinusSign()) >= 0
+ || affix.indexOf(symbols.getMinusSignText()) >= 0
|| affix.indexOf(CURRENCY_SIGN) >= 0;
} else {
needQuote = affix.indexOf(PATTERN_ZERO_DIGIT) >= 0
@@ -3235,7 +3225,7 @@ public class DecimalFormat extends NumberFormat {
if ((negPrefixPattern != null && posPrefixPattern != null &&
negPrefixPattern.equals("'-" + posPrefixPattern)) ||
(negPrefixPattern == posPrefixPattern && // n == p == null
- negativePrefix.equals(symbols.getMinusSign() + positivePrefix)))
+ negativePrefix.equals(symbols.getMinusSignText() + positivePrefix)))
break;
}
result.append(localized ? symbols.getPatternSeparator() :
@@ -3255,16 +3245,16 @@ public class DecimalFormat extends NumberFormat {
* by this routine, since that is the typical end-user desire;
* use setMaximumInteger if you want to set a real value.
* For negative numbers, use a second pattern, separated by a semicolon
- * Example "#,#00.0#" → 1,234.56
+ *
Example {@code "#,#00.0#"} → 1,234.56
*
This means a minimum of 2 integer digits, 1 fraction digit, and
* a maximum of 2 fraction digits.
- *
Example: "#,#00.0#;(#,#00.0#)" for negatives in
+ *
Example: {@code "#,#00.0#;(#,#00.0#)"} for negatives in
* parentheses.
*
In negative patterns, the minimum and maximum counts are ignored;
* these are presumed to be set in the positive pattern.
*
* @param pattern a new pattern
- * @exception NullPointerException if pattern is null
+ * @exception NullPointerException if {@code pattern} is null
* @exception IllegalArgumentException if the given pattern is invalid.
*/
public void applyPattern(String pattern) {
@@ -3282,16 +3272,16 @@ public class DecimalFormat extends NumberFormat {
* by this routine, since that is the typical end-user desire;
* use setMaximumInteger if you want to set a real value.
* For negative numbers, use a second pattern, separated by a semicolon
- *
Example "#,#00.0#" → 1,234.56
+ *
Example {@code "#,#00.0#"} → 1,234.56
*
This means a minimum of 2 integer digits, 1 fraction digit, and
* a maximum of 2 fraction digits.
- *
Example: "#,#00.0#;(#,#00.0#)" for negatives in
+ *
Example: {@code "#,#00.0#;(#,#00.0#)"} for negatives in
* parentheses.
*
In negative patterns, the minimum and maximum counts are ignored;
* these are presumed to be set in the positive pattern.
*
* @param pattern a new pattern
- * @exception NullPointerException if pattern is null
+ * @exception NullPointerException if {@code pattern} is null
* @exception IllegalArgumentException if the given pattern is invalid.
*/
public void applyLocalizedPattern(String pattern) {
@@ -3309,7 +3299,7 @@ public class DecimalFormat extends NumberFormat {
char perMill = PATTERN_PER_MILLE;
char digit = PATTERN_DIGIT;
char separator = PATTERN_SEPARATOR;
- String exponent = PATTERN_EXPONENT;
+ String exponent = PATTERN_EXPONENT;
char minus = PATTERN_MINUS;
if (localized) {
zeroDigit = symbols.getZeroDigit();
@@ -3635,8 +3625,8 @@ public class DecimalFormat extends NumberFormat {
/**
* Sets the maximum number of digits allowed in the integer portion of a
* number.
- * For formatting numbers other than BigInteger and
- * BigDecimal objects, the lower of newValue and
+ * For formatting numbers other than {@code BigInteger} and
+ * {@code BigDecimal} objects, the lower of {@code newValue} and
* 309 is used. Negative input values are replaced with 0.
* @see NumberFormat#setMaximumIntegerDigits
*/
@@ -3656,8 +3646,8 @@ public class DecimalFormat extends NumberFormat {
/**
* Sets the minimum number of digits allowed in the integer portion of a
* number.
- * For formatting numbers other than BigInteger and
- * BigDecimal objects, the lower of newValue and
+ * For formatting numbers other than {@code BigInteger} and
+ * {@code BigDecimal} objects, the lower of {@code newValue} and
* 309 is used. Negative input values are replaced with 0.
* @see NumberFormat#setMinimumIntegerDigits
*/
@@ -3677,8 +3667,8 @@ public class DecimalFormat extends NumberFormat {
/**
* Sets the maximum number of digits allowed in the fraction portion of a
* number.
- * For formatting numbers other than BigInteger and
- * BigDecimal objects, the lower of newValue and
+ * For formatting numbers other than {@code BigInteger} and
+ * {@code BigDecimal} objects, the lower of {@code newValue} and
* 340 is used. Negative input values are replaced with 0.
* @see NumberFormat#setMaximumFractionDigits
*/
@@ -3698,8 +3688,8 @@ public class DecimalFormat extends NumberFormat {
/**
* Sets the minimum number of digits allowed in the fraction portion of a
* number.
- * For formatting numbers other than BigInteger and
- * BigDecimal objects, the lower of newValue and
+ * For formatting numbers other than {@code BigInteger} and
+ * {@code BigDecimal} objects, the lower of {@code newValue} and
* 340 is used. Negative input values are replaced with 0.
* @see NumberFormat#setMinimumFractionDigits
*/
@@ -3719,8 +3709,8 @@ public class DecimalFormat extends NumberFormat {
/**
* Gets the maximum number of digits allowed in the integer portion of a
* number.
- * For formatting numbers other than BigInteger and
- * BigDecimal objects, the lower of the return value and
+ * For formatting numbers other than {@code BigInteger} and
+ * {@code BigDecimal} objects, the lower of the return value and
* 309 is used.
* @see #setMaximumIntegerDigits
*/
@@ -3732,8 +3722,8 @@ public class DecimalFormat extends NumberFormat {
/**
* Gets the minimum number of digits allowed in the integer portion of a
* number.
- * For formatting numbers other than BigInteger and
- * BigDecimal objects, the lower of the return value and
+ * For formatting numbers other than {@code BigInteger} and
+ * {@code BigDecimal} objects, the lower of the return value and
* 309 is used.
* @see #setMinimumIntegerDigits
*/
@@ -3745,8 +3735,8 @@ public class DecimalFormat extends NumberFormat {
/**
* Gets the maximum number of digits allowed in the fraction portion of a
* number.
- * For formatting numbers other than BigInteger and
- * BigDecimal objects, the lower of the return value and
+ * For formatting numbers other than {@code BigInteger} and
+ * {@code BigDecimal} objects, the lower of the return value and
* 340 is used.
* @see #setMaximumFractionDigits
*/
@@ -3758,8 +3748,8 @@ public class DecimalFormat extends NumberFormat {
/**
* Gets the minimum number of digits allowed in the fraction portion of a
* number.
- * For formatting numbers other than BigInteger and
- * BigDecimal objects, the lower of the return value and
+ * For formatting numbers other than {@code BigInteger} and
+ * {@code BigDecimal} objects, the lower of the return value and
* 340 is used.
* @see #setMinimumFractionDigits
*/
@@ -3775,7 +3765,7 @@ public class DecimalFormat extends NumberFormat {
* {@link DecimalFormatSymbols#getCurrency DecimalFormatSymbols.getCurrency}
* on this number format's symbols.
*
- * @return the currency used by this decimal format, or null
+ * @return the currency used by this decimal format, or {@code null}
* @since 1.4
*/
@Override
@@ -3792,7 +3782,7 @@ public class DecimalFormat extends NumberFormat {
* on this number format's symbols.
*
* @param currency the new currency to be used by this decimal format
- * @exception NullPointerException if currency is null
+ * @exception NullPointerException if {@code currency} is null
* @since 1.4
*/
@Override
@@ -3809,7 +3799,7 @@ public class DecimalFormat extends NumberFormat {
/**
* Gets the {@link java.math.RoundingMode} used in this DecimalFormat.
*
- * @return The RoundingMode used for this DecimalFormat.
+ * @return The {@code RoundingMode} used for this DecimalFormat.
* @see #setRoundingMode(RoundingMode)
* @since 1.6
*/
@@ -3821,9 +3811,9 @@ public class DecimalFormat extends NumberFormat {
/**
* Sets the {@link java.math.RoundingMode} used in this DecimalFormat.
*
- * @param roundingMode The RoundingMode to be used
+ * @param roundingMode The {@code RoundingMode} to be used
* @see #getRoundingMode()
- * @exception NullPointerException if roundingMode is null.
+ * @exception NullPointerException if {@code roundingMode} is null.
* @since 1.6
*/
@Override
@@ -3845,38 +3835,38 @@ public class DecimalFormat extends NumberFormat {
*
* Verify that the superclass's digit count fields correctly reflect
* the limits imposed on formatting numbers other than
- * BigInteger and BigDecimal objects. These
+ * {@code BigInteger} and {@code BigDecimal} objects. These
* limits are stored in the superclass for serialization compatibility
- * with older versions, while the limits for BigInteger and
- * BigDecimal objects are kept in this class.
+ * with older versions, while the limits for {@code BigInteger} and
+ * {@code BigDecimal} objects are kept in this class.
* If, in the superclass, the minimum or maximum integer digit count is
- * larger than DOUBLE_INTEGER_DIGITS or if the minimum or
+ * larger than {@code DOUBLE_INTEGER_DIGITS} or if the minimum or
* maximum fraction digit count is larger than
- * DOUBLE_FRACTION_DIGITS, then the stream data is invalid
- * and this method throws an InvalidObjectException.
+ * {@code DOUBLE_FRACTION_DIGITS}, then the stream data is invalid
+ * and this method throws an {@code InvalidObjectException}.
*
- * If serialVersionOnStream is less than 4, initialize
- * roundingMode to {@link java.math.RoundingMode#HALF_EVEN
+ * If {@code serialVersionOnStream} is less than 4, initialize
+ * {@code roundingMode} to {@link java.math.RoundingMode#HALF_EVEN
* RoundingMode.HALF_EVEN}. This field is new with version 4.
*
- * If serialVersionOnStream is less than 3, then call
+ * If {@code serialVersionOnStream} is less than 3, then call
* the setters for the minimum and maximum integer and fraction digits with
* the values of the corresponding superclass getters to initialize the
* fields in this class. The fields in this class are new with version 3.
*
- * If serialVersionOnStream is less than 1, indicating that
+ * If {@code serialVersionOnStream} is less than 1, indicating that
* the stream was written by JDK 1.1, initialize
- * useExponentialNotation
+ * {@code useExponentialNotation}
* to false, since it was not present in JDK 1.1.
*
- * Set serialVersionOnStream to the maximum allowed value so
+ * Set {@code serialVersionOnStream} to the maximum allowed value so
* that default serialization will work properly if this object is streamed
* out again.
*
*
* Stream versions older than 2 will not have the affix pattern variables
- * posPrefixPattern etc. As a result, they will be initialized
- * to null, which means the affix strings will be taken as
+ * {@code posPrefixPattern} etc. As a result, they will be initialized
+ * to {@code null}, which means the affix strings will be taken as
* literal values. This is exactly what we want, since that corresponds to
* the pre-version-2 behavior.
*/
@@ -3960,14 +3950,14 @@ public class DecimalFormat extends NumberFormat {
/**
* The prefix pattern for non-negative numbers. This variable corresponds
- * to positivePrefix.
+ * to {@code positivePrefix}.
*
- *
This pattern is expanded by the method expandAffix() to
- * positivePrefix to update the latter to reflect changes in
- * symbols. If this variable is null then
- * positivePrefix is taken as a literal value that does not
- * change when symbols changes. This variable is always
- * null for DecimalFormat objects older than
+ *
This pattern is expanded by the method {@code expandAffix()} to
+ * {@code positivePrefix} to update the latter to reflect changes in
+ * {@code symbols}. If this variable is {@code null} then
+ * {@code positivePrefix} is taken as a literal value that does not
+ * change when {@code symbols} changes. This variable is always
+ * {@code null} for {@code DecimalFormat} objects older than
* stream version 2 restored from stream.
*
* @serial
@@ -3977,8 +3967,8 @@ public class DecimalFormat extends NumberFormat {
/**
* The suffix pattern for non-negative numbers. This variable corresponds
- * to positiveSuffix. This variable is analogous to
- * posPrefixPattern; see that variable for further
+ * to {@code positiveSuffix}. This variable is analogous to
+ * {@code posPrefixPattern}; see that variable for further
* documentation.
*
* @serial
@@ -3988,8 +3978,8 @@ public class DecimalFormat extends NumberFormat {
/**
* The prefix pattern for negative numbers. This variable corresponds
- * to negativePrefix. This variable is analogous to
- * posPrefixPattern; see that variable for further
+ * to {@code negativePrefix}. This variable is analogous to
+ * {@code posPrefixPattern}; see that variable for further
* documentation.
*
* @serial
@@ -3999,8 +3989,8 @@ public class DecimalFormat extends NumberFormat {
/**
* The suffix pattern for negative numbers. This variable corresponds
- * to negativeSuffix. This variable is analogous to
- * posPrefixPattern; see that variable for further
+ * to {@code negativeSuffix}. This variable is analogous to
+ * {@code posPrefixPattern}; see that variable for further
* documentation.
*
* @serial
@@ -4019,7 +4009,7 @@ public class DecimalFormat extends NumberFormat {
/**
* The number of digits between grouping separators in the integer
* portion of a number. Must be greater than 0 if
- * NumberFormat.groupingUsed is true.
+ * {@code NumberFormat.groupingUsed} is true.
*
* @serial
* @see #getGroupingSize
@@ -4053,7 +4043,7 @@ public class DecimalFormat extends NumberFormat {
private transient boolean isCurrencyFormat = false;
/**
- * The DecimalFormatSymbols object used by this format.
+ * The {@code DecimalFormatSymbols} object used by this format.
* It contains the symbols used to format numbers, e.g. the grouping separator,
* decimal separator, and so on.
*
@@ -4074,28 +4064,28 @@ public class DecimalFormat extends NumberFormat {
/**
* FieldPositions describing the positive prefix String. This is
- * lazily created. Use getPositivePrefixFieldPositions
+ * lazily created. Use {@code getPositivePrefixFieldPositions}
* when needed.
*/
private transient FieldPosition[] positivePrefixFieldPositions;
/**
* FieldPositions describing the positive suffix String. This is
- * lazily created. Use getPositiveSuffixFieldPositions
+ * lazily created. Use {@code getPositiveSuffixFieldPositions}
* when needed.
*/
private transient FieldPosition[] positiveSuffixFieldPositions;
/**
* FieldPositions describing the negative prefix String. This is
- * lazily created. Use getNegativePrefixFieldPositions
+ * lazily created. Use {@code getNegativePrefixFieldPositions}
* when needed.
*/
private transient FieldPosition[] negativePrefixFieldPositions;
/**
* FieldPositions describing the negative suffix String. This is
- * lazily created. Use getNegativeSuffixFieldPositions
+ * lazily created. Use {@code getNegativeSuffixFieldPositions}
* when needed.
*/
private transient FieldPosition[] negativeSuffixFieldPositions;
@@ -4103,7 +4093,7 @@ public class DecimalFormat extends NumberFormat {
/**
* The minimum number of digits used to display the exponent when a number is
* formatted in exponential notation. This field is ignored if
- * useExponentialNotation is not true.
+ * {@code useExponentialNotation} is not true.
*
* @serial
* @since 1.2
@@ -4112,9 +4102,9 @@ public class DecimalFormat extends NumberFormat {
/**
* The maximum number of digits allowed in the integer portion of a
- * BigInteger or BigDecimal number.
- * maximumIntegerDigits must be greater than or equal to
- * minimumIntegerDigits.
+ * {@code BigInteger} or {@code BigDecimal} number.
+ * {@code maximumIntegerDigits} must be greater than or equal to
+ * {@code minimumIntegerDigits}.
*
* @serial
* @see #getMaximumIntegerDigits
@@ -4124,9 +4114,9 @@ public class DecimalFormat extends NumberFormat {
/**
* The minimum number of digits allowed in the integer portion of a
- * BigInteger or BigDecimal number.
- * minimumIntegerDigits must be less than or equal to
- * maximumIntegerDigits.
+ * {@code BigInteger} or {@code BigDecimal} number.
+ * {@code minimumIntegerDigits} must be less than or equal to
+ * {@code maximumIntegerDigits}.
*
* @serial
* @see #getMinimumIntegerDigits
@@ -4136,9 +4126,9 @@ public class DecimalFormat extends NumberFormat {
/**
* The maximum number of digits allowed in the fractional portion of a
- * BigInteger or BigDecimal number.
- * maximumFractionDigits must be greater than or equal to
- * minimumFractionDigits.
+ * {@code BigInteger} or {@code BigDecimal} number.
+ * {@code maximumFractionDigits} must be greater than or equal to
+ * {@code minimumFractionDigits}.
*
* @serial
* @see #getMaximumFractionDigits
@@ -4148,9 +4138,9 @@ public class DecimalFormat extends NumberFormat {
/**
* The minimum number of digits allowed in the fractional portion of a
- * BigInteger or BigDecimal number.
- * minimumFractionDigits must be less than or equal to
- * maximumFractionDigits.
+ * {@code BigInteger} or {@code BigDecimal} number.
+ * {@code minimumFractionDigits} must be less than or equal to
+ * {@code maximumFractionDigits}.
*
* @serial
* @see #getMinimumFractionDigits
@@ -4247,19 +4237,19 @@ public class DecimalFormat extends NumberFormat {
*
* - 0 (default): versions before the Java 2 platform v1.2
*
- 1: version for 1.2, which includes the two new fields
- *
useExponentialNotation and
- * minExponentDigits.
+ * {@code useExponentialNotation} and
+ * {@code minExponentDigits}.
* - 2: version for 1.3 and later, which adds four new fields:
- *
posPrefixPattern, posSuffixPattern,
- * negPrefixPattern, and negSuffixPattern.
+ * {@code posPrefixPattern}, {@code posSuffixPattern},
+ * {@code negPrefixPattern}, and {@code negSuffixPattern}.
* - 3: version for 1.5 and later, which adds five new fields:
- *
maximumIntegerDigits,
- * minimumIntegerDigits,
- * maximumFractionDigits,
- * minimumFractionDigits, and
- * parseBigDecimal.
+ * {@code maximumIntegerDigits},
+ * {@code minimumIntegerDigits},
+ * {@code maximumFractionDigits},
+ * {@code minimumFractionDigits}, and
+ * {@code parseBigDecimal}.
* - 4: version for 1.6 and later, which adds one new field:
- *
roundingMode.
+ * {@code roundingMode}.
*
* @since 1.2
* @serial
diff --git a/src/java.base/share/classes/java/text/DecimalFormatSymbols.java b/src/java.base/share/classes/java/text/DecimalFormatSymbols.java
index acaf3bfbcf1..5937c2f8114 100644
--- a/src/java.base/share/classes/java/text/DecimalFormatSymbols.java
+++ b/src/java.base/share/classes/java/text/DecimalFormatSymbols.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1996, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1996, 2019, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -38,12 +38,14 @@
package java.text;
+import java.io.InvalidObjectException;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.Serializable;
import java.text.spi.DecimalFormatSymbolsProvider;
import java.util.Currency;
import java.util.Locale;
+import java.util.Objects;
import sun.util.locale.provider.CalendarDataUtility;
import sun.util.locale.provider.LocaleProviderAdapter;
import sun.util.locale.provider.LocaleServiceProviderPool;
@@ -51,11 +53,11 @@ import sun.util.locale.provider.ResourceBundleBasedAdapter;
/**
* This class represents the set of symbols (such as the decimal separator,
- * the grouping separator, and so on) needed by DecimalFormat
- * to format numbers. DecimalFormat creates for itself an instance of
- * DecimalFormatSymbols from its locale data. If you need to change any
- * of these symbols, you can get the DecimalFormatSymbols object from
- * your DecimalFormat and modify it.
+ * the grouping separator, and so on) needed by {@code DecimalFormat}
+ * to format numbers. {@code DecimalFormat} creates for itself an instance of
+ * {@code DecimalFormatSymbols} from its locale data. If you need to change any
+ * of these symbols, you can get the {@code DecimalFormatSymbols} object from
+ * your {@code DecimalFormat} and modify it.
*
* If the locale contains "rg" (region override)
* Unicode extension,
@@ -107,7 +109,7 @@ public class DecimalFormatSymbols implements Cloneable, Serializable {
* instead of the Latin numbering system.
*
* @param locale the desired locale
- * @exception NullPointerException if locale is null
+ * @exception NullPointerException if {@code locale} is null
*/
public DecimalFormatSymbols( Locale locale ) {
initialize( locale );
@@ -115,16 +117,16 @@ public class DecimalFormatSymbols implements Cloneable, Serializable {
/**
* Returns an array of all locales for which the
- * getInstance methods of this class can return
+ * {@code getInstance} methods of this class can return
* localized instances.
* The returned array represents the union of locales supported by the Java
* runtime and by installed
* {@link java.text.spi.DecimalFormatSymbolsProvider DecimalFormatSymbolsProvider}
- * implementations. It must contain at least a Locale
+ * implementations. It must contain at least a {@code Locale}
* instance equal to {@link java.util.Locale#US Locale.US}.
*
* @return an array of locales for which localized
- * DecimalFormatSymbols instances are available.
+ * {@code DecimalFormatSymbols} instances are available.
* @since 1.6
*/
public static Locale[] getAvailableLocales() {
@@ -134,8 +136,8 @@ public class DecimalFormatSymbols implements Cloneable, Serializable {
}
/**
- * Gets the DecimalFormatSymbols instance for the default
- * locale. This method provides access to DecimalFormatSymbols
+ * Gets the {@code DecimalFormatSymbols} instance for the default
+ * locale. This method provides access to {@code DecimalFormatSymbols}
* instances for locales supported by the Java runtime itself as well
* as for those supported by installed
* {@link java.text.spi.DecimalFormatSymbolsProvider
@@ -145,7 +147,7 @@ public class DecimalFormatSymbols implements Cloneable, Serializable {
* getInstance(Locale.getDefault(Locale.Category.FORMAT))}.
* @see java.util.Locale#getDefault(java.util.Locale.Category)
* @see java.util.Locale.Category#FORMAT
- * @return a DecimalFormatSymbols instance.
+ * @return a {@code DecimalFormatSymbols} instance.
* @since 1.6
*/
public static final DecimalFormatSymbols getInstance() {
@@ -153,8 +155,8 @@ public class DecimalFormatSymbols implements Cloneable, Serializable {
}
/**
- * Gets the DecimalFormatSymbols instance for the specified
- * locale. This method provides access to DecimalFormatSymbols
+ * Gets the {@code DecimalFormatSymbols} instance for the specified
+ * locale. This method provides access to {@code DecimalFormatSymbols}
* instances for locales supported by the Java runtime itself as well
* as for those supported by installed
* {@link java.text.spi.DecimalFormatSymbolsProvider
@@ -169,8 +171,8 @@ public class DecimalFormatSymbols implements Cloneable, Serializable {
* instead of the Latin numbering system.
*
* @param locale the desired locale.
- * @return a DecimalFormatSymbols instance.
- * @exception NullPointerException if locale is null
+ * @return a {@code DecimalFormatSymbols} instance.
+ * @exception NullPointerException if {@code locale} is null
* @since 1.6
*/
public static final DecimalFormatSymbols getInstance(Locale locale) {
@@ -255,6 +257,41 @@ public class DecimalFormatSymbols implements Cloneable, Serializable {
*/
public void setPerMill(char perMill) {
this.perMill = perMill;
+ this.perMillText = Character.toString(perMill);
+ }
+
+ /**
+ * Gets the string used for per mille sign. Different for Arabic, etc.
+ *
+ * @return the string used for per mille sign
+ * @since 13
+ */
+ String getPerMillText() {
+ return perMillText;
+ }
+
+ /**
+ * Sets the string used for per mille sign. Different for Arabic, etc.
+ *
+ * Setting the {@code perMillText} affects the return value of
+ * {@link #getPerMill()}, in which the first non-format character of
+ * {@code perMillText} is returned.
+ *
+ * @param perMillText the string used for per mille sign
+ * @throws NullPointerException if {@code perMillText} is null
+ * @throws IllegalArgumentException if {@code perMillText} is an empty string
+ * @see #getPerMill()
+ * @see #getPerMillText()
+ * @since 13
+ */
+ void setPerMillText(String perMillText) {
+ Objects.requireNonNull(perMillText);
+ if (perMillText.isEmpty()) {
+ throw new IllegalArgumentException("Empty argument string");
+ }
+
+ this.perMillText = perMillText;
+ this.perMill = findNonFormatChar(perMillText, '\u2030');
}
/**
@@ -273,6 +310,41 @@ public class DecimalFormatSymbols implements Cloneable, Serializable {
*/
public void setPercent(char percent) {
this.percent = percent;
+ this.percentText = Character.toString(percent);
+ }
+
+ /**
+ * Gets the string used for percent sign. Different for Arabic, etc.
+ *
+ * @return the string used for percent sign
+ * @since 13
+ */
+ String getPercentText() {
+ return percentText;
+ }
+
+ /**
+ * Sets the string used for percent sign. Different for Arabic, etc.
+ *
+ * Setting the {@code percentText} affects the return value of
+ * {@link #getPercent()}, in which the first non-format character of
+ * {@code percentText} is returned.
+ *
+ * @param percentText the string used for percent sign
+ * @throws NullPointerException if {@code percentText} is null
+ * @throws IllegalArgumentException if {@code percentText} is an empty string
+ * @see #getPercent()
+ * @see #getPercentText()
+ * @since 13
+ */
+ void setPercentText(String percentText) {
+ Objects.requireNonNull(percentText);
+ if (percentText.isEmpty()) {
+ throw new IllegalArgumentException("Empty argument string");
+ }
+
+ this.percentText = percentText;
+ this.percent = findNonFormatChar(percentText, '%');
}
/**
@@ -373,6 +445,46 @@ public class DecimalFormatSymbols implements Cloneable, Serializable {
*/
public void setMinusSign(char minusSign) {
this.minusSign = minusSign;
+ this.minusSignText = Character.toString(minusSign);
+ }
+
+ /**
+ * Gets the string used to represent minus sign. If no explicit
+ * negative format is specified, one is formed by prefixing
+ * minusSignText to the positive format.
+ *
+ * @return the string representing minus sign
+ * @since 13
+ */
+ String getMinusSignText() {
+ return minusSignText;
+ }
+
+ /**
+ * Sets the string used to represent minus sign. If no explicit
+ * negative format is specified, one is formed by prefixing
+ * minusSignText to the positive format.
+ *
+ * Setting the {@code minusSignText} affects the return value of
+ * {@link #getMinusSign()}, in which the first non-format character of
+ * {@code minusSignText} is returned.
+ *
+ * @param minusSignText the character representing minus sign
+ * @throws NullPointerException if {@code minusSignText} is null
+ * @throws IllegalArgumentException if {@code minusSignText} is an
+ * empty string
+ * @see #getMinusSign()
+ * @see #getMinusSignText()
+ * @since 13
+ */
+ void setMinusSignText(String minusSignText) {
+ Objects.requireNonNull(minusSignText);
+ if (minusSignText.isEmpty()) {
+ throw new IllegalArgumentException("Empty argument string");
+ }
+
+ this.minusSignText = minusSignText;
+ this.minusSign = findNonFormatChar(minusSignText, '-');
}
/**
@@ -464,7 +576,7 @@ public class DecimalFormatSymbols implements Cloneable, Serializable {
* symbol attribute to the currency's ISO 4217 currency code.
*
* @param currency the new currency to be used
- * @exception NullPointerException if currency is null
+ * @exception NullPointerException if {@code currency} is null
* @since 1.4
* @see #setCurrencySymbol
* @see #setInternationalCurrencySymbol
@@ -540,7 +652,7 @@ public class DecimalFormatSymbols implements Cloneable, Serializable {
* Examples: "x10^" for 1.23x10^4, "E" for 1.23E4.
*
* @param exp the exponent separator string
- * @exception NullPointerException if exp is null
+ * @exception NullPointerException if {@code exp} is null
* @see #getExponentSeparator()
* @since 1.6
*/
@@ -583,9 +695,12 @@ public class DecimalFormatSymbols implements Cloneable, Serializable {
groupingSeparator == other.groupingSeparator &&
decimalSeparator == other.decimalSeparator &&
percent == other.percent &&
+ percentText.equals(other.percentText) &&
perMill == other.perMill &&
+ perMillText.equals(other.perMillText) &&
digit == other.digit &&
minusSign == other.minusSign &&
+ minusSignText.equals(other.minusSignText) &&
patternSeparator == other.patternSeparator &&
infinity.equals(other.infinity) &&
NaN.equals(other.NaN) &&
@@ -631,13 +746,16 @@ public class DecimalFormatSymbols implements Cloneable, Serializable {
decimalSeparator = numberElements[0].charAt(0);
groupingSeparator = numberElements[1].charAt(0);
patternSeparator = numberElements[2].charAt(0);
- percent = numberElements[3].charAt(0);
+ percentText = numberElements[3];
+ percent = findNonFormatChar(percentText, '%');
zeroDigit = numberElements[4].charAt(0); //different for Arabic,etc.
digit = numberElements[5].charAt(0);
- minusSign = numberElements[6].charAt(0);
+ minusSignText = numberElements[6];
+ minusSign = findNonFormatChar(minusSignText, '-');
exponential = numberElements[7].charAt(0);
exponentialSeparator = numberElements[7]; //string representation new since 1.6
- perMill = numberElements[8].charAt(0);
+ perMillText = numberElements[8];
+ perMill = findNonFormatChar(perMillText, '\u2030');
infinity = numberElements[9];
NaN = numberElements[10];
@@ -651,6 +769,16 @@ public class DecimalFormatSymbols implements Cloneable, Serializable {
monetarySeparator = decimalSeparator;
}
+ /**
+ * Obtains non-format single character from String
+ */
+ private char findNonFormatChar(String src, char defChar) {
+ return (char)src.chars()
+ .filter(c -> Character.getType(c) != Character.FORMAT)
+ .findFirst()
+ .orElse(defChar);
+ }
+
/**
* Lazy initialization for currency related fields
*/
@@ -704,18 +832,24 @@ public class DecimalFormatSymbols implements Cloneable, Serializable {
/**
* Reads the default serializable fields, provides default values for objects
* in older serial versions, and initializes non-serializable fields.
- * If serialVersionOnStream
- * is less than 1, initializes monetarySeparator to be
- * the same as decimalSeparator and exponential
+ * If {@code serialVersionOnStream}
+ * is less than 1, initializes {@code monetarySeparator} to be
+ * the same as {@code decimalSeparator} and {@code exponential}
* to be 'E'.
- * If serialVersionOnStream is less than 2,
- * initializes localeto the root locale, and initializes
- * If serialVersionOnStream is less than 3, it initializes
- * exponentialSeparator using exponential.
- * Sets serialVersionOnStream back to the maximum allowed value so that
+ * If {@code serialVersionOnStream} is less than 2,
+ * initializes {@code locale}to the root locale, and initializes
+ * If {@code serialVersionOnStream} is less than 3, it initializes
+ * {@code exponentialSeparator} using {@code exponential}.
+ * If {@code serialVersionOnStream} is less than 4, it initializes
+ * {@code perMillText}, {@code percentText}, and
+ * {@code minusSignText} using {@code perMill}, {@code percent}, and
+ * {@code minusSign} respectively.
+ * Sets {@code serialVersionOnStream} back to the maximum allowed value so that
* default serialization will work properly if this object is streamed out again.
* Initializes the currency from the intlCurrencySymbol field.
*
+ * @throws InvalidObjectException if {@code char} and {@code String}
+ * representations of either percent, per mille, and/or minus sign disagree.
* @since 1.1.6
*/
private void readObject(ObjectInputStream stream)
@@ -735,6 +869,23 @@ public class DecimalFormatSymbols implements Cloneable, Serializable {
// didn't have exponentialSeparator. Create one using exponential
exponentialSeparator = Character.toString(exponential);
}
+ if (serialVersionOnStream < 4) {
+ // didn't have perMillText, percentText, and minusSignText.
+ // Create one using corresponding char variations.
+ perMillText = Character.toString(perMill);
+ percentText = Character.toString(percent);
+ minusSignText = Character.toString(minusSign);
+ } else {
+ // Check whether char and text fields agree
+ if (findNonFormatChar(perMillText, '\uFFFF') != perMill ||
+ findNonFormatChar(percentText, '\uFFFF') != percent ||
+ findNonFormatChar(minusSignText, '\uFFFF') != minusSign) {
+ throw new InvalidObjectException(
+ "'char' and 'String' representations of either percent, " +
+ "per mille, and/or minus sign disagree.");
+ }
+ }
+
serialVersionOnStream = currentSerialVersion;
if (intlCurrencySymbol != null) {
@@ -862,8 +1013,8 @@ public class DecimalFormatSymbols implements Cloneable, Serializable {
* The string used to separate the mantissa from the exponent.
* Examples: "x10^" for 1.23x10^4, "E" for 1.23E4.
*
- * If both exponential and exponentialSeparator
- * exist, this exponentialSeparator has the precedence.
+ * If both {@code exponential} and {@code exponentialSeparator}
+ * exist, this {@code exponentialSeparator} has the precedence.
*
* @serial
* @since 1.6
@@ -878,6 +1029,39 @@ public class DecimalFormatSymbols implements Cloneable, Serializable {
*/
private Locale locale;
+ /**
+ * String representation of per mille sign, which may include
+ * formatting characters, such as BiDi control characters.
+ * The first non-format character of this string is the same as
+ * {@code perMill}.
+ *
+ * @serial
+ * @since 13
+ */
+ private String perMillText;
+
+ /**
+ * String representation of percent sign, which may include
+ * formatting characters, such as BiDi control characters.
+ * The first non-format character of this string is the same as
+ * {@code percent}.
+ *
+ * @serial
+ * @since 13
+ */
+ private String percentText;
+
+ /**
+ * String representation of minus sign, which may include
+ * formatting characters, such as BiDi control characters.
+ * The first non-format character of this string is the same as
+ * {@code minusSign}.
+ *
+ * @serial
+ * @since 13
+ */
+ private String minusSignText;
+
// currency; only the ISO code is serialized.
private transient Currency currency;
private transient volatile boolean currencyInitialized;
@@ -891,23 +1075,28 @@ public class DecimalFormatSymbols implements Cloneable, Serializable {
// monetarySeparator and exponential.
// - 2 for version from J2SE 1.4, which includes locale field.
// - 3 for version from J2SE 1.6, which includes exponentialSeparator field.
- private static final int currentSerialVersion = 3;
+ // - 4 for version from Java SE 13, which includes perMillText, percentText,
+ // and minusSignText field.
+ private static final int currentSerialVersion = 4;
/**
- * Describes the version of DecimalFormatSymbols present on the stream.
+ * Describes the version of {@code DecimalFormatSymbols} present on the stream.
* Possible values are:
*
* - 0 (or uninitialized): versions prior to JDK 1.1.6.
*
*
- 1: Versions written by JDK 1.1.6 or later, which include
- * two new fields:
monetarySeparator and exponential.
+ * two new fields: {@code monetarySeparator} and {@code exponential}.
* - 2: Versions written by J2SE 1.4 or later, which include a
- * new
locale field.
+ * new {@code locale} field.
* - 3: Versions written by J2SE 1.6 or later, which include a
- * new
exponentialSeparator field.
+ * new {@code exponentialSeparator} field.
+ * - 4: Versions written by Java SE 13 or later, which include
+ * new {@code perMillText}, {@code percentText}, and
+ * {@code minusSignText} field.
*
- * When streaming out a DecimalFormatSymbols, the most recent format
- * (corresponding to the highest allowable serialVersionOnStream)
+ * When streaming out a {@code DecimalFormatSymbols}, the most recent format
+ * (corresponding to the highest allowable {@code serialVersionOnStream})
* is always written.
*
* @serial
diff --git a/src/java.base/share/classes/java/time/chrono/JapaneseChronology.java b/src/java.base/share/classes/java/time/chrono/JapaneseChronology.java
index ed2d9172a07..92dcc984f26 100644
--- a/src/java.base/share/classes/java/time/chrono/JapaneseChronology.java
+++ b/src/java.base/share/classes/java/time/chrono/JapaneseChronology.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2012, 2018, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2019, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -363,9 +363,8 @@ public final class JapaneseChronology extends AbstractChronology implements Seri
/**
* Returns the calendar system era object from the given numeric value.
*
- * See the description of each Era for the numeric values of:
- * {@link JapaneseEra#HEISEI}, {@link JapaneseEra#SHOWA},{@link JapaneseEra#TAISHO},
- * {@link JapaneseEra#MEIJI}), only Meiji and later eras are supported.
+ * The numeric values supported by this method are the same as the
+ * numeric values supported by {@link JapaneseEra#of(int)}.
*
* @param eraValue the era value
* @return the Japanese {@code Era} for the given numeric era value
diff --git a/src/java.base/share/classes/java/time/chrono/JapaneseEra.java b/src/java.base/share/classes/java/time/chrono/JapaneseEra.java
index e998a4da6f4..226e4ebf010 100644
--- a/src/java.base/share/classes/java/time/chrono/JapaneseEra.java
+++ b/src/java.base/share/classes/java/time/chrono/JapaneseEra.java
@@ -151,14 +151,15 @@ public final class JapaneseEra
*/
public static final JapaneseEra HEISEI = new JapaneseEra(2, LocalDate.of(1989, 1, 8));
/**
- * The singleton instance for the 'NewEra' era (2019-05-01 - current)
- * which has the value 3.
+ * The singleton instance for the 'Reiwa' era (2019-05-01 - )
+ * which has the value 3. The end date of this era is not specified, unless
+ * the Japanese Government defines it.
*/
- private static final JapaneseEra NEWERA = new JapaneseEra(3, LocalDate.of(2019, 5, 1));
+ public static final JapaneseEra REIWA = new JapaneseEra(3, LocalDate.of(2019, 5, 1));
// The number of predefined JapaneseEra constants.
// There may be a supplemental era defined by the property.
- private static final int N_ERA_CONSTANTS = NEWERA.getValue() + ERA_OFFSET;
+ private static final int N_ERA_CONSTANTS = REIWA.getValue() + ERA_OFFSET;
/**
* Serialization version.
@@ -176,7 +177,7 @@ public final class JapaneseEra
KNOWN_ERAS[1] = TAISHO;
KNOWN_ERAS[2] = SHOWA;
KNOWN_ERAS[3] = HEISEI;
- KNOWN_ERAS[4] = NEWERA;
+ KNOWN_ERAS[4] = REIWA;
for (int i = N_ERA_CONSTANTS; i < ERA_CONFIG.length; i++) {
CalendarDate date = ERA_CONFIG[i].getSinceDate();
LocalDate isoDate = LocalDate.of(date.getYear(), date.getMonth(), date.getDayOfMonth());
diff --git a/src/java.base/share/classes/java/util/JapaneseImperialCalendar.java b/src/java.base/share/classes/java/util/JapaneseImperialCalendar.java
index 623d74e56df..4a5d714687b 100644
--- a/src/java.base/share/classes/java/util/JapaneseImperialCalendar.java
+++ b/src/java.base/share/classes/java/util/JapaneseImperialCalendar.java
@@ -50,7 +50,7 @@ import sun.util.calendar.ZoneInfo;
* 2 Taisho 1912-07-30T00:00:00 local time
* 3 Showa 1926-12-25T00:00:00 local time
* 4 Heisei 1989-01-08T00:00:00 local time
- * 5 NewEra 2019-05-01T00:00:00 local time
+ * 5 Reiwa 2019-05-01T00:00:00 local time
* ------------------------------------------------------
* }
*
@@ -129,9 +129,9 @@ class JapaneseImperialCalendar extends Calendar {
public static final int HEISEI = 4;
/**
- * The ERA constant designating the NewEra era.
+ * The ERA constant designating the Reiwa era.
*/
- private static final int NEWERA = 5;
+ private static final int REIWA = 5;
private static final int EPOCH_OFFSET = 719163; // Fixed date of January 1, 1970 (Gregorian)
@@ -1761,12 +1761,12 @@ class JapaneseImperialCalendar extends Calendar {
}
} else if (transitionYear) {
if (jdate.getYear() == 1) {
- // As of NewEra (since Meiji) there's no case
+ // As of Reiwa (since Meiji) there's no case
// that there are multiple transitions in a
// year. Historically there was such
// case. There might be such case again in the
// future.
- if (era > NEWERA) {
+ if (era > REIWA) {
CalendarDate pd = eras[era - 1].getSinceDate();
if (normalizedYear == pd.getYear()) {
d.setMonth(pd.getMonth()).setDayOfMonth(pd.getDayOfMonth());
diff --git a/src/java.base/share/classes/java/util/jar/Attributes.java b/src/java.base/share/classes/java/util/jar/Attributes.java
index 69d56814824..880942185c3 100644
--- a/src/java.base/share/classes/java/util/jar/Attributes.java
+++ b/src/java.base/share/classes/java/util/jar/Attributes.java
@@ -34,6 +34,8 @@ import java.util.Map;
import java.util.Objects;
import java.util.Set;
+import jdk.internal.misc.VM;
+import jdk.internal.vm.annotation.Stable;
import sun.util.logging.PlatformLogger;
import static java.nio.charset.StandardCharsets.UTF_8;
@@ -454,7 +456,7 @@ public class Attributes implements Map