(Note that this version is often presented as "MSVC 14.28", and reported
by cl.exe as 19.28.) Older versions will not be accepted by
configure and will not work. The maximum accepted version
-of Visual Studio is 2022.
+of Visual Studio is 2026.
If you have multiple versions of Visual Studio installed,
configure will by default pick the latest. You can request
a specific version to be used by setting
diff --git a/doc/building.md b/doc/building.md
index addc74aae516..45104bb499f0 100644
--- a/doc/building.md
+++ b/doc/building.md
@@ -389,7 +389,7 @@ available for this update.
The minimum accepted version is Visual Studio 2019 version 16.8. (Note that this
version is often presented as "MSVC 14.28", and reported by cl.exe as 19.28.)
Older versions will not be accepted by `configure` and will not work. The
-maximum accepted version of Visual Studio is 2022.
+maximum accepted version of Visual Studio is 2026.
If you have multiple versions of Visual Studio installed, `configure` will by
default pick the latest. You can request a specific version to be used by
diff --git a/make/Global.gmk b/make/Global.gmk
index e5e76b475b94..fae21f0b4280 100644
--- a/make/Global.gmk
+++ b/make/Global.gmk
@@ -103,6 +103,7 @@ help:
$(info $(_) # method is 'auto', 'ignore' or 'fail' (default))
$(info $(_) TEST="test1 ..." # Use the given test descriptor(s) for testing, e.g.)
$(info $(_) # make test TEST="jdk_lang gtest:all")
+ $(info $(_) TEST_DEPS="dependency1 ..." # Specify additional dependencies for running tests, e.g docs-jdk)
$(info $(_) JTREG="OPT1=x;OPT2=y" # Control the JTREG test harness, use 'help' to list)
$(info $(_) GTEST="OPT1=x;OPT2=y" # Control the GTEST test harness, use 'help' to list)
$(info $(_) MICRO="OPT1=x;OPT2=y" # Control the MICRO test harness, use 'help' to list)
diff --git a/make/InitSupport.gmk b/make/InitSupport.gmk
index 31c80e2f7267..e38f9e105475 100644
--- a/make/InitSupport.gmk
+++ b/make/InitSupport.gmk
@@ -50,7 +50,7 @@ ifeq ($(HAS_SPEC),)
# Make control variables, handled by Init.gmk
INIT_CONTROL_VARIABLES += LOG CONF CONF_NAME SPEC JOBS TEST_JOBS CONF_CHECK \
- COMPARE_BUILD JTREG GTEST MICRO TEST_OPTS TEST_VM_OPTS
+ COMPARE_BUILD JTREG GTEST MICRO TEST_OPTS TEST_VM_OPTS TEST_DEPS
# All known make control variables
MAKE_CONTROL_VARIABLES := $(INIT_CONTROL_VARIABLES) TEST JDK_FILTER SPEC_FILTER
diff --git a/make/Main.gmk b/make/Main.gmk
index 62d43c689e49..722a6d854e89 100644
--- a/make/Main.gmk
+++ b/make/Main.gmk
@@ -1,5 +1,5 @@
#
-# Copyright (c) 2011, 2023, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2011, 2024, Oracle and/or its affiliates. All rights reserved.
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
#
# This code is free software; you can redistribute it and/or modify it
@@ -774,13 +774,13 @@ $(eval $(call SetupTarget, build-microbenchmark, \
$(eval $(call SetupTarget, test, \
MAKEFILE := RunTests, \
ARGS := TEST="$(TEST)", \
- DEPS := jdk-image test-image, \
+ DEPS := jdk-image test-image $(TEST_DEPS), \
))
$(eval $(call SetupTarget, exploded-test, \
MAKEFILE := RunTests, \
ARGS := TEST="$(TEST)" JDK_IMAGE_DIR=$(JDK_OUTPUTDIR), \
- DEPS := exploded-image test-image, \
+ DEPS := exploded-image test-image $(TEST_DEPS), \
))
ifeq ($(JCOV_ENABLED), true)
@@ -1061,8 +1061,8 @@ else
test-make-compile-commands: compile-commands
# Declare dependency for all generated test targets
- $(foreach t, $(filter-out test-make%, $(ALL_TEST_TARGETS)), $(eval $t: jdk-image test-image))
- $(foreach t, $(ALL_EXPLODED_TEST_TARGETS), $(eval $t: exploded-image test-image))
+ $(foreach t, $(filter-out test-make%, $(ALL_TEST_TARGETS)), $(eval $t: jdk-image test-image $(TEST_DEPS)))
+ $(foreach t, $(ALL_EXPLODED_TEST_TARGETS), $(eval $t: exploded-image test-image $(TEST_DEPS)))
interim-image: $(INTERIM_JMOD_TARGETS)
@@ -1293,9 +1293,13 @@ test-hotspot-jtreg-native: test-hotspot_native_sanity
test-hotspot-gtest: exploded-test-gtest
test-jdk-jtreg-native: test-jdk_native_sanity
+# Set dependencies for doc tests
+$(eval $(call AddTestDependency, docs_all, docs-jdk))
+test-docs: test-docs_all
+
ALL_TARGETS += $(RUN_TEST_TARGETS) run-test exploded-run-test check \
test-hotspot-jtreg test-hotspot-jtreg-native test-hotspot-gtest \
- test-jdk-jtreg-native
+ test-jdk-jtreg-native test-docs
################################################################################
################################################################################
diff --git a/make/MainSupport.gmk b/make/MainSupport.gmk
index 34137c502d4a..aa0bf8f8ac8f 100644
--- a/make/MainSupport.gmk
+++ b/make/MainSupport.gmk
@@ -132,6 +132,15 @@ define CleanModule
$(call Clean-include, $1)
endef
+define AddTestDependency
+ test-$(strip $1): $2
+
+ exploded-test-$(strip $1): $2
+
+ ifneq ($(filter $(TEST), $1), )
+ TEST_DEPS += $2
+ endif
+endef
################################################################################
diff --git a/make/RunTests.gmk b/make/RunTests.gmk
index b490f9f77489..f61125f53315 100644
--- a/make/RunTests.gmk
+++ b/make/RunTests.gmk
@@ -263,6 +263,7 @@ jaxp_JTREG_PROBLEM_LIST += $(TOPDIR)/test/jaxp/ProblemList.txt
langtools_JTREG_PROBLEM_LIST += $(TOPDIR)/test/langtools/ProblemList.txt
hotspot_JTREG_PROBLEM_LIST += $(TOPDIR)/test/hotspot/jtreg/ProblemList.txt
lib-test_JTREG_PROBLEM_LIST += $(TOPDIR)/test/lib-test/ProblemList.txt
+docs_JTREG_PROBLEM_LIST += $(TOPDIR)/test/docs/ProblemList.txt
################################################################################
# Parse test selection
@@ -866,6 +867,8 @@ define SetupRunJtregTestBody
$1_JTREG_BASIC_OPTIONS += -e:TEST_IMAGE_DIR=$(TEST_IMAGE_DIR)
+ $1_JTREG_BASIC_OPTIONS += -e:DOCS_JDK_IMAGE_DIR=$$(DOCS_JDK_IMAGE_DIR)
+
ifneq ($$(JTREG_FAILURE_HANDLER_OPTIONS), )
$1_JTREG_LAUNCHER_OPTIONS += -Djava.library.path="$(JTREG_FAILURE_HANDLER_DIR)"
endif
diff --git a/make/autoconf/basic_tools.m4 b/make/autoconf/basic_tools.m4
index 3ad7d778be15..caef5f73ca8e 100644
--- a/make/autoconf/basic_tools.m4
+++ b/make/autoconf/basic_tools.m4
@@ -148,7 +148,7 @@ AC_DEFUN([BASIC_CHECK_MAKE_VERSION],
if test "x$OPENJDK_BUILD_OS_ENV" = "xwindows.cygwin"; then
MAKE_EXPECTED_ENV='cygwin'
elif test "x$OPENJDK_BUILD_OS_ENV" = "xwindows.msys2"; then
- MAKE_EXPECTED_ENV='msys'
+ MAKE_EXPECTED_ENV='cygwin|msys'
elif test "x$OPENJDK_BUILD_OS_ENV" = "xwindows.wsl1" || test "x$OPENJDK_BUILD_OS_ENV" = "xwindows.wsl2"; then
if test "x$OPENJDK_BUILD_CPU" = "xaarch64"; then
MAKE_EXPECTED_ENV='aarch64-.*-linux-gnu'
@@ -159,7 +159,7 @@ AC_DEFUN([BASIC_CHECK_MAKE_VERSION],
AC_MSG_ERROR([Unknown Windows environment])
fi
MAKE_BUILT_FOR=`$MAKE_CANDIDATE --version | $GREP -i 'built for'`
- IS_MAKE_CORRECT_ENV=`$ECHO $MAKE_BUILT_FOR | $GREP $MAKE_EXPECTED_ENV`
+ IS_MAKE_CORRECT_ENV=`$ECHO $MAKE_BUILT_FOR | $GREP -E $MAKE_EXPECTED_ENV`
else
# Not relevant for non-Windows
IS_MAKE_CORRECT_ENV=true
diff --git a/make/autoconf/toolchain.m4 b/make/autoconf/toolchain.m4
index 069ced05f329..a2b576ac1ab3 100644
--- a/make/autoconf/toolchain.m4
+++ b/make/autoconf/toolchain.m4
@@ -380,7 +380,7 @@ AC_DEFUN_ONCE([TOOLCHAIN_POST_DETECTION],
[
# Restore old path, except for the microsoft toolchain, which requires the
# toolchain path to remain in place. Otherwise the compiler will not work in
- # some siutations in later configure checks.
+ # some situations in later configure checks.
if test "x$TOOLCHAIN_TYPE" != "xmicrosoft"; then
PATH="$OLD_PATH"
fi
@@ -389,10 +389,6 @@ AC_DEFUN_ONCE([TOOLCHAIN_POST_DETECTION],
# This is necessary since AC_PROG_CC defaults CFLAGS to "-g -O2"
CFLAGS="$ORG_CFLAGS"
CXXFLAGS="$ORG_CXXFLAGS"
-
- # filter out some unwanted additions autoconf may add to CXX; we saw this on macOS with autoconf 2.72
- UTIL_GET_NON_MATCHING_VALUES(cxx_filtered, $CXX, -std=c++11 -std=gnu++11)
- CXX="$cxx_filtered"
])
# Check if a compiler is of the toolchain type we expect, and save the version
diff --git a/make/autoconf/toolchain_microsoft.m4 b/make/autoconf/toolchain_microsoft.m4
index 51bba4871925..13e93f270739 100644
--- a/make/autoconf/toolchain_microsoft.m4
+++ b/make/autoconf/toolchain_microsoft.m4
@@ -25,7 +25,7 @@
################################################################################
# The order of these defines the priority by which we try to find them.
-VALID_VS_VERSIONS="2022 2019"
+VALID_VS_VERSIONS="2022 2019 2026"
VS_DESCRIPTION_2019="Microsoft Visual Studio 2019"
VS_VERSION_INTERNAL_2019=142
@@ -57,6 +57,21 @@ VS_SDK_PLATFORM_NAME_2022=
VS_SUPPORTED_2022=true
VS_TOOLSET_SUPPORTED_2022=true
+VS_DESCRIPTION_2026="Microsoft Visual Studio 2026"
+VS_VERSION_INTERNAL_2026=145
+VS_MSVCR_2026=vcruntime140.dll
+VS_VCRUNTIME_1_2026=vcruntime140_1.dll
+VS_MSVCP_2026=msvcp140.dll
+VS_ENVVAR_2026="VS180COMNTOOLS"
+VS_USE_UCRT_2026="true"
+VS_VS_INSTALLDIR_2026="Microsoft Visual Studio/18"
+VS_EDITIONS_2026="BuildTools Community Professional Enterprise"
+VS_SDK_INSTALLDIR_2026=
+VS_VS_PLATFORM_NAME_2026="v145"
+VS_SDK_PLATFORM_NAME_2026=
+VS_SUPPORTED_2026=true
+VS_TOOLSET_SUPPORTED_2026=true
+
################################################################################
AC_DEFUN([TOOLCHAIN_CHECK_POSSIBLE_VISUAL_STUDIO_ROOT],
diff --git a/make/autoconf/util.m4 b/make/autoconf/util.m4
index 76426005f81d..c87411c8ab3f 100644
--- a/make/autoconf/util.m4
+++ b/make/autoconf/util.m4
@@ -26,6 +26,70 @@
m4_include([util_paths.m4])
###############################################################################
+# Overwrite the existing version of AC_PROG_CC with our own custom variant.
+# Unlike the regular AC_PROG_CC, the compiler list must always be passed.
+AC_DEFUN([AC_PROG_CC],
+[
+ AC_LANG_PUSH(C)
+ AC_ARG_VAR([CC], [C compiler command])
+ AC_ARG_VAR([CFLAGS], [C compiler flags])
+
+ _AC_ARG_VAR_LDFLAGS()
+ _AC_ARG_VAR_LIBS()
+ _AC_ARG_VAR_CPPFLAGS()
+
+ AC_CHECK_TOOLS(CC, [$1])
+
+ test -z "$CC" && AC_MSG_FAILURE([no acceptable C compiler found in \$PATH])
+
+ # Provide some information about the compiler.
+ _AS_ECHO_LOG([checking for _AC_LANG compiler version])
+ set X $ac_compile
+ ac_compiler=$[2]
+ for ac_option in --version -v -V -qversion -version; do
+ _AC_DO_LIMIT([$ac_compiler $ac_option >&AS_MESSAGE_LOG_FD])
+ done
+
+ m4_expand_once([_AC_COMPILER_EXEEXT])
+ m4_expand_once([_AC_COMPILER_OBJEXT])
+
+ _AC_PROG_CC_G
+
+ AC_LANG_POP(C)
+])
+
+###############################################################################
+# Overwrite the existing version of AC_PROG_CXX with our own custom variant.
+# Unlike the regular AC_PROG_CXX, the compiler list must always be passed.
+AC_DEFUN([AC_PROG_CXX],
+[
+ AC_LANG_PUSH(C++)
+ AC_ARG_VAR([CXX], [C++ compiler command])
+ AC_ARG_VAR([CXXFLAGS], [C++ compiler flags])
+
+ _AC_ARG_VAR_LDFLAGS()
+ _AC_ARG_VAR_LIBS()
+ _AC_ARG_VAR_CPPFLAGS()
+
+ AC_CHECK_TOOLS(CXX, [$1])
+
+ # Provide some information about the compiler.
+ _AS_ECHO_LOG([checking for _AC_LANG compiler version])
+ set X $ac_compile
+ ac_compiler=$[2]
+ for ac_option in --version -v -V -qversion; do
+ _AC_DO_LIMIT([$ac_compiler $ac_option >&AS_MESSAGE_LOG_FD])
+ done
+
+ m4_expand_once([_AC_COMPILER_EXEEXT])
+ m4_expand_once([_AC_COMPILER_OBJEXT])
+
+ _AC_PROG_CXX_G
+
+ AC_LANG_POP(C++)
+])
+
+################################################################################
# Create a function/macro that takes a series of named arguments. The call is
# similar to AC_DEFUN, but the setup of the function looks like this:
# UTIL_DEFUN_NAMED([MYFUNC], [FOO *BAR], [$@], [
diff --git a/make/common/FindTests.gmk b/make/common/FindTests.gmk
index b12630349c0d..5bdce82efa3c 100644
--- a/make/common/FindTests.gmk
+++ b/make/common/FindTests.gmk
@@ -1,5 +1,5 @@
#
-# Copyright (c) 2017, 2019, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2017, 2024, Oracle and/or its affiliates. All rights reserved.
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
#
# This code is free software; you can redistribute it and/or modify it
@@ -43,7 +43,7 @@ $(eval $(call IncludeCustomExtension, common/FindTests.gmk))
TEST_BASEDIRS += $(TOPDIR)/test $(TOPDIR)
# JTREG_TESTROOTS might have been set by a custom extension
-JTREG_TESTROOTS += $(addprefix $(TOPDIR)/test/, hotspot/jtreg jdk langtools jaxp lib-test)
+JTREG_TESTROOTS += $(addprefix $(TOPDIR)/test/, hotspot/jtreg jdk langtools jaxp lib-test docs)
# Extract the names of the Jtreg group files from the TEST.ROOT files. The
# TEST.ROOT files being properties files can be interpreted as makefiles so
diff --git a/make/conf/github-actions.conf b/make/conf/github-actions.conf
index 0157f5119ce0..b35533eb1ce6 100644
--- a/make/conf/github-actions.conf
+++ b/make/conf/github-actions.conf
@@ -29,17 +29,17 @@ GTEST_VERSION=1.14.0
JTREG_VERSION=7.5.2+1
LINUX_X64_BOOT_JDK_EXT=tar.gz
-LINUX_X64_BOOT_JDK_URL=https://github.com/adoptium/temurin21-binaries/releases/download/jdk-21.0.6%2B7/OpenJDK21U-jdk_x64_linux_hotspot_21.0.6_7.tar.gz
-LINUX_X64_BOOT_JDK_SHA256=a2650fba422283fbed20d936ce5d2a52906a5414ec17b2f7676dddb87201dbae
+LINUX_X64_BOOT_JDK_URL=https://github.com/adoptium/temurin21-binaries/releases/download/jdk-21.0.11%2B10/OpenJDK21U-jdk_x64_linux_hotspot_21.0.11_10.tar.gz
+LINUX_X64_BOOT_JDK_SHA256=4b2220e232a97997b436ca6ab15cbf70171ecff52958a46159dfa5a8c44ca4de
MACOS_AARCH64_BOOT_JDK_EXT=tar.gz
-MACOS_AARCH64_BOOT_JDK_URL=https://github.com/adoptium/temurin21-binaries/releases/download/jdk-21.0.6%2B7/OpenJDK21U-jdk_aarch64_mac_hotspot_21.0.6_7.tar.gz
-MACOS_AARCH64_BOOT_JDK_SHA256=4ef4083919126a3d93e603284b405c7493905497485a92b375f5d6c3e8f7e8f2
+MACOS_AARCH64_BOOT_JDK_URL=https://github.com/adoptium/temurin21-binaries/releases/download/jdk-21.0.11%2B10/OpenJDK21U-jdk_aarch64_mac_hotspot_21.0.11_10.tar.gz
+MACOS_AARCH64_BOOT_JDK_SHA256=6ebcf221c9b41507b14c098e93c6ead6440b8d9bd154f8ec666c4c73abbdb201
MACOS_X64_BOOT_JDK_EXT=tar.gz
-MACOS_X64_BOOT_JDK_URL=https://github.com/adoptium/temurin21-binaries/releases/download/jdk-21.0.6%2B7/OpenJDK21U-jdk_x64_mac_hotspot_21.0.6_7.tar.gz
-MACOS_X64_BOOT_JDK_SHA256=7aacfc400078ad65b7c7de3ec75ff74bf5c2077d6740b350f85ae10be4f71e76
+MACOS_X64_BOOT_JDK_URL=https://github.com/adoptium/temurin21-binaries/releases/download/jdk-21.0.11%2B10/OpenJDK21U-jdk_x64_mac_hotspot_21.0.11_10.tar.gz
+MACOS_X64_BOOT_JDK_SHA256=34180eb03e6d207c388cce3da668f6cc7cd7508c185c24782fadac2c9c0e66f9
WINDOWS_X64_BOOT_JDK_EXT=zip
-WINDOWS_X64_BOOT_JDK_URL=https://github.com/adoptium/temurin21-binaries/releases/download/jdk-21.0.6%2B7/OpenJDK21U-jdk_x64_windows_hotspot_21.0.6_7.zip
-WINDOWS_X64_BOOT_JDK_SHA256=897c8eebb0f85a99ccecbd482ebae9a45d88c19d6077054f6529ebab49b6d259
+WINDOWS_X64_BOOT_JDK_URL=https://github.com/adoptium/temurin21-binaries/releases/download/jdk-21.0.11%2B10/OpenJDK21U-jdk_x64_windows_hotspot_21.0.11_10.zip
+WINDOWS_X64_BOOT_JDK_SHA256=d3625e7cadf23787ea540229544b6e2ab494b3b54da1801879e583e1dfee0a64
diff --git a/make/conf/jib-profiles.js b/make/conf/jib-profiles.js
index 220897030d59..a3dd255b0f15 100644
--- a/make/conf/jib-profiles.js
+++ b/make/conf/jib-profiles.js
@@ -952,7 +952,7 @@ var getJibProfilesProfiles = function (input, common, data) {
// Profiles used to run tests using Jib for internal dependencies.
var testedProfile = input.testedProfile;
- if (testedProfile == null) {
+ if (testedProfile == null || testedProfile == "docs") {
testedProfile = input.build_os + "-" + input.build_cpu;
}
var testedProfileJdk = testedProfile + ".jdk";
@@ -994,25 +994,38 @@ var getJibProfilesProfiles = function (input, common, data) {
testOnlyProfilesPrebuilt["run-test-prebuilt"]["dependencies"].push(testedProfile + ".jdk_symbols");
}
+ var testOnlyProfilesPrebuiltDocs = {
+ "run-test-prebuilt-docs": clone(testOnlyProfilesPrebuilt["run-test-prebuilt"])
+ };
+
+ testOnlyProfilesPrebuiltDocs["run-test-prebuilt-docs"].dependencies.push("docs.doc_api_spec", "tidy");
+ testOnlyProfilesPrebuiltDocs["run-test-prebuilt-docs"].environment["DOCS_JDK_IMAGE_DIR"]
+ = input.get("docs.doc_api_spec", "install_path");
+ testOnlyProfilesPrebuiltDocs["run-test-prebuilt-docs"].environment["TIDY"]
+ = input.get("tidy", "home_path") + "/bin/tidy";
+ testOnlyProfilesPrebuiltDocs["run-test-prebuilt-docs"].labels = "test-docs";
+
// If actually running the run-test-prebuilt profile, verify that the input
// variable is valid and if so, add the appropriate target_* values from
// the tested profile. Use testImageProfile value as backup.
- if (input.profile == "run-test-prebuilt") {
+ if (input.profile == "run-test-prebuilt" || input.profile == "run-test-prebuilt-docs") {
if (profiles[testedProfile] == null && profiles[testImageProfile] == null) {
error("testedProfile is not defined: " + testedProfile + " " + testImageProfile);
}
}
- if (profiles[testedProfile] != null) {
- testOnlyProfilesPrebuilt["run-test-prebuilt"]["target_os"]
- = profiles[testedProfile]["target_os"];
- testOnlyProfilesPrebuilt["run-test-prebuilt"]["target_cpu"]
- = profiles[testedProfile]["target_cpu"];
- } else if (profiles[testImageProfile] != null) {
- testOnlyProfilesPrebuilt["run-test-prebuilt"]["target_os"]
- = profiles[testImageProfile]["target_os"];
- testOnlyProfilesPrebuilt["run-test-prebuilt"]["target_cpu"]
- = profiles[testImageProfile]["target_cpu"];
+ function updateProfileTargets(profiles, testedProfile, testImageProfile, targetProfile, runTestProfile) {
+ var profileToCheck = profiles[testedProfile] || profiles[testImageProfile];
+
+ if (profileToCheck != null) {
+ targetProfile[runTestProfile]["target_os"] = profileToCheck["target_os"];
+ targetProfile[runTestProfile]["target_cpu"] = profileToCheck["target_cpu"];
+ }
}
+
+ updateProfileTargets(profiles, testedProfile, testImageProfile, testOnlyProfilesPrebuilt, "run-test-prebuilt");
+ updateProfileTargets(profiles, testedProfile, testImageProfile, testOnlyProfilesPrebuiltDocs, "run-test-prebuilt-docs");
+
+ profiles = concatObjects(profiles, testOnlyProfilesPrebuiltDocs);
profiles = concatObjects(profiles, testOnlyProfilesPrebuilt);
// On macosx add the devkit bin dir to the path in all the run-test profiles.
@@ -1062,6 +1075,8 @@ var getJibProfilesProfiles = function (input, common, data) {
}
profiles["run-test-prebuilt"] = concatObjects(profiles["run-test-prebuilt"],
runTestPrebuiltSrcFullExtra);
+ profiles["run-test-prebuilt-docs"] = concatObjects(profiles["run-test-prebuilt-docs"],
+ runTestPrebuiltSrcFullExtra);
}
// Generate the missing platform attributes
diff --git a/make/conf/version-numbers.conf b/make/conf/version-numbers.conf
index dfab158b4c89..aecbc27c216f 100644
--- a/make/conf/version-numbers.conf
+++ b/make/conf/version-numbers.conf
@@ -28,12 +28,12 @@
DEFAULT_VERSION_FEATURE=21
DEFAULT_VERSION_INTERIM=0
-DEFAULT_VERSION_UPDATE=11
+DEFAULT_VERSION_UPDATE=12
DEFAULT_VERSION_PATCH=0
DEFAULT_VERSION_EXTRA1=0
DEFAULT_VERSION_EXTRA2=0
DEFAULT_VERSION_EXTRA3=0
-DEFAULT_VERSION_DATE=2026-04-21
+DEFAULT_VERSION_DATE=2026-07-21
DEFAULT_VERSION_CLASSFILE_MAJOR=65 # "`$EXPR $DEFAULT_VERSION_FEATURE + 44`"
DEFAULT_VERSION_CLASSFILE_MINOR=0
DEFAULT_VERSION_DOCS_API_SINCE=11
diff --git a/src/hotspot/cpu/arm/arm_32.ad b/src/hotspot/cpu/arm/arm_32.ad
index affe5a816fca..dd9217d73a9c 100644
--- a/src/hotspot/cpu/arm/arm_32.ad
+++ b/src/hotspot/cpu/arm/arm_32.ad
@@ -62,22 +62,22 @@ register %{
// Integer/Long Registers
// ----------------------------
-reg_def R_R0 (SOC, SOC, Op_RegI, 0, R(0)->as_VMReg());
-reg_def R_R1 (SOC, SOC, Op_RegI, 1, R(1)->as_VMReg());
-reg_def R_R2 (SOC, SOC, Op_RegI, 2, R(2)->as_VMReg());
-reg_def R_R3 (SOC, SOC, Op_RegI, 3, R(3)->as_VMReg());
-reg_def R_R4 (SOC, SOE, Op_RegI, 4, R(4)->as_VMReg());
-reg_def R_R5 (SOC, SOE, Op_RegI, 5, R(5)->as_VMReg());
-reg_def R_R6 (SOC, SOE, Op_RegI, 6, R(6)->as_VMReg());
-reg_def R_R7 (SOC, SOE, Op_RegI, 7, R(7)->as_VMReg());
-reg_def R_R8 (SOC, SOE, Op_RegI, 8, R(8)->as_VMReg());
-reg_def R_R9 (SOC, SOE, Op_RegI, 9, R(9)->as_VMReg());
-reg_def R_R10(NS, SOE, Op_RegI, 10, R(10)->as_VMReg());
-reg_def R_R11(NS, SOE, Op_RegI, 11, R(11)->as_VMReg());
-reg_def R_R12(SOC, SOC, Op_RegI, 12, R(12)->as_VMReg());
-reg_def R_R13(NS, NS, Op_RegI, 13, R(13)->as_VMReg());
-reg_def R_R14(SOC, SOC, Op_RegI, 14, R(14)->as_VMReg());
-reg_def R_R15(NS, NS, Op_RegI, 15, R(15)->as_VMReg());
+reg_def R_R0 (SOC, SOC, Op_RegI, 0, as_Register(0)->as_VMReg());
+reg_def R_R1 (SOC, SOC, Op_RegI, 1, as_Register(1)->as_VMReg());
+reg_def R_R2 (SOC, SOC, Op_RegI, 2, as_Register(2)->as_VMReg());
+reg_def R_R3 (SOC, SOC, Op_RegI, 3, as_Register(3)->as_VMReg());
+reg_def R_R4 (SOC, SOE, Op_RegI, 4, as_Register(4)->as_VMReg());
+reg_def R_R5 (SOC, SOE, Op_RegI, 5, as_Register(5)->as_VMReg());
+reg_def R_R6 (SOC, SOE, Op_RegI, 6, as_Register(6)->as_VMReg());
+reg_def R_R7 (SOC, SOE, Op_RegI, 7, as_Register(7)->as_VMReg());
+reg_def R_R8 (SOC, SOE, Op_RegI, 8, as_Register(8)->as_VMReg());
+reg_def R_R9 (SOC, SOE, Op_RegI, 9, as_Register(9)->as_VMReg());
+reg_def R_R10(NS, SOE, Op_RegI, 10, as_Register(10)->as_VMReg());
+reg_def R_R11(NS, SOE, Op_RegI, 11, as_Register(11)->as_VMReg());
+reg_def R_R12(SOC, SOC, Op_RegI, 12, as_Register(12)->as_VMReg());
+reg_def R_R13(NS, NS, Op_RegI, 13, as_Register(13)->as_VMReg());
+reg_def R_R14(SOC, SOC, Op_RegI, 14, as_Register(14)->as_VMReg());
+reg_def R_R15(NS, NS, Op_RegI, 15, as_Register(15)->as_VMReg());
// ----------------------------
// Float/Double Registers
diff --git a/src/hotspot/cpu/arm/assembler_arm_32.hpp b/src/hotspot/cpu/arm/assembler_arm_32.hpp
index dd04ad1ab3a3..5972782233bb 100644
--- a/src/hotspot/cpu/arm/assembler_arm_32.hpp
+++ b/src/hotspot/cpu/arm/assembler_arm_32.hpp
@@ -114,7 +114,7 @@ class RegisterSet {
}
RegisterSet(Register first, Register last) {
- assert(first < last, "encoding constraint");
+ assert(first->encoding() < last->encoding(), "encoding constraint");
_encoding = (1 << (last->encoding() + 1)) - (1 << first->encoding());
}
diff --git a/src/hotspot/cpu/arm/c1_CodeStubs_arm.cpp b/src/hotspot/cpu/arm/c1_CodeStubs_arm.cpp
index 3d8dbc38071e..cc4043d3fffa 100644
--- a/src/hotspot/cpu/arm/c1_CodeStubs_arm.cpp
+++ b/src/hotspot/cpu/arm/c1_CodeStubs_arm.cpp
@@ -182,7 +182,7 @@ void MonitorEnterStub::emit_code(LIR_Assembler* ce) {
const Register lock_reg = _lock_reg->as_pointer_register();
ce->verify_reserved_argument_area_size(2);
- if (obj_reg < lock_reg) {
+ if (obj_reg->encoding() < lock_reg->encoding()) {
__ stmia(SP, RegisterSet(obj_reg) | RegisterSet(lock_reg));
} else {
__ str(obj_reg, Address(SP));
diff --git a/src/hotspot/cpu/arm/c1_LIRAssembler_arm.cpp b/src/hotspot/cpu/arm/c1_LIRAssembler_arm.cpp
index 45786898458b..dcac4271a643 100644
--- a/src/hotspot/cpu/arm/c1_LIRAssembler_arm.cpp
+++ b/src/hotspot/cpu/arm/c1_LIRAssembler_arm.cpp
@@ -152,8 +152,14 @@ void LIR_Assembler::osr_entry() {
int monitor_offset = (method()->max_locals() + 2 * (number_of_locks - 1)) * BytesPerWord;
for (int i = 0; i < number_of_locks; i++) {
int slot_offset = monitor_offset - (i * 2 * BytesPerWord);
- __ ldr(R1, Address(OSR_buf, slot_offset + 0*BytesPerWord));
- __ ldr(R2, Address(OSR_buf, slot_offset + 1*BytesPerWord));
+ if (slot_offset >= 4096 - BytesPerWord) {
+ __ add_slow(R2, OSR_buf, slot_offset);
+ __ ldr(R1, Address(R2, 0*BytesPerWord));
+ __ ldr(R2, Address(R2, 1*BytesPerWord));
+ } else {
+ __ ldr(R1, Address(OSR_buf, slot_offset + 0*BytesPerWord));
+ __ ldr(R2, Address(OSR_buf, slot_offset + 1*BytesPerWord));
+ }
__ str(R1, frame_map()->address_for_monitor_lock(i));
__ str(R2, frame_map()->address_for_monitor_object(i));
}
@@ -2653,11 +2659,11 @@ void LIR_Assembler::volatile_move_op(LIR_Opr src, LIR_Opr dest, BasicType type,
const Register src_hi = src->as_register_hi();
assert(addr->index()->is_illegal() && addr->disp() == 0, "The address is simple already");
- if (src_lo < src_hi) {
+ if (src_lo->encoding() < src_hi->encoding()) {
null_check_offset = __ offset();
__ stmia(addr->base()->as_register(), RegisterSet(src_lo) | RegisterSet(src_hi));
} else {
- assert(src_lo < Rtemp, "Rtemp is higher than any allocatable register");
+ assert(src_lo->encoding() < Rtemp->encoding(), "Rtemp is higher than any allocatable register");
__ mov(Rtemp, src_hi);
null_check_offset = __ offset();
__ stmia(addr->base()->as_register(), RegisterSet(src_lo) | RegisterSet(Rtemp));
@@ -2670,10 +2676,10 @@ void LIR_Assembler::volatile_move_op(LIR_Opr src, LIR_Opr dest, BasicType type,
assert(addr->index()->is_illegal() && addr->disp() == 0, "The address is simple already");
null_check_offset = __ offset();
- if (dest_lo < dest_hi) {
+ if (dest_lo->encoding() < dest_hi->encoding()) {
__ ldmia(addr->base()->as_register(), RegisterSet(dest_lo) | RegisterSet(dest_hi));
} else {
- assert(dest_lo < Rtemp, "Rtemp is higher than any allocatable register");
+ assert(dest_lo->encoding() < Rtemp->encoding(), "Rtemp is higher than any allocatable register");
__ ldmia(addr->base()->as_register(), RegisterSet(dest_lo) | RegisterSet(Rtemp));
__ mov(dest_hi, Rtemp);
}
diff --git a/src/hotspot/cpu/arm/interp_masm_arm.cpp b/src/hotspot/cpu/arm/interp_masm_arm.cpp
index f49b6ed06ece..2678b74bd780 100644
--- a/src/hotspot/cpu/arm/interp_masm_arm.cpp
+++ b/src/hotspot/cpu/arm/interp_masm_arm.cpp
@@ -406,7 +406,7 @@ void InterpreterMacroAssembler::pop_i(Register r) {
void InterpreterMacroAssembler::pop_l(Register lo, Register hi) {
assert_different_registers(lo, hi);
- assert(lo < hi, "lo must be < hi");
+ assert(lo->encoding() < hi->encoding(), "lo must be < hi");
pop(RegisterSet(lo) | RegisterSet(hi));
}
@@ -456,7 +456,7 @@ void InterpreterMacroAssembler::push_i(Register r) {
void InterpreterMacroAssembler::push_l(Register lo, Register hi) {
assert_different_registers(lo, hi);
- assert(lo < hi, "lo must be < hi");
+ assert(lo->encoding() < hi->encoding(), "lo must be < hi");
push(RegisterSet(lo) | RegisterSet(hi));
}
diff --git a/src/hotspot/cpu/arm/register_arm.cpp b/src/hotspot/cpu/arm/register_arm.cpp
index a0ae9ff4f92a..a4c5a3f20bb1 100644
--- a/src/hotspot/cpu/arm/register_arm.cpp
+++ b/src/hotspot/cpu/arm/register_arm.cpp
@@ -26,12 +26,19 @@
#include "register_arm.hpp"
#include "utilities/debug.hpp"
-const int ConcreteRegisterImpl::max_gpr = ConcreteRegisterImpl::num_gpr;
-const int ConcreteRegisterImpl::max_fpr = ConcreteRegisterImpl::num_fpr +
- ConcreteRegisterImpl::max_gpr;
+Register::RegisterImpl all_RegisterImpls [Register::number_of_registers + 1];
+FloatRegister::FloatRegisterImpl all_FloatRegisterImpls [FloatRegister::number_of_registers + 1];
+VFPSystemRegister::VFPSystemRegisterImpl all_VFPSystemRegisterImpls [VFPSystemRegister::number_of_registers + 1] {
+ { -1 }, //vfpsnoreg
+ { VFPSystemRegister::FPSID },
+ { VFPSystemRegister::FPSCR },
+ { VFPSystemRegister::MVFR0 },
+ { VFPSystemRegister::MVFR1 }
+};
-const char* RegisterImpl::name() const {
- const char* names[number_of_registers] = {
+const char* Register::RegisterImpl::name() const {
+ static const char* names[number_of_registers + 1] = {
+ "noreg",
"r0", "r1", "r2", "r3", "r4", "r5", "r6",
#if (FP_REG_NUM == 7)
"fp",
@@ -46,13 +53,14 @@ const char* RegisterImpl::name() const {
#endif
"r12", "sp", "lr", "pc"
};
- return is_valid() ? names[encoding()] : "noreg";
+ return names[encoding() + 1];
}
-const char* FloatRegisterImpl::name() const {
- const char* names[number_of_registers] = {
- "s0", "s1", "s2", "s3", "s4", "s5", "s6", "s7",
- "s8", "s9", "s10", "s11", "s12", "s13", "s14", "s15",
+const char* FloatRegister::FloatRegisterImpl::name() const {
+ static const char* names[number_of_registers + 1] = {
+ "fnoreg",
+ "s0", "s1", "s2", "s3", "s4", "s5", "s6", "s7",
+ "s8", "s9", "s10", "s11", "s12", "s13", "s14", "s15",
"s16", "s17", "s18", "s19", "s20", "s21", "s22", "s23",
"s24", "s25", "s26", "s27", "s28", "s29", "s30", "s31"
#ifdef COMPILER2
@@ -62,5 +70,5 @@ const char* FloatRegisterImpl::name() const {
"s56", "s57?","s58", "s59?","s60", "s61?","s62", "s63?"
#endif
};
- return is_valid() ? names[encoding()] : "fnoreg";
+ return names[encoding() + 1];
}
diff --git a/src/hotspot/cpu/arm/register_arm.hpp b/src/hotspot/cpu/arm/register_arm.hpp
index 9f486d2a6258..d56fcf04dd99 100644
--- a/src/hotspot/cpu/arm/register_arm.hpp
+++ b/src/hotspot/cpu/arm/register_arm.hpp
@@ -31,26 +31,6 @@
class VMRegImpl;
typedef VMRegImpl* VMReg;
-// These are declared ucontext.h
-#undef R0
-#undef R1
-#undef R2
-#undef R3
-#undef R4
-#undef R5
-#undef R6
-#undef R7
-#undef R8
-#undef R9
-#undef R10
-#undef R11
-#undef R12
-#undef R13
-#undef R14
-#undef R15
-
-#define R(r) ((Register)(r))
-
/////////////////////////////////
// Support for different ARM ABIs
// Note: default ABI is for linux
@@ -94,25 +74,86 @@ typedef VMRegImpl* VMReg;
#define ALIGN_WIDE_ARGUMENTS 1
#endif
-#define R0 ((Register)0)
-#define R1 ((Register)1)
-#define R2 ((Register)2)
-#define R3 ((Register)3)
-#define R4 ((Register)4)
-#define R5 ((Register)5)
-#define R6 ((Register)6)
-#define R7 ((Register)7)
-#define R8 ((Register)8)
-#define R9 ((Register)9)
-#define R10 ((Register)10)
-#define R11 ((Register)11)
-#define R12 ((Register)12)
-#define R13 ((Register)13)
-#define R14 ((Register)14)
-#define R15 ((Register)15)
-
-
-#define FP ((Register)FP_REG_NUM)
+class Register {
+ private:
+ int _encoding;
+
+ constexpr explicit Register(int encoding) : _encoding(encoding) {}
+
+ public:
+ enum {
+ number_of_registers = 16,
+ max_slots_per_register = 1
+ };
+
+ class RegisterImpl : public AbstractRegisterImpl {
+ friend class Register;
+
+ static constexpr const RegisterImpl* first();
+
+ public:
+
+ // accessors and testers
+ int raw_encoding() const { return this - first(); }
+ int encoding() const { assert(is_valid(), "invalid register"); return raw_encoding(); }
+ bool is_valid() const { return 0 <= raw_encoding() && raw_encoding() < number_of_registers; }
+
+ inline Register successor() const;
+
+ VMReg as_VMReg() const;
+
+ const char* name() const;
+ };
+
+
+ inline friend constexpr Register as_Register(int encoding);
+
+ constexpr Register() : _encoding(-1) {} //noreg
+
+ int operator==(const Register r) const { return _encoding == r._encoding; }
+ int operator!=(const Register r) const { return _encoding != r._encoding; }
+
+ const RegisterImpl* operator->() const { return RegisterImpl::first() + _encoding; }
+};
+
+extern Register::RegisterImpl all_RegisterImpls[Register::number_of_registers + 1] INTERNAL_VISIBILITY;
+
+inline constexpr const Register::RegisterImpl* Register::RegisterImpl::first() {
+ return all_RegisterImpls + 1;
+}
+
+constexpr Register noreg = Register();
+
+inline constexpr Register as_Register(int encoding) {
+ if (0 <= encoding && encoding < Register::number_of_registers) {
+ return Register(encoding);
+ }
+ return noreg;
+}
+
+inline Register Register::RegisterImpl::successor() const {
+ assert(is_valid(), "sainty");
+ return as_Register(encoding() + 1);
+}
+
+constexpr Register R0 = as_Register( 0);
+constexpr Register R1 = as_Register( 1);
+constexpr Register R2 = as_Register( 2);
+constexpr Register R3 = as_Register( 3);
+constexpr Register R4 = as_Register( 4);
+constexpr Register R5 = as_Register( 5);
+constexpr Register R6 = as_Register( 6);
+constexpr Register R7 = as_Register( 7);
+constexpr Register R8 = as_Register( 8);
+constexpr Register R9 = as_Register( 9);
+constexpr Register R10 = as_Register(10);
+constexpr Register R11 = as_Register(11);
+constexpr Register R12 = as_Register(12);
+constexpr Register R13 = as_Register(13);
+constexpr Register R14 = as_Register(14);
+constexpr Register R15 = as_Register(15);
+
+constexpr Register FP = as_Register(FP_REG_NUM);
// Safe use of registers which may be FP on some platforms.
//
@@ -122,282 +163,340 @@ typedef VMRegImpl* VMReg;
// as FP on supported ABIs (and replace R# by altFP_#_11). altFP_#_11
// must be #define to R11 if and only if # is FP_REG_NUM.
#if (FP_REG_NUM == 7)
-#define altFP_7_11 ((Register)11)
+constexpr Register altFP_7_11 = R11;
#else
-#define altFP_7_11 ((Register)7)
+constexpr Register altFP_7_11 = R7;
#endif
-#define SP R13
-#define LR R14
-#define PC R15
+constexpr Register SP = R13;
+constexpr Register LR = R14;
+constexpr Register PC = R15;
-class RegisterImpl;
-typedef RegisterImpl* Register;
+class FloatRegister {
+ private:
+ int _encoding;
-inline Register as_Register(int encoding) {
- return (Register)(intptr_t)encoding;
-}
+ constexpr explicit FloatRegister(int encoding) : _encoding(encoding) {}
-class RegisterImpl : public AbstractRegisterImpl {
public:
enum {
- number_of_registers = 16
+ number_of_registers = NOT_COMPILER2(32) COMPILER2_PRESENT(64),
+ max_slots_per_register = 1
};
- Register successor() const { return as_Register(encoding() + 1); }
+ class FloatRegisterImpl : public AbstractRegisterImpl {
+ friend class FloatRegister;
- inline friend Register as_Register(int encoding);
+ static constexpr const FloatRegisterImpl* first();
- VMReg as_VMReg();
+ public:
- // accessors
- int encoding() const { assert(is_valid(), "invalid register"); return value(); }
- const char* name() const;
+ // accessors and testers
+ int raw_encoding() const { return this - first(); }
+ int encoding() const { assert(is_valid(), "invalid register"); return raw_encoding(); }
+ bool is_valid() const { return 0 <= raw_encoding() && raw_encoding() < number_of_registers; }
+ inline FloatRegister successor() const;
- // testers
- bool is_valid() const { return 0 <= value() && value() < number_of_registers; }
+ VMReg as_VMReg() const;
-};
-
-CONSTANT_REGISTER_DECLARATION(Register, noreg, (-1));
+ int hi_bits() const {
+ return (encoding() >> 1) & 0xf;
+ }
+ int lo_bit() const {
+ return encoding() & 1;
+ }
-// Use FloatRegister as shortcut
-class FloatRegisterImpl;
-typedef FloatRegisterImpl* FloatRegister;
+ int hi_bit() const {
+ return encoding() >> 5;
+ }
-inline FloatRegister as_FloatRegister(int encoding) {
- return (FloatRegister)(intptr_t)encoding;
-}
-
-class FloatRegisterImpl : public AbstractRegisterImpl {
- public:
- enum {
- number_of_registers = NOT_COMPILER2(32) COMPILER2_PRESENT(64)
+ const char* name() const;
};
- inline friend FloatRegister as_FloatRegister(int encoding);
+ inline friend constexpr FloatRegister as_FloatRegister(int encoding);
- VMReg as_VMReg();
+ constexpr FloatRegister() : _encoding(-1) {} // fnoreg
- int encoding() const { assert(is_valid(), "invalid register"); return value(); }
- bool is_valid() const { return 0 <= (intx)this && (intx)this < number_of_registers; }
- FloatRegister successor() const { return as_FloatRegister(encoding() + 1); }
+ int operator==(const FloatRegister r) const { return _encoding == r._encoding; }
+ int operator!=(const FloatRegister r) const { return _encoding != r._encoding; }
- const char* name() const;
+ const FloatRegisterImpl* operator->() const { return FloatRegisterImpl::first() + _encoding; }
+};
- int hi_bits() const {
- return (encoding() >> 1) & 0xf;
- }
+extern FloatRegister::FloatRegisterImpl all_FloatRegisterImpls[FloatRegister::number_of_registers + 1] INTERNAL_VISIBILITY;
- int lo_bit() const {
- return encoding() & 1;
- }
+inline constexpr const FloatRegister::FloatRegisterImpl* FloatRegister::FloatRegisterImpl::first() {
+ return all_FloatRegisterImpls + 1;
+}
- int hi_bit() const {
- return encoding() >> 5;
+constexpr FloatRegister fnoreg = FloatRegister();
+
+inline constexpr FloatRegister as_FloatRegister(int encoding) {
+ if (0 <= encoding && encoding < FloatRegister::number_of_registers) {
+ return FloatRegister(encoding);
}
-};
+ return fnoreg;
+}
-CONSTANT_REGISTER_DECLARATION(FloatRegister, fnoreg, (-1));
+inline FloatRegister FloatRegister::FloatRegisterImpl::successor() const {
+ assert(is_valid(), "sainty");
+ return as_FloatRegister(encoding() + 1);
+}
/*
* S1-S6 are named with "_reg" suffix to avoid conflict with
* constants defined in sharedRuntimeTrig.cpp
*/
-CONSTANT_REGISTER_DECLARATION(FloatRegister, S0, ( 0));
-CONSTANT_REGISTER_DECLARATION(FloatRegister, S1_reg, ( 1));
-CONSTANT_REGISTER_DECLARATION(FloatRegister, S2_reg, ( 2));
-CONSTANT_REGISTER_DECLARATION(FloatRegister, S3_reg, ( 3));
-CONSTANT_REGISTER_DECLARATION(FloatRegister, S4_reg, ( 4));
-CONSTANT_REGISTER_DECLARATION(FloatRegister, S5_reg, ( 5));
-CONSTANT_REGISTER_DECLARATION(FloatRegister, S6_reg, ( 6));
-CONSTANT_REGISTER_DECLARATION(FloatRegister, S7, ( 7));
-CONSTANT_REGISTER_DECLARATION(FloatRegister, S8, ( 8));
-CONSTANT_REGISTER_DECLARATION(FloatRegister, S9, ( 9));
-CONSTANT_REGISTER_DECLARATION(FloatRegister, S10, (10));
-CONSTANT_REGISTER_DECLARATION(FloatRegister, S11, (11));
-CONSTANT_REGISTER_DECLARATION(FloatRegister, S12, (12));
-CONSTANT_REGISTER_DECLARATION(FloatRegister, S13, (13));
-CONSTANT_REGISTER_DECLARATION(FloatRegister, S14, (14));
-CONSTANT_REGISTER_DECLARATION(FloatRegister, S15, (15));
-CONSTANT_REGISTER_DECLARATION(FloatRegister, S16, (16));
-CONSTANT_REGISTER_DECLARATION(FloatRegister, S17, (17));
-CONSTANT_REGISTER_DECLARATION(FloatRegister, S18, (18));
-CONSTANT_REGISTER_DECLARATION(FloatRegister, S19, (19));
-CONSTANT_REGISTER_DECLARATION(FloatRegister, S20, (20));
-CONSTANT_REGISTER_DECLARATION(FloatRegister, S21, (21));
-CONSTANT_REGISTER_DECLARATION(FloatRegister, S22, (22));
-CONSTANT_REGISTER_DECLARATION(FloatRegister, S23, (23));
-CONSTANT_REGISTER_DECLARATION(FloatRegister, S24, (24));
-CONSTANT_REGISTER_DECLARATION(FloatRegister, S25, (25));
-CONSTANT_REGISTER_DECLARATION(FloatRegister, S26, (26));
-CONSTANT_REGISTER_DECLARATION(FloatRegister, S27, (27));
-CONSTANT_REGISTER_DECLARATION(FloatRegister, S28, (28));
-CONSTANT_REGISTER_DECLARATION(FloatRegister, S29, (29));
-CONSTANT_REGISTER_DECLARATION(FloatRegister, S30, (30));
-CONSTANT_REGISTER_DECLARATION(FloatRegister, S31, (31));
-CONSTANT_REGISTER_DECLARATION(FloatRegister, Stemp, (30));
-
-CONSTANT_REGISTER_DECLARATION(FloatRegister, D0, ( 0));
-CONSTANT_REGISTER_DECLARATION(FloatRegister, D1, ( 2));
-CONSTANT_REGISTER_DECLARATION(FloatRegister, D2, ( 4));
-CONSTANT_REGISTER_DECLARATION(FloatRegister, D3, ( 6));
-CONSTANT_REGISTER_DECLARATION(FloatRegister, D4, ( 8));
-CONSTANT_REGISTER_DECLARATION(FloatRegister, D5, ( 10));
-CONSTANT_REGISTER_DECLARATION(FloatRegister, D6, ( 12));
-CONSTANT_REGISTER_DECLARATION(FloatRegister, D7, ( 14));
-CONSTANT_REGISTER_DECLARATION(FloatRegister, D8, ( 16));
-CONSTANT_REGISTER_DECLARATION(FloatRegister, D9, ( 18));
-CONSTANT_REGISTER_DECLARATION(FloatRegister, D10, ( 20));
-CONSTANT_REGISTER_DECLARATION(FloatRegister, D11, ( 22));
-CONSTANT_REGISTER_DECLARATION(FloatRegister, D12, ( 24));
-CONSTANT_REGISTER_DECLARATION(FloatRegister, D13, ( 26));
-CONSTANT_REGISTER_DECLARATION(FloatRegister, D14, ( 28));
-CONSTANT_REGISTER_DECLARATION(FloatRegister, D15, (30));
-CONSTANT_REGISTER_DECLARATION(FloatRegister, D16, (32));
-CONSTANT_REGISTER_DECLARATION(FloatRegister, D17, (34));
-CONSTANT_REGISTER_DECLARATION(FloatRegister, D18, (36));
-CONSTANT_REGISTER_DECLARATION(FloatRegister, D19, (38));
-CONSTANT_REGISTER_DECLARATION(FloatRegister, D20, (40));
-CONSTANT_REGISTER_DECLARATION(FloatRegister, D21, (42));
-CONSTANT_REGISTER_DECLARATION(FloatRegister, D22, (44));
-CONSTANT_REGISTER_DECLARATION(FloatRegister, D23, (46));
-CONSTANT_REGISTER_DECLARATION(FloatRegister, D24, (48));
-CONSTANT_REGISTER_DECLARATION(FloatRegister, D25, (50));
-CONSTANT_REGISTER_DECLARATION(FloatRegister, D26, (52));
-CONSTANT_REGISTER_DECLARATION(FloatRegister, D27, (54));
-CONSTANT_REGISTER_DECLARATION(FloatRegister, D28, (56));
-CONSTANT_REGISTER_DECLARATION(FloatRegister, D29, (58));
-CONSTANT_REGISTER_DECLARATION(FloatRegister, D30, (60));
-CONSTANT_REGISTER_DECLARATION(FloatRegister, D31, (62));
+constexpr FloatRegister S0 = as_FloatRegister( 0);
+constexpr FloatRegister S1_reg = as_FloatRegister(1);
+constexpr FloatRegister S2_reg = as_FloatRegister(2);
+constexpr FloatRegister S3_reg = as_FloatRegister(3);
+constexpr FloatRegister S4_reg = as_FloatRegister(4);
+constexpr FloatRegister S5_reg = as_FloatRegister(5);
+constexpr FloatRegister S6_reg = as_FloatRegister(6);
+constexpr FloatRegister S7 = as_FloatRegister( 7);
+constexpr FloatRegister S8 = as_FloatRegister( 8);
+constexpr FloatRegister S9 = as_FloatRegister( 9);
+constexpr FloatRegister S10 = as_FloatRegister(10);
+constexpr FloatRegister S11 = as_FloatRegister(11);
+constexpr FloatRegister S12 = as_FloatRegister(12);
+constexpr FloatRegister S13 = as_FloatRegister(13);
+constexpr FloatRegister S14 = as_FloatRegister(14);
+constexpr FloatRegister S15 = as_FloatRegister(15);
+constexpr FloatRegister S16 = as_FloatRegister(16);
+constexpr FloatRegister S17 = as_FloatRegister(17);
+constexpr FloatRegister S18 = as_FloatRegister(18);
+constexpr FloatRegister S19 = as_FloatRegister(19);
+constexpr FloatRegister S20 = as_FloatRegister(20);
+constexpr FloatRegister S21 = as_FloatRegister(21);
+constexpr FloatRegister S22 = as_FloatRegister(22);
+constexpr FloatRegister S23 = as_FloatRegister(23);
+constexpr FloatRegister S24 = as_FloatRegister(24);
+constexpr FloatRegister S25 = as_FloatRegister(25);
+constexpr FloatRegister S26 = as_FloatRegister(26);
+constexpr FloatRegister S27 = as_FloatRegister(27);
+constexpr FloatRegister S28 = as_FloatRegister(28);
+constexpr FloatRegister S29 = as_FloatRegister(29);
+constexpr FloatRegister S30 = as_FloatRegister(30);
+constexpr FloatRegister S31 = as_FloatRegister(31);
+constexpr FloatRegister Stemp = S30;
+
+constexpr FloatRegister D0 = as_FloatRegister( 0);
+constexpr FloatRegister D1 = as_FloatRegister( 2);
+constexpr FloatRegister D2 = as_FloatRegister( 4);
+constexpr FloatRegister D3 = as_FloatRegister( 6);
+constexpr FloatRegister D4 = as_FloatRegister( 8);
+constexpr FloatRegister D5 = as_FloatRegister(10);
+constexpr FloatRegister D6 = as_FloatRegister(12);
+constexpr FloatRegister D7 = as_FloatRegister(14);
+constexpr FloatRegister D8 = as_FloatRegister(16);
+constexpr FloatRegister D9 = as_FloatRegister(18);
+constexpr FloatRegister D10 = as_FloatRegister(20);
+constexpr FloatRegister D11 = as_FloatRegister(22);
+constexpr FloatRegister D12 = as_FloatRegister(24);
+constexpr FloatRegister D13 = as_FloatRegister(26);
+constexpr FloatRegister D14 = as_FloatRegister(28);
+constexpr FloatRegister D15 = as_FloatRegister(30);
+constexpr FloatRegister D16 = as_FloatRegister(32);
+constexpr FloatRegister D17 = as_FloatRegister(34);
+constexpr FloatRegister D18 = as_FloatRegister(36);
+constexpr FloatRegister D19 = as_FloatRegister(38);
+constexpr FloatRegister D20 = as_FloatRegister(40);
+constexpr FloatRegister D21 = as_FloatRegister(42);
+constexpr FloatRegister D22 = as_FloatRegister(44);
+constexpr FloatRegister D23 = as_FloatRegister(46);
+constexpr FloatRegister D24 = as_FloatRegister(48);
+constexpr FloatRegister D25 = as_FloatRegister(50);
+constexpr FloatRegister D26 = as_FloatRegister(52);
+constexpr FloatRegister D27 = as_FloatRegister(54);
+constexpr FloatRegister D28 = as_FloatRegister(56);
+constexpr FloatRegister D29 = as_FloatRegister(58);
+constexpr FloatRegister D30 = as_FloatRegister(60);
+constexpr FloatRegister D31 = as_FloatRegister(62);
class ConcreteRegisterImpl : public AbstractRegisterImpl {
public:
enum {
- log_vmregs_per_word = LogBytesPerWord - LogBytesPerInt, // VMRegs are of 4-byte size
-#ifdef COMPILER2
- log_bytes_per_fpr = 2, // quad vectors
-#else
- log_bytes_per_fpr = 2, // double vectors
-#endif
- log_words_per_fpr = log_bytes_per_fpr - LogBytesPerWord,
- words_per_fpr = 1 << log_words_per_fpr,
- log_vmregs_per_fpr = log_bytes_per_fpr - LogBytesPerInt,
- log_vmregs_per_gpr = log_vmregs_per_word,
- vmregs_per_gpr = 1 << log_vmregs_per_gpr,
- vmregs_per_fpr = 1 << log_vmregs_per_fpr,
-
- num_gpr = RegisterImpl::number_of_registers << log_vmregs_per_gpr,
- max_gpr0 = num_gpr,
- num_fpr = FloatRegisterImpl::number_of_registers << log_vmregs_per_fpr,
- max_fpr0 = max_gpr0 + num_fpr,
- number_of_registers = num_gpr + num_fpr + 1+1 // APSR and FPSCR so that c2's REG_COUNT <= ConcreteRegisterImpl::number_of_registers
- };
+ max_gpr = Register::number_of_registers * Register::max_slots_per_register,
+ max_fpr = max_gpr + FloatRegister::number_of_registers * FloatRegister::max_slots_per_register,
- static const int max_gpr;
- static const int max_fpr;
+ number_of_registers = max_fpr + 1+1 // APSR and FPSCR so that c2's REG_COUNT <= ConcreteRegisterImpl::number_of_registers
+ };
};
-class VFPSystemRegisterImpl;
-typedef VFPSystemRegisterImpl* VFPSystemRegister;
-class VFPSystemRegisterImpl : public AbstractRegisterImpl {
+typedef AbstractRegSet RegSet;
+typedef AbstractRegSet FloatRegSet;
+
+template <>
+inline Register AbstractRegSet::first() {
+ if (_bitset == 0) { return noreg; }
+ return as_Register(count_trailing_zeros(_bitset));
+}
+
+
+template <>
+inline FloatRegister AbstractRegSet::first() {
+ uint32_t first = _bitset & -_bitset;
+ return first ? as_FloatRegister(exact_log2(first)) : fnoreg;
+}
+
+
+class VFPSystemRegister {
+ private:
+ int _store_idx;
+
+ constexpr explicit VFPSystemRegister(int store_idx) : _store_idx(store_idx) {}
+
+ enum {
+ _FPSID_store_idx = 0,
+ _FPSCR_store_idx = 1,
+ _MVFR0_store_idx = 2,
+ _MVFR1_store_idx = 3
+ };
+
public:
- int encoding() const { return value(); }
+ enum {
+ FPSID = 0,
+ FPSCR = 1,
+ MVFR0 = 6,
+ MVFR1 = 7,
+ number_of_registers = 4
+ };
+
+ class VFPSystemRegisterImpl : public AbstractRegisterImpl {
+ friend class VFPSystemRegister;
+
+ int _encoding;
+
+ static constexpr const VFPSystemRegisterImpl* first();
+
+ public:
+ constexpr VFPSystemRegisterImpl(int encoding) : _encoding(encoding) {}
+
+ int encoding() const { return _encoding; }
+ };
+
+ inline friend constexpr VFPSystemRegister as_VFPSystemRegister(int encoding);
+
+ constexpr VFPSystemRegister() : _store_idx(-1) {} // vfpsnoreg
+
+ int operator==(const VFPSystemRegister r) const { return _store_idx == r._store_idx; }
+ int operator!=(const VFPSystemRegister r) const { return _store_idx != r._store_idx; }
+
+ const VFPSystemRegisterImpl* operator->() const { return VFPSystemRegisterImpl::first() + _store_idx; }
};
-#define FPSID ((VFPSystemRegister)0)
-#define FPSCR ((VFPSystemRegister)1)
-#define MVFR0 ((VFPSystemRegister)0x6)
-#define MVFR1 ((VFPSystemRegister)0x7)
+extern VFPSystemRegister::VFPSystemRegisterImpl all_VFPSystemRegisterImpls[VFPSystemRegister::number_of_registers + 1] INTERNAL_VISIBILITY;
+
+inline constexpr const VFPSystemRegister::VFPSystemRegisterImpl* VFPSystemRegister::VFPSystemRegisterImpl::first() {
+ return all_VFPSystemRegisterImpls + 1;
+}
+
+constexpr VFPSystemRegister vfpsnoreg = VFPSystemRegister();
+
+inline constexpr VFPSystemRegister as_VFPSystemRegister(int encoding) {
+ switch (encoding) {
+ case VFPSystemRegister::FPSID: return VFPSystemRegister(VFPSystemRegister::_FPSID_store_idx);
+ case VFPSystemRegister::FPSCR: return VFPSystemRegister(VFPSystemRegister::_FPSCR_store_idx);
+ case VFPSystemRegister::MVFR0: return VFPSystemRegister(VFPSystemRegister::_MVFR0_store_idx);
+ case VFPSystemRegister::MVFR1: return VFPSystemRegister(VFPSystemRegister::_MVFR1_store_idx);
+ default: return vfpsnoreg;
+ }
+}
+
+constexpr VFPSystemRegister FPSID = as_VFPSystemRegister(VFPSystemRegister::FPSID);
+constexpr VFPSystemRegister FPSCR = as_VFPSystemRegister(VFPSystemRegister::FPSCR);
+constexpr VFPSystemRegister MVFR0 = as_VFPSystemRegister(VFPSystemRegister::MVFR0);
+constexpr VFPSystemRegister MVFR1 = as_VFPSystemRegister(VFPSystemRegister::MVFR1);
/*
* Register definitions shared across interpreter and compiler
*/
-#define Rexception_obj R4
-#define Rexception_pc R5
+constexpr Register Rexception_obj = R4;
+constexpr Register Rexception_pc = R5;
/*
* Interpreter register definitions common to C++ and template interpreters.
*/
-#define Rlocals R8
-#define Rmethod R9
-#define Rthread R10
-#define Rtemp R12
+constexpr Register Rlocals = R8;
+constexpr Register Rmethod = R9;
+constexpr Register Rthread = R10;
+constexpr Register Rtemp = R12;
// Interpreter calling conventions
-#define Rparams SP
-#define Rsender_sp R4
+constexpr Register Rparams = SP;
+constexpr Register Rsender_sp = R4;
// JSR292
// Note: R5_mh is needed only during the call setup, including adapters
// This does not seem to conflict with Rexception_pc
// In case of issues, R3 might be OK but adapters calling the runtime would have to save it
-#define R5_mh R5 // MethodHandle register, used during the call setup
-#define Rmh_SP_save FP // for C1
+constexpr Register R5_mh = R5; // MethodHandle register, used during the call setup
+constexpr Register Rmh_SP_save = FP; // for C1
/*
* C++ Interpreter Register Defines
*/
-#define Rsave0 R4
-#define Rsave1 R5
-#define Rsave2 R6
-#define Rstate altFP_7_11 // R7 or R11
-#define Ricklass R8
+constexpr Register Rsave0 = R4;
+constexpr Register Rsave1 = R5;
+constexpr Register Rsave2 = R6;
+constexpr Register Rstate = altFP_7_11; // R7 or R11
+constexpr Register Ricklass = R8;
/*
* TemplateTable Interpreter Register Usage
*/
// Temporary registers
-#define R0_tmp R0
-#define R1_tmp R1
-#define R2_tmp R2
-#define R3_tmp R3
-#define R4_tmp R4
-#define R5_tmp R5
-#define R12_tmp R12
-#define LR_tmp LR
+constexpr Register R0_tmp = R0;
+constexpr Register R1_tmp = R1;
+constexpr Register R2_tmp = R2;
+constexpr Register R3_tmp = R3;
+constexpr Register R4_tmp = R4;
+constexpr Register R5_tmp = R5;
+constexpr Register R12_tmp = R12;
+constexpr Register LR_tmp = LR;
-#define S0_tmp S0
-#define S1_tmp S1_reg
+constexpr FloatRegister S0_tmp = S0;
+constexpr FloatRegister S1_tmp = S1_reg;
-#define D0_tmp D0
-#define D1_tmp D1
+constexpr FloatRegister D0_tmp = D0;
+constexpr FloatRegister D1_tmp = D1;
// Temporary registers saved across VM calls (according to C calling conventions)
-#define Rtmp_save0 R4
-#define Rtmp_save1 R5
+constexpr Register Rtmp_save0 = R4;
+constexpr Register Rtmp_save1 = R5;
// Cached TOS value
-#define R0_tos R0
+constexpr Register R0_tos = R0;
-#define R0_tos_lo R0
-#define R1_tos_hi R1
+constexpr Register R0_tos_lo = R0;
+constexpr Register R1_tos_hi = R1;
-#define S0_tos S0
-#define D0_tos D0
+constexpr FloatRegister S0_tos = S0;
+constexpr FloatRegister D0_tos = D0;
// Dispatch table
-#define RdispatchTable R6
+constexpr Register RdispatchTable = R6;
// Bytecode pointer
-#define Rbcp altFP_7_11
+constexpr Register Rbcp = altFP_7_11;
// Pre-loaded next bytecode for the dispatch
-#define R3_bytecode R3
+constexpr Register R3_bytecode = R3;
// Conventions between bytecode templates and stubs
-#define R2_ClassCastException_obj R2
-#define R4_ArrayIndexOutOfBounds_index R4
+constexpr Register R2_ClassCastException_obj = R2;
+constexpr Register R4_ArrayIndexOutOfBounds_index = R4;
// Interpreter expression stack top
-#define Rstack_top SP
+constexpr Register Rstack_top = SP;
/*
* Linux 32-bit ARM C ABI Register calling conventions
@@ -420,10 +519,11 @@ class VFPSystemRegisterImpl : public AbstractRegisterImpl {
* R14 (LR) Link register
* R15 (PC) Program Counter
*/
-#define c_rarg0 R0
-#define c_rarg1 R1
-#define c_rarg2 R2
-#define c_rarg3 R3
+
+constexpr Register c_rarg0 = R0;
+constexpr Register c_rarg1 = R1;
+constexpr Register c_rarg2 = R2;
+constexpr Register c_rarg3 = R3;
#define GPR_PARAMS 4
@@ -431,10 +531,10 @@ class VFPSystemRegisterImpl : public AbstractRegisterImpl {
// Java ABI
// XXX Is this correct?
-#define j_rarg0 c_rarg0
-#define j_rarg1 c_rarg1
-#define j_rarg2 c_rarg2
-#define j_rarg3 c_rarg3
+constexpr Register j_rarg0 = c_rarg0;
+constexpr Register j_rarg1 = c_rarg1;
+constexpr Register j_rarg2 = c_rarg2;
+constexpr Register j_rarg3 = c_rarg3;
#endif // CPU_ARM_REGISTER_ARM_HPP
diff --git a/src/hotspot/cpu/arm/sharedRuntime_arm.cpp b/src/hotspot/cpu/arm/sharedRuntime_arm.cpp
index d55cdfb02514..d53b360b977b 100644
--- a/src/hotspot/cpu/arm/sharedRuntime_arm.cpp
+++ b/src/hotspot/cpu/arm/sharedRuntime_arm.cpp
@@ -71,7 +71,7 @@ class RegisterSaver {
enum RegisterLayout {
- fpu_save_size = FloatRegisterImpl::number_of_registers,
+ fpu_save_size = FloatRegister::number_of_registers,
#ifndef __SOFTFP__
D0_offset = 0,
#endif
@@ -140,8 +140,8 @@ OopMap* RegisterSaver::save_live_registers(MacroAssembler* masm,
if (VM_Version::has_vfp3_32()) {
__ fpush(FloatRegisterSet(D16, 16));
} else {
- if (FloatRegisterImpl::number_of_registers > 32) {
- assert(FloatRegisterImpl::number_of_registers == 64, "nb fp registers should be 64");
+ if (FloatRegister::number_of_registers > 32) {
+ assert(FloatRegister::number_of_registers == 64, "nb fp registers should be 64");
__ sub(SP, SP, 32 * wordSize);
}
}
@@ -183,8 +183,8 @@ void RegisterSaver::restore_live_registers(MacroAssembler* masm, bool restore_lr
if (VM_Version::has_vfp3_32()) {
__ fpop(FloatRegisterSet(D16, 16));
} else {
- if (FloatRegisterImpl::number_of_registers > 32) {
- assert(FloatRegisterImpl::number_of_registers == 64, "nb fp registers should be 64");
+ if (FloatRegister::number_of_registers > 32) {
+ assert(FloatRegister::number_of_registers == 64, "nb fp registers should be 64");
__ add(SP, SP, 32 * wordSize);
}
}
diff --git a/src/hotspot/cpu/arm/vmreg_arm.cpp b/src/hotspot/cpu/arm/vmreg_arm.cpp
index c7c972db5c9b..c82f60c97d05 100644
--- a/src/hotspot/cpu/arm/vmreg_arm.cpp
+++ b/src/hotspot/cpu/arm/vmreg_arm.cpp
@@ -31,14 +31,14 @@ void VMRegImpl::set_regName() {
Register reg = ::as_Register(0);
int i;
for (i = 0; i < ConcreteRegisterImpl::max_gpr; reg = reg->successor()) {
- for (int j = 0; j < (1 << ConcreteRegisterImpl::log_vmregs_per_gpr); j++) {
+ for (int j = 0; j < Register::max_slots_per_register; j++) {
regName[i++] = reg->name();
}
}
#ifndef __SOFTFP__
FloatRegister freg = ::as_FloatRegister(0);
for ( ; i < ConcreteRegisterImpl::max_fpr ; ) {
- for (int j = 0; j < (1 << ConcreteRegisterImpl::log_vmregs_per_fpr); j++) {
+ for (int j = 0; j < Register::max_slots_per_register; j++) {
regName[i++] = freg->name();
}
freg = freg->successor();
diff --git a/src/hotspot/cpu/arm/vmreg_arm.hpp b/src/hotspot/cpu/arm/vmreg_arm.hpp
index c13f443b804f..f1dfd09a1e69 100644
--- a/src/hotspot/cpu/arm/vmreg_arm.hpp
+++ b/src/hotspot/cpu/arm/vmreg_arm.hpp
@@ -36,20 +36,20 @@
inline Register as_Register() {
assert(is_Register(), "must be");
assert(is_concrete(), "concrete register expected");
- return ::as_Register(value() >> ConcreteRegisterImpl::log_vmregs_per_gpr);
+ return ::as_Register(value() / Register::max_slots_per_register);
}
inline FloatRegister as_FloatRegister() {
assert(is_FloatRegister(), "must be");
assert(is_concrete(), "concrete register expected");
- return ::as_FloatRegister((value() - ConcreteRegisterImpl::max_gpr) >> ConcreteRegisterImpl::log_vmregs_per_fpr);
+ return ::as_FloatRegister((value() - ConcreteRegisterImpl::max_gpr) / FloatRegister::max_slots_per_register);
}
inline bool is_concrete() {
if (is_Register()) {
- return ((value() & right_n_bits(ConcreteRegisterImpl::log_vmregs_per_gpr)) == 0);
+ return (value() % Register::max_slots_per_register == 0);
} else if (is_FloatRegister()) {
- return (((value() - ConcreteRegisterImpl::max_gpr) & right_n_bits(ConcreteRegisterImpl::log_vmregs_per_fpr)) == 0);
+ return (value() % FloatRegister::max_slots_per_register == 0); // Single slot
} else {
return false;
}
diff --git a/src/hotspot/cpu/arm/vmreg_arm.inline.hpp b/src/hotspot/cpu/arm/vmreg_arm.inline.hpp
index f122b9ede701..3e5c18dbda0a 100644
--- a/src/hotspot/cpu/arm/vmreg_arm.inline.hpp
+++ b/src/hotspot/cpu/arm/vmreg_arm.inline.hpp
@@ -25,11 +25,11 @@
#ifndef CPU_ARM_VMREG_ARM_INLINE_HPP
#define CPU_ARM_VMREG_ARM_INLINE_HPP
-inline VMReg RegisterImpl::as_VMReg() {
- return VMRegImpl::as_VMReg(encoding() << ConcreteRegisterImpl::log_vmregs_per_gpr);
+inline VMReg Register::RegisterImpl::as_VMReg() const {
+ return VMRegImpl::as_VMReg(encoding() * Register::max_slots_per_register);
}
-inline VMReg FloatRegisterImpl::as_VMReg() {
- return VMRegImpl::as_VMReg((encoding() << ConcreteRegisterImpl::log_vmregs_per_fpr) + ConcreteRegisterImpl::max_gpr);
+inline VMReg FloatRegister::FloatRegisterImpl::as_VMReg() const {
+ return VMRegImpl::as_VMReg((encoding() * FloatRegister::max_slots_per_register) + ConcreteRegisterImpl::max_gpr);
}
#endif // CPU_ARM_VMREG_ARM_INLINE_HPP
diff --git a/src/hotspot/cpu/ppc/c2_MacroAssembler_ppc.cpp b/src/hotspot/cpu/ppc/c2_MacroAssembler_ppc.cpp
index d504c71e2b8b..608f8f919463 100644
--- a/src/hotspot/cpu/ppc/c2_MacroAssembler_ppc.cpp
+++ b/src/hotspot/cpu/ppc/c2_MacroAssembler_ppc.cpp
@@ -594,9 +594,11 @@ void C2_MacroAssembler::count_positives(Register src, Register cnt, Register res
bind(Lslow); // Fallback to slow version.
subf(tmp0, src, result); // Bytes known positive.
- subf_(tmp0, tmp0, cnt); // Remaining Bytes.
+ clrldi(tmp1, cnt, 32); // Clear garbage from upper 32 bits.
+ subf_(tmp0, tmp0, tmp1); // Remaining Bytes.
beq(CCR0, Ldone);
mtctr(tmp0);
+
bind(Lloop);
lbz(tmp0, 0, result);
andi_(tmp0, tmp0, 0x80);
diff --git a/src/hotspot/cpu/ppc/macroAssembler_ppc.cpp b/src/hotspot/cpu/ppc/macroAssembler_ppc.cpp
index adc40748fe7c..7e847e651844 100644
--- a/src/hotspot/cpu/ppc/macroAssembler_ppc.cpp
+++ b/src/hotspot/cpu/ppc/macroAssembler_ppc.cpp
@@ -4440,7 +4440,7 @@ void MacroAssembler::push_cont_fastpath() {
Label done;
ld_ptr(R0, JavaThread::cont_fastpath_offset(), R16_thread);
cmpld(CCR0, R1_SP, R0);
- ble(CCR0, done);
+ ble(CCR0, done); // if (SP <= _cont_fastpath) goto done;
st_ptr(R1_SP, JavaThread::cont_fastpath_offset(), R16_thread);
bind(done);
}
@@ -4449,7 +4449,7 @@ void MacroAssembler::pop_cont_fastpath() {
Label done;
ld_ptr(R0, JavaThread::cont_fastpath_offset(), R16_thread);
cmpld(CCR0, R1_SP, R0);
- ble(CCR0, done);
+ blt(CCR0, done); // if (SP < _cont_fastpath) goto done;
li(R0, 0);
st_ptr(R0, JavaThread::cont_fastpath_offset(), R16_thread);
bind(done);
diff --git a/src/hotspot/cpu/ppc/registerMap_ppc.cpp b/src/hotspot/cpu/ppc/registerMap_ppc.cpp
new file mode 100644
index 000000000000..e26e85df555f
--- /dev/null
+++ b/src/hotspot/cpu/ppc/registerMap_ppc.cpp
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2021, 2026, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2026 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
+ * 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 "runtime/registerMap.hpp"
+
+address RegisterMap::pd_location(VMReg base_reg, int slot_idx) const {
+ if (base_reg->is_VectorSRegister()) {
+ // Not all physical slots belonging to a VectorRegister have corresponding
+ // valid VMReg locations in the RegisterMap.
+ // (See RegisterSaver::push_frame_reg_args_and_save_live_registers.)
+ // However, the slots are always saved to the stack in a contiguous region
+ // of memory so we can calculate the address of the upper slots by
+ // offsetting from the base address.
+ assert(base_reg->is_concrete(), "must pass base reg");
+ address base_location = location(base_reg, nullptr);
+ if (base_location != nullptr) {
+ intptr_t offset_in_bytes = slot_idx * VMRegImpl::stack_slot_size;
+ return base_location + offset_in_bytes;
+ } else {
+ return nullptr;
+ }
+ } else {
+ return location(base_reg->next(slot_idx), nullptr);
+ }
+}
diff --git a/src/hotspot/cpu/ppc/registerMap_ppc.hpp b/src/hotspot/cpu/ppc/registerMap_ppc.hpp
index 01eb642107cb..607c712d10f2 100644
--- a/src/hotspot/cpu/ppc/registerMap_ppc.hpp
+++ b/src/hotspot/cpu/ppc/registerMap_ppc.hpp
@@ -1,6 +1,6 @@
/*
- * Copyright (c) 2000, 2023, Oracle and/or its affiliates. All rights reserved.
- * Copyright (c) 2012, 2013 SAP SE. All rights reserved.
+ * Copyright (c) 2000, 2026, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2026 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
@@ -35,9 +35,7 @@
// Since there is none, we just return null.
address pd_location(VMReg reg) const { return nullptr; }
- address pd_location(VMReg base_reg, int slot_idx) const {
- return location(base_reg->next(slot_idx), nullptr);
- }
+ address pd_location(VMReg base_reg, int slot_idx) const;
// no PD state to clear or copy:
void pd_clear() {}
diff --git a/src/hotspot/cpu/ppc/sharedRuntime_ppc.cpp b/src/hotspot/cpu/ppc/sharedRuntime_ppc.cpp
index 2281c083b98c..0790eceddc25 100644
--- a/src/hotspot/cpu/ppc/sharedRuntime_ppc.cpp
+++ b/src/hotspot/cpu/ppc/sharedRuntime_ppc.cpp
@@ -105,7 +105,7 @@ class RegisterSaver {
// During deoptimization only the result registers need to be restored
// all the other values have already been extracted.
- static void restore_result_registers(MacroAssembler* masm, int frame_size_in_bytes);
+ static void restore_result_registers(MacroAssembler* masm, int frame_size_in_bytes, bool save_vectors);
// Constants and data structures:
@@ -355,6 +355,7 @@ OopMap* RegisterSaver::push_frame_reg_args_and_save_live_registers(MacroAssemble
__ li(R30, offset);
__ stxvd2x(as_VectorSRegister(reg_num), R30, R1_SP);
+ // RegisterMap::pd_location only uses the first VMReg for each VectorRegister.
if (generate_oop_map) {
map->set_callee_saved(VMRegImpl::stack2reg(offset>>2),
RegisterSaver_LiveVSRegs[i].vmreg);
@@ -528,10 +529,14 @@ void RegisterSaver::restore_argument_registers_and_pop_frame(MacroAssembler*masm
}
// Restore the registers that might be holding a result.
-void RegisterSaver::restore_result_registers(MacroAssembler* masm, int frame_size_in_bytes) {
+void RegisterSaver::restore_result_registers(MacroAssembler* masm, int frame_size_in_bytes, bool save_vectors) {
const int regstosave_num = sizeof(RegisterSaver_LiveRegs) /
sizeof(RegisterSaver::LiveRegType);
- const int register_save_size = regstosave_num * reg_size; // VS registers not relevant here.
+ const int vecregstosave_num = save_vectors ? (sizeof(RegisterSaver_LiveVSRegs) /
+ sizeof(RegisterSaver::LiveRegType))
+ : 0;
+ const int register_save_size = regstosave_num * reg_size + vecregstosave_num * vs_reg_size;
+
const int register_save_offset = frame_size_in_bytes - register_save_size;
// restore all result registers (ints and floats)
@@ -560,7 +565,7 @@ void RegisterSaver::restore_result_registers(MacroAssembler* masm, int frame_siz
offset += reg_size;
}
- assert(offset == frame_size_in_bytes, "consistency check");
+ assert(offset == frame_size_in_bytes - (save_vectors ? vecregstosave_num * vs_reg_size : 0), "consistency check");
}
// Is vector's size (in bytes) bigger than a size saved by default?
@@ -2984,7 +2989,8 @@ void SharedRuntime::generate_deopt_blob() {
&first_frame_size_in_bytes,
/*generate_oop_map=*/ true,
return_pc_adjustment_no_exception,
- RegisterSaver::return_pc_is_lr);
+ RegisterSaver::return_pc_is_lr,
+ /*save_vectors*/ SuperwordUseVSX);
assert(map != nullptr, "OopMap must have been created");
__ li(exec_mode_reg, Deoptimization::Unpack_deopt);
@@ -3019,7 +3025,8 @@ void SharedRuntime::generate_deopt_blob() {
&first_frame_size_in_bytes,
/*generate_oop_map=*/ false,
/*return_pc_adjustment_exception=*/ 0,
- RegisterSaver::return_pc_is_pre_saved);
+ RegisterSaver::return_pc_is_pre_saved,
+ /*save_vectors*/ SuperwordUseVSX);
// Deopt during an exception. Save exec mode for unpack_frames.
__ li(exec_mode_reg, Deoptimization::Unpack_exception);
@@ -3037,7 +3044,8 @@ void SharedRuntime::generate_deopt_blob() {
&first_frame_size_in_bytes,
/*generate_oop_map=*/ false,
/*return_pc_adjustment_reexecute=*/ 0,
- RegisterSaver::return_pc_is_pre_saved);
+ RegisterSaver::return_pc_is_pre_saved,
+ /*save_vectors*/ SuperwordUseVSX);
__ li(exec_mode_reg, Deoptimization::Unpack_reexecute);
#endif
@@ -3063,7 +3071,7 @@ void SharedRuntime::generate_deopt_blob() {
// Restore only the result registers that have been saved
// by save_volatile_registers(...).
- RegisterSaver::restore_result_registers(masm, first_frame_size_in_bytes);
+ RegisterSaver::restore_result_registers(masm, first_frame_size_in_bytes, /*save_vectors*/ SuperwordUseVSX);
// reload the exec mode from the UnrollBlock (it might have changed)
__ lwz(exec_mode_reg, in_bytes(Deoptimization::UnrollBlock::unpack_kind_offset()), unroll_block_reg);
diff --git a/src/hotspot/cpu/ppc/vm_version_ppc.cpp b/src/hotspot/cpu/ppc/vm_version_ppc.cpp
index e5037482c447..0543885a4752 100644
--- a/src/hotspot/cpu/ppc/vm_version_ppc.cpp
+++ b/src/hotspot/cpu/ppc/vm_version_ppc.cpp
@@ -26,6 +26,7 @@
#include "precompiled.hpp"
#include "asm/assembler.inline.hpp"
#include "asm/macroAssembler.inline.hpp"
+#include "compiler/compilerDefinitions.inline.hpp"
#include "compiler/disassembler.hpp"
#include "jvm.h"
#include "memory/resourceArea.hpp"
@@ -130,7 +131,7 @@ void VM_Version::initialize() {
}
if (PowerArchitecturePPC64 >= 8) {
- if (FLAG_IS_DEFAULT(SuperwordUseVSX)) {
+ if (FLAG_IS_DEFAULT(SuperwordUseVSX) && CompilerConfig::is_c2_enabled()) {
FLAG_SET_ERGO(SuperwordUseVSX, true);
}
} else {
diff --git a/src/hotspot/cpu/riscv/gc/shenandoah/shenandoahBarrierSetAssembler_riscv.cpp b/src/hotspot/cpu/riscv/gc/shenandoah/shenandoahBarrierSetAssembler_riscv.cpp
index 26d60441c2d2..ed828f9356b4 100644
--- a/src/hotspot/cpu/riscv/gc/shenandoah/shenandoahBarrierSetAssembler_riscv.cpp
+++ b/src/hotspot/cpu/riscv/gc/shenandoah/shenandoahBarrierSetAssembler_riscv.cpp
@@ -298,7 +298,7 @@ void ShenandoahBarrierSetAssembler::load_reference_barrier(MacroAssembler* masm,
} else {
assert(is_phantom, "only remaining strength");
assert(!is_narrow, "phantom access cannot be narrow");
- target = CAST_FROM_FN_PTR(address, ShenandoahRuntime::load_reference_barrier_weak);
+ target = CAST_FROM_FN_PTR(address, ShenandoahRuntime::load_reference_barrier_phantom);
}
__ call(target);
__ mv(t0, x10);
diff --git a/src/hotspot/os/aix/os_aix.cpp b/src/hotspot/os/aix/os_aix.cpp
index 67592d37bb5d..a4bd69fa0583 100644
--- a/src/hotspot/os/aix/os_aix.cpp
+++ b/src/hotspot/os/aix/os_aix.cpp
@@ -177,7 +177,7 @@ static void vmembk_print_on(outputStream* os);
////////////////////////////////////////////////////////////////////////////////
// global variables (for a description see os_aix.hpp)
-julong os::Aix::_physical_memory = 0;
+physical_memory_size_type os::Aix::_physical_memory = 0;
pthread_t os::Aix::_main_thread = ((pthread_t)0);
@@ -265,28 +265,29 @@ static bool is_close_to_brk(address a) {
return false;
}
-julong os::free_memory() {
- return Aix::available_memory();
+bool os::free_memory(physical_memory_size_type& value) {
+ return Aix::available_memory(value);
}
-julong os::available_memory() {
- return Aix::available_memory();
+bool os::available_memory(physical_memory_size_type& value) {
+ return Aix::available_memory(value);
}
-julong os::Aix::available_memory() {
+bool os::Aix::available_memory(physical_memory_size_type& value) {
// Avoid expensive API call here, as returned value will always be null.
if (os::Aix::on_pase()) {
return 0x0LL;
}
os::Aix::meminfo_t mi;
if (os::Aix::get_meminfo(&mi)) {
- return mi.real_free;
+ value = static_cast(mi.real_free);
+ return true;
} else {
- return ULONG_MAX;
+ return false;
}
}
-julong os::physical_memory() {
+physical_memory_size_type os::physical_memory() {
return Aix::physical_memory();
}
@@ -357,7 +358,7 @@ void os::Aix::initialize_system_info() {
if (!os::Aix::get_meminfo(&mi)) {
assert(false, "os::Aix::get_meminfo failed.");
}
- _physical_memory = (julong) mi.real_total;
+ _physical_memory = static_cast(mi.real_total);
}
// Helper function for tracing page sizes.
@@ -1133,6 +1134,8 @@ static void* dll_load_library(const char *filename, int *eno, char *ebuf, int eb
dflags |= RTLD_MEMBER;
}
+ Events::log_dll_message(nullptr, "Attempting to load shared library %s", filename);
+
void* result;
const char* error_report = nullptr;
result = Aix_dlopen(filename, dflags, eno, &error_report);
@@ -2406,7 +2409,7 @@ jint os::init_2(void) {
}
trcVerbose("processor count: %d", os::_processor_count);
- trcVerbose("physical memory: %lu", Aix::_physical_memory);
+ trcVerbose("physical memory: " PHYS_MEM_TYPE_FORMAT, Aix::_physical_memory);
// Initially build up the loaded dll map.
LoadedLibraries::reload();
diff --git a/src/hotspot/os/aix/os_aix.hpp b/src/hotspot/os/aix/os_aix.hpp
index 8cb49b5fe74a..7e47ced50887 100644
--- a/src/hotspot/os/aix/os_aix.hpp
+++ b/src/hotspot/os/aix/os_aix.hpp
@@ -35,7 +35,7 @@ class os::Aix {
private:
- static julong _physical_memory;
+ static physical_memory_size_type _physical_memory;
static pthread_t _main_thread;
// -1 = uninitialized, 0 = AIX, 1 = OS/400 (PASE)
@@ -58,9 +58,9 @@ class os::Aix {
// 1 - EXTSHM=ON
static int _extshm;
- static julong available_memory();
- static julong free_memory();
- static julong physical_memory() { return _physical_memory; }
+ static bool available_memory(physical_memory_size_type& value);
+ static bool free_memory(physical_memory_size_type& value);
+ static physical_memory_size_type physical_memory() { return _physical_memory; }
static void initialize_system_info();
// OS recognitions (PASE/AIX, OS level) call this before calling any
diff --git a/src/hotspot/os/bsd/os_bsd.cpp b/src/hotspot/os/bsd/os_bsd.cpp
index 155920e0a5a2..4db4c9c3a085 100644
--- a/src/hotspot/os/bsd/os_bsd.cpp
+++ b/src/hotspot/os/bsd/os_bsd.cpp
@@ -120,7 +120,7 @@
////////////////////////////////////////////////////////////////////////////////
// global variables
-julong os::Bsd::_physical_memory = 0;
+physical_memory_size_type os::Bsd::_physical_memory = 0;
#ifdef __APPLE__
mach_timebase_info_data_t os::Bsd::_timebase_info = {0, 0};
@@ -139,17 +139,17 @@ static volatile int processor_id_next = 0;
////////////////////////////////////////////////////////////////////////////////
// utility functions
-julong os::available_memory() {
- return Bsd::available_memory();
+bool os::available_memory(physical_memory_size_type& value) {
+ return Bsd::available_memory(value);
}
-julong os::free_memory() {
- return Bsd::available_memory();
+bool os::free_memory(physical_memory_size_type& value) {
+ return Bsd::available_memory(value);
}
// available here means free
-julong os::Bsd::available_memory() {
- uint64_t available = physical_memory() >> 2;
+bool os::Bsd::available_memory(physical_memory_size_type& value) {
+ physical_memory_size_type available = physical_memory() >> 2;
#ifdef __APPLE__
mach_msg_type_number_t count = HOST_VM_INFO64_COUNT;
vm_statistics64_data_t vmstat;
@@ -159,9 +159,12 @@ julong os::Bsd::available_memory() {
"host_statistics64 failed - check mach_host_self() and count");
if (kerr == KERN_SUCCESS) {
available = vmstat.free_count * os::vm_page_size();
+ } else {
+ return false;
}
#endif
- return available;
+ value = available;
+ return true;
}
// for more info see :
@@ -180,7 +183,7 @@ void os::Bsd::print_uptime_info(outputStream* st) {
}
}
-julong os::physical_memory() {
+physical_memory_size_type os::physical_memory() {
return Bsd::physical_memory();
}
@@ -254,7 +257,7 @@ void os::Bsd::initialize_system_info() {
len = sizeof(mem_val);
if (sysctl(mib, 2, &mem_val, &len, nullptr, 0) != -1) {
assert(len == sizeof(mem_val), "unexpected data size");
- _physical_memory = mem_val;
+ _physical_memory = static_cast(mem_val);
} else {
_physical_memory = 256 * 1024 * 1024; // fallback (XXXBSD?)
}
@@ -265,7 +268,7 @@ void os::Bsd::initialize_system_info() {
// datasize rlimit restricts us anyway.
struct rlimit limits;
getrlimit(RLIMIT_DATA, &limits);
- _physical_memory = MIN2(_physical_memory, (julong)limits.rlim_cur);
+ _physical_memory = MIN2(_physical_memory, static_cast(limits.rlim_cur));
}
#endif
}
@@ -987,6 +990,8 @@ void *os::Bsd::dlopen_helper(const char *filename, int mode) {
assert(rtn == 0, "fegetenv must succeed");
#endif // IA32
+ Events::log_dll_message(nullptr, "Attempting to load shared library %s", filename);
+
void * result= ::dlopen(filename, RTLD_LAZY);
#ifndef IA32
@@ -1415,10 +1420,13 @@ void os::print_memory_info(outputStream* st) {
st->print("Memory:");
st->print(" " SIZE_FORMAT "k page", os::vm_page_size()>>10);
- st->print(", physical " UINT64_FORMAT "k",
- os::physical_memory() >> 10);
- st->print("(" UINT64_FORMAT "k free)",
- os::available_memory() >> 10);
+ physical_memory_size_type phys_mem = os::physical_memory();
+ st->print(", physical " PHYS_MEM_TYPE_FORMAT "k",
+ phys_mem >> 10);
+ physical_memory_size_type avail_mem = 0;
+ (void)os::available_memory(avail_mem);
+ st->print("(" PHYS_MEM_TYPE_FORMAT "k free)",
+ avail_mem >> 10);
if((sysctlbyname("vm.swapusage", &swap_usage, &size, nullptr, 0) == 0) || (errno == ENOMEM)) {
if (size >= offset_of(xsw_usage, xsu_used)) {
diff --git a/src/hotspot/os/bsd/os_bsd.hpp b/src/hotspot/os/bsd/os_bsd.hpp
index f79212bc43c0..f8317ed0c8d7 100644
--- a/src/hotspot/os/bsd/os_bsd.hpp
+++ b/src/hotspot/os/bsd/os_bsd.hpp
@@ -42,12 +42,12 @@ class os::Bsd {
protected:
- static julong _physical_memory;
+ static physical_memory_size_type _physical_memory;
static pthread_t _main_thread;
- static julong available_memory();
- static julong free_memory();
- static julong physical_memory() { return _physical_memory; }
+ static bool available_memory(physical_memory_size_type& value);
+ static bool free_memory(physical_memory_size_type& value);
+ static physical_memory_size_type physical_memory() { return _physical_memory; }
static void initialize_system_info();
static void rebuild_cpu_to_node_map();
diff --git a/src/hotspot/os/linux/cgroupSubsystem_linux.cpp b/src/hotspot/os/linux/cgroupSubsystem_linux.cpp
index 1186c78b865a..99648021a5b1 100644
--- a/src/hotspot/os/linux/cgroupSubsystem_linux.cpp
+++ b/src/hotspot/os/linux/cgroupSubsystem_linux.cpp
@@ -62,7 +62,7 @@ CgroupSubsystem* CgroupSubsystemFactory::create() {
CgroupV1MemoryController* memory = nullptr;
CgroupV1Controller* cpuset = nullptr;
CgroupV1CpuController* cpu = nullptr;
- CgroupV1Controller* cpuacct = nullptr;
+ CgroupV1CpuacctController* cpuacct = nullptr;
CgroupV1Controller* pids = nullptr;
CgroupInfo cg_infos[CG_INFO_LENGTH];
u1 cg_type_flags = INVALID_CGROUPS_GENERIC;
@@ -105,9 +105,10 @@ CgroupSubsystem* CgroupSubsystemFactory::create() {
CgroupV2CpuController* cpu = new CgroupV2CpuController(CgroupV2Controller(cg_infos[CPU_IDX]._mount_path,
cg_infos[CPU_IDX]._cgroup_path,
cg_infos[CPU_IDX]._read_only));
+ CgroupV2CpuacctController* cpuacct = new CgroupV2CpuacctController(cpu);
log_debug(os, container)("Detected cgroups v2 unified hierarchy");
cleanup(cg_infos);
- return new CgroupV2Subsystem(memory, cpu, mem_other);
+ return new CgroupV2Subsystem(memory, cpu, cpuacct, mem_other);
}
/*
@@ -150,7 +151,7 @@ CgroupSubsystem* CgroupSubsystemFactory::create() {
cpu = new CgroupV1CpuController(CgroupV1Controller(info._root_mount_path, info._mount_path, info._read_only));
cpu->set_subsystem_path(info._cgroup_path);
} else if (strcmp(info._name, "cpuacct") == 0) {
- cpuacct = new CgroupV1Controller(info._root_mount_path, info._mount_path, info._read_only);
+ cpuacct = new CgroupV1CpuacctController(CgroupV1Controller(info._root_mount_path, info._mount_path, info._read_only));
cpuacct->set_subsystem_path(info._cgroup_path);
} else if (strcmp(info._name, "pids") == 0) {
pids = new CgroupV1Controller(info._root_mount_path, info._mount_path, info._read_only);
@@ -669,8 +670,8 @@ jlong CgroupSubsystem::memory_limit_in_bytes() {
if (!memory_limit->should_check_metric()) {
return memory_limit->value();
}
- jlong phys_mem = os::Linux::physical_memory();
- log_trace(os, container)("total physical memory: " JLONG_FORMAT, phys_mem);
+ julong phys_mem = static_cast(os::Linux::physical_memory());
+ log_trace(os, container)("total physical memory: " JULONG_FORMAT, phys_mem);
jlong mem_limit = contrl->controller()->read_memory_limit_in_bytes(phys_mem);
// Update cached metric to avoid re-reading container settings too often
memory_limit->set_value(mem_limit, OSCONTAINER_CACHE_TIMEOUT);
@@ -840,16 +841,20 @@ jlong CgroupController::limit_from_str(char* limit_str) {
// CgroupSubsystem implementations
jlong CgroupSubsystem::memory_and_swap_limit_in_bytes() {
- julong phys_mem = os::Linux::physical_memory();
+ julong phys_mem = static_cast(os::Linux::physical_memory());
julong host_swap = os::Linux::host_swap();
return memory_controller()->controller()->memory_and_swap_limit_in_bytes(phys_mem, host_swap);
}
jlong CgroupSubsystem::memory_soft_limit_in_bytes() {
- julong phys_mem = os::Linux::physical_memory();
+ julong phys_mem = static_cast(os::Linux::physical_memory());
return memory_controller()->controller()->memory_soft_limit_in_bytes(phys_mem);
}
+jlong CgroupSubsystem::memory_throttle_limit_in_bytes() {
+ return memory_controller()->controller()->memory_throttle_limit_in_bytes();
+}
+
jlong CgroupSubsystem::memory_usage_in_bytes() {
return memory_controller()->controller()->memory_usage_in_bytes();
}
@@ -878,7 +883,11 @@ int CgroupSubsystem::cpu_shares() {
return cpu_controller()->controller()->cpu_shares();
}
+jlong CgroupSubsystem::cpu_usage_in_micros() {
+ return cpuacct_controller()->cpu_usage_in_micros();
+}
+
void CgroupSubsystem::print_version_specific_info(outputStream* st) {
- julong phys_mem = os::Linux::physical_memory();
+ julong phys_mem = static_cast(os::Linux::physical_memory());
memory_controller()->controller()->print_version_specific_info(st, phys_mem);
}
diff --git a/src/hotspot/os/linux/cgroupSubsystem_linux.hpp b/src/hotspot/os/linux/cgroupSubsystem_linux.hpp
index 6b32408f801c..13db41d1fa6e 100644
--- a/src/hotspot/os/linux/cgroupSubsystem_linux.hpp
+++ b/src/hotspot/os/linux/cgroupSubsystem_linux.hpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2019, 2023, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2019, 2025, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -227,6 +227,18 @@ class CgroupCpuController: public CHeapObj {
virtual const char* cgroup_path() = 0;
};
+// Pure virtual class representing version agnostic CPU accounting controllers
+class CgroupCpuacctController: public CHeapObj {
+ public:
+ virtual jlong cpu_usage_in_micros() = 0;
+ virtual bool needs_hierarchy_adjustment() = 0;
+ virtual bool is_read_only() = 0;
+ virtual const char* subsystem_path() = 0;
+ virtual void set_subsystem_path(const char* cgroup_path) = 0;
+ virtual const char* mount_point() = 0;
+ virtual const char* cgroup_path() = 0;
+};
+
// Pure virtual class representing version agnostic memory controllers
class CgroupMemoryController: public CHeapObj {
public:
@@ -234,6 +246,7 @@ class CgroupMemoryController: public CHeapObj {
virtual jlong memory_usage_in_bytes() = 0;
virtual jlong memory_and_swap_limit_in_bytes(julong host_mem, julong host_swap) = 0;
virtual jlong memory_soft_limit_in_bytes(julong upper_bound) = 0;
+ virtual jlong memory_throttle_limit_in_bytes() = 0;
virtual jlong memory_max_usage_in_bytes() = 0;
virtual jlong rss_usage_in_bytes() = 0;
virtual jlong cache_usage_in_bytes() = 0;
@@ -260,14 +273,18 @@ class CgroupSubsystem: public CHeapObj {
virtual const char * container_type() = 0;
virtual CachingCgroupController* memory_controller() = 0;
virtual CachingCgroupController* cpu_controller() = 0;
+ virtual CgroupCpuacctController* cpuacct_controller() = 0;
int cpu_quota();
int cpu_period();
int cpu_shares();
+ jlong cpu_usage_in_micros();
+
jlong memory_usage_in_bytes();
jlong memory_and_swap_limit_in_bytes();
jlong memory_soft_limit_in_bytes();
+ jlong memory_throttle_limit_in_bytes();
jlong memory_max_usage_in_bytes();
jlong rss_usage_in_bytes();
jlong cache_usage_in_bytes();
diff --git a/src/hotspot/os/linux/cgroupUtil_linux.cpp b/src/hotspot/os/linux/cgroupUtil_linux.cpp
index b52ef87dcaee..72dda36504d3 100644
--- a/src/hotspot/os/linux/cgroupUtil_linux.cpp
+++ b/src/hotspot/os/linux/cgroupUtil_linux.cpp
@@ -65,7 +65,7 @@ void CgroupUtil::adjust_controller(CgroupMemoryController* mem) {
char* cg_path = os::strdup(orig);
char* last_slash;
assert(cg_path[0] == '/', "cgroup path must start with '/'");
- julong phys_mem = os::Linux::physical_memory();
+ julong phys_mem = static_cast(os::Linux::physical_memory());
char* limit_cg_path = nullptr;
jlong limit = mem->read_memory_limit_in_bytes(phys_mem);
jlong lowest_limit = limit < 0 ? phys_mem : limit;
diff --git a/src/hotspot/os/linux/cgroupV1Subsystem_linux.cpp b/src/hotspot/os/linux/cgroupV1Subsystem_linux.cpp
index 8c8f558116a0..75544ff6059e 100644
--- a/src/hotspot/os/linux/cgroupV1Subsystem_linux.cpp
+++ b/src/hotspot/os/linux/cgroupV1Subsystem_linux.cpp
@@ -243,10 +243,16 @@ jlong CgroupV1MemoryController::memory_soft_limit_in_bytes(julong phys_mem) {
}
}
+jlong CgroupV1MemoryController::memory_throttle_limit_in_bytes() {
+ // Log this string at trace level so as to make tests happy.
+ log_trace(os, container)("Memory Throttle Limit is not supported.");
+ return OSCONTAINER_ERROR; // not supported
+}
+
// Constructor
CgroupV1Subsystem::CgroupV1Subsystem(CgroupV1Controller* cpuset,
CgroupV1CpuController* cpu,
- CgroupV1Controller* cpuacct,
+ CgroupV1CpuacctController* cpuacct,
CgroupV1Controller* pids,
CgroupV1MemoryController* memory) :
_cpuset(cpuset),
@@ -415,6 +421,13 @@ int CgroupV1CpuController::cpu_shares() {
return shares_int;
}
+jlong CgroupV1CpuacctController::cpu_usage_in_micros() {
+ julong cpu_usage;
+ CONTAINER_READ_NUMBER_CHECKED(reader(), "/cpuacct.usage", "CPU Usage", cpu_usage);
+ // Output is in nanoseconds, convert to microseconds.
+ return (jlong)cpu_usage / 1000;
+}
+
/* pids_max
*
* Return the maximum number of tasks available to the process
diff --git a/src/hotspot/os/linux/cgroupV1Subsystem_linux.hpp b/src/hotspot/os/linux/cgroupV1Subsystem_linux.hpp
index 250d0273fc4d..ad1feb38f9e2 100644
--- a/src/hotspot/os/linux/cgroupV1Subsystem_linux.hpp
+++ b/src/hotspot/os/linux/cgroupV1Subsystem_linux.hpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2019, 2024, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2019, 2025, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -81,6 +81,7 @@ class CgroupV1MemoryController final : public CgroupMemoryController {
jlong memory_usage_in_bytes() override;
jlong memory_and_swap_limit_in_bytes(julong host_mem, julong host_swap) override;
jlong memory_soft_limit_in_bytes(julong upper_bound) override;
+ jlong memory_throttle_limit_in_bytes() override;
jlong memory_max_usage_in_bytes() override;
jlong rss_usage_in_bytes() override;
jlong cache_usage_in_bytes() override;
@@ -140,12 +141,41 @@ class CgroupV1CpuController final : public CgroupCpuController {
}
};
+class CgroupV1CpuacctController final : public CgroupCpuacctController {
+
+ private:
+ CgroupV1Controller _reader;
+ CgroupV1Controller* reader() { return &_reader; }
+ public:
+ jlong cpu_usage_in_micros() override;
+ void set_subsystem_path(const char *cgroup_path) override {
+ reader()->set_subsystem_path(cgroup_path);
+ }
+ bool is_read_only() override {
+ return reader()->is_read_only();
+ }
+ const char* subsystem_path() override {
+ return reader()->subsystem_path();
+ }
+ const char* mount_point() override {
+ return reader()->mount_point();
+ }
+ bool needs_hierarchy_adjustment() override {
+ return reader()->needs_hierarchy_adjustment();
+ }
+ const char* cgroup_path() override { return reader()->cgroup_path(); }
+
+ public:
+ CgroupV1CpuacctController(const CgroupV1Controller& reader) : _reader(reader) {
+ }
+};
+
class CgroupV1Subsystem: public CgroupSubsystem {
public:
CgroupV1Subsystem(CgroupV1Controller* cpuset,
CgroupV1CpuController* cpu,
- CgroupV1Controller* cpuacct,
+ CgroupV1CpuacctController* cpuacct,
CgroupV1Controller* pids,
CgroupV1MemoryController* memory);
@@ -165,13 +195,14 @@ class CgroupV1Subsystem: public CgroupSubsystem {
}
CachingCgroupController* memory_controller() { return _memory; }
CachingCgroupController* cpu_controller() { return _cpu; }
+ CgroupCpuacctController* cpuacct_controller() { return _cpuacct; }
private:
/* controllers */
CachingCgroupController* _memory = nullptr;
CgroupV1Controller* _cpuset = nullptr;
CachingCgroupController* _cpu = nullptr;
- CgroupV1Controller* _cpuacct = nullptr;
+ CgroupV1CpuacctController* _cpuacct = nullptr;
CgroupV1Controller* _pids = nullptr;
};
diff --git a/src/hotspot/os/linux/cgroupV2Subsystem_linux.cpp b/src/hotspot/os/linux/cgroupV2Subsystem_linux.cpp
index 4367eba4c43a..395a78d4addc 100644
--- a/src/hotspot/os/linux/cgroupV2Subsystem_linux.cpp
+++ b/src/hotspot/os/linux/cgroupV2Subsystem_linux.cpp
@@ -1,5 +1,6 @@
/*
* Copyright (c) 2020, 2025, Red Hat Inc.
+ * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -25,6 +26,8 @@
#include "cgroupV2Subsystem_linux.hpp"
#include "cgroupUtil_linux.hpp"
+#include
+
// Constructor
CgroupV2Controller::CgroupV2Controller(char* mount_path,
char *cgroup_path,
@@ -60,22 +63,39 @@ int CgroupV2CpuController::cpu_shares() {
log_debug(os, container)("CPU Shares is: %d", -1);
return -1;
}
+ // cg v2 values must be in range [1-10000]
+ assert(shares_int >= 1 && shares_int <= 10000, "invariant");
// CPU shares (OCI) value needs to get translated into
// a proper Cgroups v2 value. See:
- // https://github.com/containers/crun/blob/master/crun.1.md#cpu-controller
+ // https://github.com/containers/crun/blob/1.24/crun.1.md#cpu-controller
//
// Use the inverse of (x == OCI value, y == cgroupsv2 value):
- // ((262142 * y - 1)/9999) + 2 = x
+ // y = 10^(log2(x)^2/612 + 125/612 * log2(x) - 7.0/34.0)
+ //
+ // By re-arranging it to the standard quadratic form:
+ // log2(x)^2 + 125 * log2(x) - (126 + 612 * log_10(y)) = 0
+ //
+ // Therefore, log2(x) = (-125 + sqrt( 125^2 - 4 * (-(126 + 612 * log_10(y)))))/2
//
- int x = 262142 * shares_int - 1;
- double frac = x/9999.0;
- x = ((int)frac) + 2;
+ // As a result we have the inverse (we can discount substraction of the
+ // square root value since those values result in very small numbers and the
+ // cpu shares values - OCI - are in range [2,262144]):
+ //
+ // x = 2^((-125 + sqrt(16129 + 2448* log10(y)))/2)
+ //
+ double log_multiplicand = log10(shares_int);
+ double discriminant = 16129 + 2448 * log_multiplicand;
+ double square_root = sqrt(discriminant);
+ double exponent = (-125 + square_root)/2;
+ double scaled_val = pow(2, exponent);
+ int x = (int) scaled_val;
log_trace(os, container)("Scaled CPU shares value is: %d", x);
// Since the scaled value is not precise, return the closest
// multiple of PER_CPU_SHARES for a more conservative mapping
if ( x <= PER_CPU_SHARES ) {
- // will always map to 1 CPU
+ // Don't do the multiples of PER_CPU_SHARES mapping since we
+ // have a value <= PER_CPU_SHARES
log_debug(os, container)("CPU Shares is: %d", x);
return x;
}
@@ -114,12 +134,14 @@ int CgroupV2CpuController::cpu_quota() {
// Constructor
CgroupV2Subsystem::CgroupV2Subsystem(CgroupV2MemoryController * memory,
CgroupV2CpuController* cpu,
+ CgroupV2CpuacctController* cpuacct,
CgroupV2Controller unified) :
_unified(unified) {
CgroupUtil::adjust_controller(memory);
CgroupUtil::adjust_controller(cpu);
_memory = new CachingCgroupController(memory);
_cpu = new CachingCgroupController(cpu);
+ _cpuacct = cpuacct;
}
bool CgroupV2Subsystem::is_containerized() {
@@ -152,6 +174,17 @@ int CgroupV2CpuController::cpu_period() {
return period;
}
+jlong CgroupV2CpuController::cpu_usage_in_micros() {
+ julong cpu_usage;
+ bool is_ok = reader()->read_numerical_key_value("/cpu.stat", "usage_usec", &cpu_usage);
+ if (!is_ok) {
+ log_trace(os, container)("CPU Usage failed: %d", OSCONTAINER_ERROR);
+ return OSCONTAINER_ERROR;
+ }
+ log_trace(os, container)("CPU Usage is: " JULONG_FORMAT, cpu_usage);
+ return (jlong)cpu_usage;
+}
+
/* memory_usage_in_bytes
*
* Return the amount of used memory used by this cgroup and descendents
@@ -173,10 +206,16 @@ jlong CgroupV2MemoryController::memory_soft_limit_in_bytes(julong phys_mem) {
return mem_soft_limit;
}
+jlong CgroupV2MemoryController::memory_throttle_limit_in_bytes() {
+ jlong mem_throttle_limit;
+ CONTAINER_READ_NUMBER_CHECKED_MAX(reader(), "/memory.high", "Memory Throttle Limit", mem_throttle_limit);
+ return mem_throttle_limit;
+}
+
jlong CgroupV2MemoryController::memory_max_usage_in_bytes() {
- // Log this string at trace level so as to make tests happy.
- log_trace(os, container)("Maximum Memory Usage is not supported.");
- return OSCONTAINER_ERROR; // not supported
+ julong mem_max_usage;
+ CONTAINER_READ_NUMBER_CHECKED(reader(), "/memory.peak", "Maximum Memory Usage", mem_max_usage);
+ return mem_max_usage;
}
jlong CgroupV2MemoryController::rss_usage_in_bytes() {
diff --git a/src/hotspot/os/linux/cgroupV2Subsystem_linux.hpp b/src/hotspot/os/linux/cgroupV2Subsystem_linux.hpp
index 0a053fa7e45e..2915aea01896 100644
--- a/src/hotspot/os/linux/cgroupV2Subsystem_linux.hpp
+++ b/src/hotspot/os/linux/cgroupV2Subsystem_linux.hpp
@@ -1,5 +1,6 @@
/*
* Copyright (c) 2020, 2024, Red Hat Inc.
+ * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -61,6 +62,34 @@ class CgroupV2CpuController: public CgroupCpuController {
int cpu_quota() override;
int cpu_period() override;
int cpu_shares() override;
+ jlong cpu_usage_in_micros();
+ bool is_read_only() override {
+ return reader()->is_read_only();
+ }
+ const char* subsystem_path() override {
+ return reader()->subsystem_path();
+ }
+ bool needs_hierarchy_adjustment() override {
+ return reader()->needs_hierarchy_adjustment();
+ }
+ void set_subsystem_path(const char* cgroup_path) override {
+ reader()->set_subsystem_path(cgroup_path);
+ }
+ const char* mount_point() override { return reader()->mount_point(); }
+ const char* cgroup_path() override { return reader()->cgroup_path(); }
+};
+
+class CgroupV2CpuacctController: public CgroupCpuacctController {
+ private:
+ CgroupV2CpuController* _reader;
+ CgroupV2CpuController* reader() { return _reader; }
+ public:
+ CgroupV2CpuacctController(CgroupV2CpuController* reader) : _reader(reader) {
+ }
+ // In cgroup v2, cpu usage is a part of the cpu controller.
+ jlong cpu_usage_in_micros() override {
+ return reader()->cpu_usage_in_micros();
+ }
bool is_read_only() override {
return reader()->is_read_only();
}
@@ -88,6 +117,7 @@ class CgroupV2MemoryController final: public CgroupMemoryController {
jlong read_memory_limit_in_bytes(julong upper_bound) override;
jlong memory_and_swap_limit_in_bytes(julong host_mem, julong host_swp) override;
jlong memory_soft_limit_in_bytes(julong upper_bound) override;
+ jlong memory_throttle_limit_in_bytes() override;
jlong memory_usage_in_bytes() override;
jlong memory_max_usage_in_bytes() override;
jlong rss_usage_in_bytes() override;
@@ -117,11 +147,14 @@ class CgroupV2Subsystem: public CgroupSubsystem {
CachingCgroupController* _memory = nullptr;
CachingCgroupController* _cpu = nullptr;
+ CgroupCpuacctController* _cpuacct = nullptr;
+
CgroupV2Controller* unified() { return &_unified; }
public:
CgroupV2Subsystem(CgroupV2MemoryController * memory,
CgroupV2CpuController* cpu,
+ CgroupV2CpuacctController* cpuacct,
CgroupV2Controller unified);
char * cpu_cpuset_cpus() override;
@@ -136,6 +169,7 @@ class CgroupV2Subsystem: public CgroupSubsystem {
}
CachingCgroupController* memory_controller() override { return _memory; }
CachingCgroupController* cpu_controller() override { return _cpu; }
+ CgroupCpuacctController* cpuacct_controller() override { return _cpuacct; };
};
#endif // CGROUP_V2_SUBSYSTEM_LINUX_HPP
diff --git a/src/hotspot/os/linux/osContainer_linux.cpp b/src/hotspot/os/linux/osContainer_linux.cpp
index 536869c785d9..8b91486122ca 100644
--- a/src/hotspot/os/linux/osContainer_linux.cpp
+++ b/src/hotspot/os/linux/osContainer_linux.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2017, 2023, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -117,6 +117,11 @@ jlong OSContainer::memory_soft_limit_in_bytes() {
return cgroup_subsystem->memory_soft_limit_in_bytes();
}
+jlong OSContainer::memory_throttle_limit_in_bytes() {
+ assert(cgroup_subsystem != nullptr, "cgroup subsystem not available");
+ return cgroup_subsystem->memory_throttle_limit_in_bytes();
+}
+
jlong OSContainer::memory_usage_in_bytes() {
assert(cgroup_subsystem != nullptr, "cgroup subsystem not available");
return cgroup_subsystem->memory_usage_in_bytes();
@@ -172,6 +177,11 @@ int OSContainer::cpu_shares() {
return cgroup_subsystem->cpu_shares();
}
+jlong OSContainer::cpu_usage_in_micros() {
+ assert(cgroup_subsystem != nullptr, "cgroup subsystem not available");
+ return cgroup_subsystem->cpu_usage_in_micros();
+}
+
jlong OSContainer::pids_max() {
assert(cgroup_subsystem != nullptr, "cgroup subsystem not available");
return cgroup_subsystem->pids_max();
diff --git a/src/hotspot/os/linux/osContainer_linux.hpp b/src/hotspot/os/linux/osContainer_linux.hpp
index bb03ba3b005a..56bd80cb8f96 100644
--- a/src/hotspot/os/linux/osContainer_linux.hpp
+++ b/src/hotspot/os/linux/osContainer_linux.hpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2017, 2022, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -53,6 +53,7 @@ class OSContainer: AllStatic {
static jlong memory_limit_in_bytes();
static jlong memory_and_swap_limit_in_bytes();
static jlong memory_soft_limit_in_bytes();
+ static jlong memory_throttle_limit_in_bytes();
static jlong memory_usage_in_bytes();
static jlong memory_max_usage_in_bytes();
static jlong rss_usage_in_bytes();
@@ -68,6 +69,8 @@ class OSContainer: AllStatic {
static int cpu_shares();
+ static jlong cpu_usage_in_micros();
+
static jlong pids_max();
static jlong pids_current();
};
diff --git a/src/hotspot/os/linux/os_linux.cpp b/src/hotspot/os/linux/os_linux.cpp
index b7389523017b..9edcb82cd200 100644
--- a/src/hotspot/os/linux/os_linux.cpp
+++ b/src/hotspot/os/linux/os_linux.cpp
@@ -161,7 +161,7 @@ enum CoredumpFilterBit {
////////////////////////////////////////////////////////////////////////////////
// global variables
-julong os::Linux::_physical_memory = 0;
+physical_memory_size_type os::Linux::_physical_memory = 0;
address os::Linux::_initial_thread_stack_bottom = nullptr;
uintptr_t os::Linux::_initial_thread_stack_size = 0;
@@ -236,15 +236,16 @@ julong os::Linux::available_memory_in_container() {
return avail_mem;
}
-julong os::available_memory() {
- return Linux::available_memory();
+bool os::available_memory(physical_memory_size_type& value) {
+ return Linux::available_memory(value);
}
-julong os::Linux::available_memory() {
+bool os::Linux::available_memory(physical_memory_size_type& value) {
julong avail_mem = available_memory_in_container();
if (avail_mem != static_cast(-1L)) {
log_trace(os)("available container memory: " JULONG_FORMAT, avail_mem);
- return avail_mem;
+ value = static_cast(avail_mem);
+ return true;
}
FILE *fp = os::fopen("/proc/meminfo", "r");
@@ -259,43 +260,52 @@ julong os::Linux::available_memory() {
fclose(fp);
}
if (avail_mem == static_cast(-1L)) {
- avail_mem = free_memory();
+ physical_memory_size_type free_mem = 0;
+ if (!free_memory(free_mem)) {
+ return false;
+ }
+ avail_mem = static_cast(free_mem);
}
log_trace(os)("available memory: " JULONG_FORMAT, avail_mem);
- return avail_mem;
+ value = static_cast(avail_mem);
+ return true;
}
-julong os::free_memory() {
- return Linux::free_memory();
+bool os::free_memory(physical_memory_size_type& value) {
+ return Linux::free_memory(value);
}
-julong os::Linux::free_memory() {
+bool os::Linux::free_memory(physical_memory_size_type& value) {
// values in struct sysinfo are "unsigned long"
struct sysinfo si;
julong free_mem = available_memory_in_container();
if (free_mem != static_cast(-1L)) {
log_trace(os)("free container memory: " JULONG_FORMAT, free_mem);
- return free_mem;
+ value = static_cast(free_mem);
+ return true;
}
- sysinfo(&si);
+ int ret = sysinfo(&si);
+ if (ret != 0) {
+ return false;
+ }
free_mem = (julong)si.freeram * si.mem_unit;
log_trace(os)("free memory: " JULONG_FORMAT, free_mem);
- return free_mem;
+ value = static_cast(free_mem);
+ return true;
}
-julong os::physical_memory() {
- jlong phys_mem = 0;
+physical_memory_size_type os::physical_memory() {
if (OSContainer::is_containerized()) {
jlong mem_limit;
if ((mem_limit = OSContainer::memory_limit_in_bytes()) > 0) {
log_trace(os)("total container memory: " JLONG_FORMAT, mem_limit);
- return mem_limit;
+ return static_cast(mem_limit);
}
}
- phys_mem = Linux::physical_memory();
- log_trace(os)("total system memory: " JLONG_FORMAT, phys_mem);
+ physical_memory_size_type phys_mem = Linux::physical_memory();
+ log_trace(os)("total system memory: " PHYS_MEM_TYPE_FORMAT, phys_mem);
return phys_mem;
}
@@ -452,7 +462,7 @@ void os::Linux::initialize_system_info() {
fclose(fp);
}
}
- _physical_memory = (julong)sysconf(_SC_PHYS_PAGES) * (julong)sysconf(_SC_PAGESIZE);
+ _physical_memory = static_cast(sysconf(_SC_PHYS_PAGES)) * static_cast(sysconf(_SC_PAGESIZE));
assert(processor_count() > 0, "linux error");
}
@@ -1832,6 +1842,8 @@ void * os::Linux::dlopen_helper(const char *filename, char *ebuf,
assert(rtn == 0, "fegetenv must succeed");
#endif // IA32
+ Events::log_dll_message(nullptr, "Attempting to load shared library %s", filename);
+
void * result = ::dlopen(filename, RTLD_LAZY);
if (result == nullptr) {
const char* error_report = ::dlerror();
@@ -2379,9 +2391,18 @@ bool os::Linux::print_container_info(outputStream* st) {
st->print_cr("%s", i == OSCONTAINER_ERROR ? "not supported" : "no shares");
}
+ jlong j = OSContainer::cpu_usage_in_micros();
+ st->print("cpu_usage_in_micros: ");
+ if (j >= 0) {
+ st->print_cr(JLONG_FORMAT, j);
+ } else {
+ st->print_cr("%s", j == OSCONTAINER_ERROR ? "not supported" : "no usage");
+ }
+
OSContainer::print_container_helper(st, OSContainer::memory_limit_in_bytes(), "memory_limit_in_bytes");
OSContainer::print_container_helper(st, OSContainer::memory_and_swap_limit_in_bytes(), "memory_and_swap_limit_in_bytes");
OSContainer::print_container_helper(st, OSContainer::memory_soft_limit_in_bytes(), "memory_soft_limit_in_bytes");
+ OSContainer::print_container_helper(st, OSContainer::memory_throttle_limit_in_bytes(), "memory_throttle_limit_in_bytes");
OSContainer::print_container_helper(st, OSContainer::memory_usage_in_bytes(), "memory_usage_in_bytes");
OSContainer::print_container_helper(st, OSContainer::memory_max_usage_in_bytes(), "memory_max_usage_in_bytes");
OSContainer::print_container_helper(st, OSContainer::rss_usage_in_bytes(), "rss_usage_in_bytes");
@@ -2389,7 +2410,7 @@ bool os::Linux::print_container_info(outputStream* st) {
OSContainer::print_version_specific_info(st);
- jlong j = OSContainer::pids_max();
+ j = OSContainer::pids_max();
st->print("maximum number of tasks: ");
if (j > 0) {
st->print_cr(JLONG_FORMAT, j);
@@ -2436,11 +2457,13 @@ void os::print_memory_info(outputStream* st) {
// values in struct sysinfo are "unsigned long"
struct sysinfo si;
sysinfo(&si);
-
- st->print(", physical " UINT64_FORMAT "k",
- os::physical_memory() >> 10);
- st->print("(" UINT64_FORMAT "k free)",
- os::available_memory() >> 10);
+ physical_memory_size_type phys_mem = physical_memory();
+ st->print(", physical " PHYS_MEM_TYPE_FORMAT "k",
+ phys_mem >> 10);
+ physical_memory_size_type avail_mem = 0;
+ (void)os::available_memory(avail_mem);
+ st->print("(" PHYS_MEM_TYPE_FORMAT "k free)",
+ avail_mem >> 10);
st->print(", swap " UINT64_FORMAT "k",
((jlong)si.totalswap * si.mem_unit) >> 10);
st->print("(" UINT64_FORMAT "k free)",
@@ -5392,7 +5415,7 @@ int os::get_core_path(char* buffer, size_t bufferSize) {
if (core_pattern[0] == '|') {
written = jio_snprintf(buffer, bufferSize,
- "\"%s\" (or dumping to %s/core.%d)",
+ "\"%s\" (alternatively, falling back to %s/core.%d)",
&core_pattern[1], p, current_process_id());
} else if (pid_pos != nullptr) {
*pid_pos = '\0';
diff --git a/src/hotspot/os/linux/os_linux.hpp b/src/hotspot/os/linux/os_linux.hpp
index 49f2777d1396..ed6c52aade44 100644
--- a/src/hotspot/os/linux/os_linux.hpp
+++ b/src/hotspot/os/linux/os_linux.hpp
@@ -51,11 +51,11 @@ class os::Linux {
protected:
- static julong _physical_memory;
+ static physical_memory_size_type _physical_memory;
static pthread_t _main_thread;
- static julong available_memory();
- static julong free_memory();
+ static bool available_memory(physical_memory_size_type& value);
+ static bool free_memory(physical_memory_size_type& value);
static void initialize_system_info();
@@ -127,7 +127,7 @@ class os::Linux {
static address initial_thread_stack_bottom(void) { return _initial_thread_stack_bottom; }
static uintptr_t initial_thread_stack_size(void) { return _initial_thread_stack_size; }
- static julong physical_memory() { return _physical_memory; }
+ static physical_memory_size_type physical_memory() { return _physical_memory; }
static julong host_swap();
static intptr_t* ucontext_get_sp(const ucontext_t* uc);
diff --git a/src/hotspot/os/posix/os_posix.cpp b/src/hotspot/os/posix/os_posix.cpp
index 7f95560a19e1..7d139712002c 100644
--- a/src/hotspot/os/posix/os_posix.cpp
+++ b/src/hotspot/os/posix/os_posix.cpp
@@ -105,49 +105,63 @@ static int clock_tics_per_sec = 100;
size_t os::_os_min_stack_allowed = PTHREAD_STACK_MIN;
// Check core dump limit and report possible place where core can be found
-void os::check_dump_limit(char* buffer, size_t bufferSize) {
+void os::check_core_dump_prerequisites(char* buffer, size_t bufferSize, bool check_only) {
+ stringStream buf(buffer, bufferSize);
if (!FLAG_IS_DEFAULT(CreateCoredumpOnCrash) && !CreateCoredumpOnCrash) {
- jio_snprintf(buffer, bufferSize, "CreateCoredumpOnCrash is disabled from command line");
- VMError::record_coredump_status(buffer, false);
- return;
- }
-
- int n;
- struct rlimit rlim;
- bool success;
-
- char core_path[PATH_MAX];
- n = get_core_path(core_path, PATH_MAX);
-
- if (n <= 0) {
- jio_snprintf(buffer, bufferSize, "core.%d (may not exist)", current_process_id());
- success = true;
+ buf.print("CreateCoredumpOnCrash is disabled from command line");
+ VMError::record_coredump_status(buf.freeze(), false);
+ } else {
+ struct rlimit rlim;
+ bool success = true;
+ bool warn = true;
+ char core_path[PATH_MAX];
+ if (get_core_path(core_path, PATH_MAX) <= 0) {
+ // In the warning message, let the user know.
+ if (check_only) {
+ buf.print("the core path couldn't be determined. It commonly defaults to ");
+ }
+ buf.print("core.%d%s", current_process_id(), check_only ? "" : " (may not exist)");
#ifdef LINUX
- } else if (core_path[0] == '"') { // redirect to user process
- jio_snprintf(buffer, bufferSize, "Core dumps may be processed with %s", core_path);
- success = true;
+ } else if (core_path[0] == '"') { // redirect to user process
+ if (check_only) {
+ buf.print("core dumps may be further processed by the following: ");
+ } else {
+ buf.print("Determined by the following: ");
+ }
+ buf.print("%s", core_path);
#endif
- } else if (getrlimit(RLIMIT_CORE, &rlim) != 0) {
- jio_snprintf(buffer, bufferSize, "%s (may not exist)", core_path);
- success = true;
- } else {
- switch(rlim.rlim_cur) {
- case RLIM_INFINITY:
- jio_snprintf(buffer, bufferSize, "%s", core_path);
- success = true;
- break;
- case 0:
- jio_snprintf(buffer, bufferSize, "Core dumps have been disabled. To enable core dumping, try \"ulimit -c unlimited\" before starting Java again");
- success = false;
- break;
- default:
- jio_snprintf(buffer, bufferSize, "%s (max size " UINT64_FORMAT " k). To ensure a full core dump, try \"ulimit -c unlimited\" before starting Java again", core_path, uint64_t(rlim.rlim_cur) / K);
- success = true;
- break;
+ } else if (getrlimit(RLIMIT_CORE, &rlim) != 0) {
+ if (check_only) {
+ buf.print("the rlimit couldn't be determined. If resource limits permit, the core dump will be located at ");
+ }
+ buf.print("%s%s", core_path, check_only ? "" : " (may not exist)");
+ } else {
+ switch(rlim.rlim_cur) {
+ case RLIM_INFINITY:
+ buf.print("%s", core_path);
+ warn = false;
+ break;
+ case 0:
+ buf.print("%s dumps have been disabled. To enable core dumping, try \"ulimit -c unlimited\" before starting Java again", check_only ? "core" : "Core");
+ success = false;
+ break;
+ default:
+ if (check_only) {
+ buf.print("core dumps are constrained ");
+ } else {
+ buf.print( "%s ", core_path);
+ }
+ buf.print( "(max size " UINT64_FORMAT " k). To ensure a full core dump, try \"ulimit -c unlimited\" before starting Java again", uint64_t(rlim.rlim_cur) / K);
+ break;
+ }
+ }
+ const char* result = buf.freeze();
+ if (!check_only) {
+ VMError::record_coredump_status(result, success);
+ } else if (warn) {
+ warning("CreateCoredumpOnCrash specified, but %s", result);
}
}
-
- VMError::record_coredump_status(buffer, success);
}
int os::get_native_stack(address* stack, int frames, int toSkip) {
diff --git a/src/hotspot/os/posix/perfMemory_posix.cpp b/src/hotspot/os/posix/perfMemory_posix.cpp
index 7c39c5af466d..790db31348c3 100644
--- a/src/hotspot/os/posix/perfMemory_posix.cpp
+++ b/src/hotspot/os/posix/perfMemory_posix.cpp
@@ -112,6 +112,10 @@ static void save_memory_to_file(char* addr, size_t size) {
result = ::close(fd);
if (result == OS_ERR) {
warning("Could not close %s: %s\n", destfile, os::strerror(errno));
+ } else {
+ if (!successful_write) {
+ remove(destfile);
+ }
}
}
FREE_C_HEAP_ARRAY(char, destfile);
@@ -954,6 +958,7 @@ static int create_sharedmem_file(const char* dirname, const char* filename, size
warning("Insufficient space for shared memory file:\n %s\nTry using the -Djava.io.tmpdir= option to select an alternate temp location.\n", filename);
}
result = OS_ERR;
+ remove(filename);
break;
}
}
diff --git a/src/hotspot/os/windows/os_windows.cpp b/src/hotspot/os/windows/os_windows.cpp
index 669e96e54058..3f82eaa053a0 100644
--- a/src/hotspot/os/windows/os_windows.cpp
+++ b/src/hotspot/os/windows/os_windows.cpp
@@ -832,25 +832,30 @@ jlong os::elapsed_frequency() {
}
-julong os::available_memory() {
- return win32::available_memory();
+bool os::available_memory(physical_memory_size_type& value) {
+ return win32::available_memory(value);
}
-julong os::free_memory() {
- return win32::available_memory();
+bool os::free_memory(physical_memory_size_type& value) {
+ return win32::available_memory(value);
}
-julong os::win32::available_memory() {
+bool os::win32::available_memory(physical_memory_size_type& value) {
// Use GlobalMemoryStatusEx() because GlobalMemoryStatus() may return incorrect
// value if total memory is larger than 4GB
MEMORYSTATUSEX ms;
ms.dwLength = sizeof(ms);
- GlobalMemoryStatusEx(&ms);
-
- return (julong)ms.ullAvailPhys;
+ BOOL res = GlobalMemoryStatusEx(&ms);
+ if (res == TRUE) {
+ value = static_cast(ms.ullAvailPhys);
+ return true;
+ } else {
+ assert(false, "GlobalMemoryStatusEx failed in os::win32::available_memory(): %lu", ::GetLastError());
+ return false;
+ }
}
-julong os::physical_memory() {
+physical_memory_size_type os::physical_memory() {
return win32::physical_memory();
}
@@ -1269,38 +1274,50 @@ void os::shutdown() {
static HANDLE dumpFile = nullptr;
-// Check if dump file can be created.
-void os::check_dump_limit(char* buffer, size_t buffsz) {
- bool status = true;
+// Check if core dump is active and if a core dump file can be created
+void os::check_core_dump_prerequisites(char* buffer, size_t bufferSize, bool check_only) {
if (!FLAG_IS_DEFAULT(CreateCoredumpOnCrash) && !CreateCoredumpOnCrash) {
- jio_snprintf(buffer, buffsz, "CreateCoredumpOnCrash is disabled from command line");
- status = false;
- }
-
+ jio_snprintf(buffer, bufferSize, "CreateCoredumpOnCrash is disabled from command line");
+ VMError::record_coredump_status(buffer, false);
+ } else {
+ bool success = true;
+ bool warn = true;
#ifndef ASSERT
- if (!os::win32::is_windows_server() && FLAG_IS_DEFAULT(CreateCoredumpOnCrash)) {
- jio_snprintf(buffer, buffsz, "Minidumps are not enabled by default on client versions of Windows");
- status = false;
- }
+ if (!os::win32::is_windows_server() && FLAG_IS_DEFAULT(CreateCoredumpOnCrash)) {
+ jio_snprintf(buffer, bufferSize, "Minidumps are not enabled by default on client versions of Windows");
+ success = false;
+ warn = true;
+ }
#endif
- if (status) {
- const char* cwd = get_current_directory(nullptr, 0);
- int pid = current_process_id();
- if (cwd != nullptr) {
- jio_snprintf(buffer, buffsz, "%s\\hs_err_pid%u.mdmp", cwd, pid);
- } else {
- jio_snprintf(buffer, buffsz, ".\\hs_err_pid%u.mdmp", pid);
+ if (success) {
+ if (!check_only) {
+ const char* cwd = get_current_directory(nullptr, 0);
+ int pid = current_process_id();
+ if (cwd != nullptr) {
+ jio_snprintf(buffer, bufferSize, "%s\\hs_err_pid%u.mdmp", cwd, pid);
+ } else {
+ jio_snprintf(buffer, bufferSize, ".\\hs_err_pid%u.mdmp", pid);
+ }
+
+ if (dumpFile == nullptr &&
+ (dumpFile = CreateFile(buffer, GENERIC_WRITE, 0, nullptr, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, nullptr))
+ == INVALID_HANDLE_VALUE) {
+ jio_snprintf(buffer, bufferSize, "Failed to create minidump file (0x%x).", GetLastError());
+ success = false;
+ }
+ } else {
+ // For now on Windows, there are no more checks that we can do
+ warn = false;
+ }
}
- if (dumpFile == nullptr &&
- (dumpFile = CreateFile(buffer, GENERIC_WRITE, 0, nullptr, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, nullptr))
- == INVALID_HANDLE_VALUE) {
- jio_snprintf(buffer, buffsz, "Failed to create minidump file (0x%x).", GetLastError());
- status = false;
+ if (!check_only) {
+ VMError::record_coredump_status(buffer, success);
+ } else if (warn) {
+ warning("CreateCoredumpOnCrash specified, but %s", buffer);
}
}
- VMError::record_coredump_status(buffer, status);
}
void os::abort(bool dump_core, void* siginfo, const void* context) {
@@ -1844,6 +1861,7 @@ void * os::dll_load_utf8(const char *utf8_name, char *ebuf, int ebuflen) {
void * os::dll_load(const char *name, char *ebuf, int ebuflen) {
log_info(os)("attempting shared library load of %s", name);
+ Events::log_dll_message(nullptr, "Attempting to load shared library %s", name);
void * result = LoadLibrary(name);
if (result != nullptr) {
@@ -4274,25 +4292,25 @@ int os::current_process_id() {
return (_initial_pid ? _initial_pid : _getpid());
}
-int os::win32::_processor_type = 0;
+int os::win32::_processor_type = 0;
// Processor level is not available on non-NT systems, use vm_version instead
-int os::win32::_processor_level = 0;
-julong os::win32::_physical_memory = 0;
+int os::win32::_processor_level = 0;
+physical_memory_size_type os::win32::_physical_memory = 0;
-bool os::win32::_is_windows_server = false;
+bool os::win32::_is_windows_server = false;
// 6573254
// Currently, the bug is observed across all the supported Windows releases,
// including the latest one (as of this writing - Windows Server 2012 R2)
-bool os::win32::_has_exit_bug = true;
+bool os::win32::_has_exit_bug = true;
-int os::win32::_major_version = 0;
-int os::win32::_minor_version = 0;
-int os::win32::_build_number = 0;
-int os::win32::_build_minor = 0;
+int os::win32::_major_version = 0;
+int os::win32::_minor_version = 0;
+int os::win32::_build_number = 0;
+int os::win32::_build_minor = 0;
-bool os::win32::_processor_group_warning_displayed = false;
-bool os::win32::_job_object_processor_group_warning_displayed = false;
+bool os::win32::_processor_group_warning_displayed = false;
+bool os::win32::_job_object_processor_group_warning_displayed = false;
void getWindowsInstallationType(char* buffer, int bufferSize) {
HKEY hKey;
@@ -4507,8 +4525,11 @@ void os::win32::initialize_system_info() {
// also returns dwAvailPhys (free physical memory bytes), dwTotalVirtual, dwAvailVirtual,
// dwMemoryLoad (% of memory in use)
- GlobalMemoryStatusEx(&ms);
- _physical_memory = ms.ullTotalPhys;
+ BOOL res = GlobalMemoryStatusEx(&ms);
+ if (res != TRUE) {
+ assert(false, "GlobalMemoryStatusEx failed in os::win32::initialize_system_info(): %lu", ::GetLastError());
+ }
+ _physical_memory = static_cast(ms.ullTotalPhys);
if (FLAG_IS_DEFAULT(MaxRAM)) {
// Adjust MaxRAM according to the maximum virtual address space available.
diff --git a/src/hotspot/os/windows/os_windows.hpp b/src/hotspot/os/windows/os_windows.hpp
index c4e5483ce8e3..abbccbf234cb 100644
--- a/src/hotspot/os/windows/os_windows.hpp
+++ b/src/hotspot/os/windows/os_windows.hpp
@@ -38,18 +38,18 @@ class os::win32 {
friend class os;
protected:
- static int _processor_type;
- static int _processor_level;
- static julong _physical_memory;
- static bool _is_windows_server;
- static bool _has_exit_bug;
- static bool _processor_group_warning_displayed;
- static bool _job_object_processor_group_warning_displayed;
-
- static int _major_version;
- static int _minor_version;
- static int _build_number;
- static int _build_minor;
+ static int _processor_type;
+ static int _processor_level;
+ static physical_memory_size_type _physical_memory;
+ static bool _is_windows_server;
+ static bool _has_exit_bug;
+ static bool _processor_group_warning_displayed;
+ static bool _job_object_processor_group_warning_displayed;
+
+ static int _major_version;
+ static int _minor_version;
+ static int _build_number;
+ static int _build_minor;
static void print_windows_version(outputStream* st);
static void print_uptime_info(outputStream* st);
@@ -102,9 +102,9 @@ class os::win32 {
static int processor_level() {
return _processor_level;
}
- static julong available_memory();
- static julong free_memory();
- static julong physical_memory() { return _physical_memory; }
+ static bool available_memory(physical_memory_size_type& value);
+ static bool free_memory(physical_memory_size_type& value);
+ static physical_memory_size_type physical_memory() { return _physical_memory; }
// load dll from Windows system directory or Windows directory
static HINSTANCE load_Windows_dll(const char* name, char *ebuf, int ebuflen);
diff --git a/src/hotspot/os_cpu/linux_arm/macroAssembler_linux_arm_32.cpp b/src/hotspot/os_cpu/linux_arm/macroAssembler_linux_arm_32.cpp
index 0a3968ffa706..f8c59cbcc5d1 100644
--- a/src/hotspot/os_cpu/linux_arm/macroAssembler_linux_arm_32.cpp
+++ b/src/hotspot/os_cpu/linux_arm/macroAssembler_linux_arm_32.cpp
@@ -247,9 +247,9 @@ void MacroAssembler::atomic_cas64(Register memval_lo, Register memval_hi, Regist
Label loop;
assert_different_registers(memval_lo, memval_hi, result, oldval_lo,
oldval_hi, newval_lo, newval_hi, base);
- assert(memval_hi == memval_lo + 1 && memval_lo < R9, "cmpxchg_long: illegal registers");
- assert(oldval_hi == oldval_lo + 1 && oldval_lo < R9, "cmpxchg_long: illegal registers");
- assert(newval_hi == newval_lo + 1 && newval_lo < R9, "cmpxchg_long: illegal registers");
+ assert(memval_hi == as_Register(memval_lo->encoding() + 1) && memval_lo->encoding() < R9->encoding(), "cmpxchg_long: illegal registers");
+ assert(oldval_hi == as_Register(oldval_lo->encoding() + 1) && oldval_lo->encoding() < R9->encoding(), "cmpxchg_long: illegal registers");
+ assert(newval_hi == as_Register(newval_lo->encoding() + 1) && newval_lo->encoding() < R9->encoding(), "cmpxchg_long: illegal registers");
assert(result != R10, "cmpxchg_long: illegal registers");
assert(base != R10, "cmpxchg_long: illegal registers");
diff --git a/src/hotspot/share/compiler/compileBroker.cpp b/src/hotspot/share/compiler/compileBroker.cpp
index b3705c869af6..90ca95e5d17b 100644
--- a/src/hotspot/share/compiler/compileBroker.cpp
+++ b/src/hotspot/share/compiler/compileBroker.cpp
@@ -1035,7 +1035,9 @@ void CompileBroker::possibly_add_compiler_threads(JavaThread* THREAD) {
if (new_c2_count <= old_c2_count && new_c1_count <= old_c1_count) return;
// Now, we do the more expensive operations.
- julong free_memory = os::free_memory();
+ physical_memory_size_type free_memory = 0;
+ // Return value ignored - defaulting to 0 on failure.
+ (void)os::free_memory(free_memory);
// If SegmentedCodeCache is off, both values refer to the single heap (with type CodeBlobType::All).
size_t available_cc_np = CodeCache::unallocated_capacity(CodeBlobType::MethodNonProfiled),
available_cc_p = CodeCache::unallocated_capacity(CodeBlobType::MethodProfiled);
diff --git a/src/hotspot/share/gc/g1/g1CollectedHeap.cpp b/src/hotspot/share/gc/g1/g1CollectedHeap.cpp
index 03d4a1854992..3a5e017d48ad 100644
--- a/src/hotspot/share/gc/g1/g1CollectedHeap.cpp
+++ b/src/hotspot/share/gc/g1/g1CollectedHeap.cpp
@@ -30,6 +30,7 @@
#include "code/icBuffer.hpp"
#include "compiler/oopMap.hpp"
#include "gc/g1/g1Allocator.inline.hpp"
+#include "gc/g1/g1Analytics.hpp"
#include "gc/g1/g1Arguments.hpp"
#include "gc/g1/g1BarrierSet.hpp"
#include "gc/g1/g1BatchedTask.hpp"
@@ -492,6 +493,13 @@ HeapWord* G1CollectedHeap::attempt_allocation_slow(uint node_index, size_t word_
gclocker_retry_count += 1;
}
+ // Has the gc overhead limit been reached in the meantime? If so, this mutator
+ // should receive null even when unsuccessfully scheduling a collection as well
+ // for global consistency.
+ if (gc_overhead_limit_exceeded()) {
+ return nullptr;
+ }
+
// We can reach here if we were unsuccessful in scheduling a
// collection (because another thread beat us to it) or if we were
// stalled due to the GC locker. In either can we should retry the
@@ -760,7 +768,12 @@ HeapWord* G1CollectedHeap::attempt_allocation_humongous(size_t word_size) {
GCLocker::stall_until_clear();
gclocker_retry_count += 1;
}
-
+ // Has the gc overhead limit been reached in the meantime? If so, this mutator
+ // should receive null even when unsuccessfully scheduling a collection as well
+ // for global consistency.
+ if (gc_overhead_limit_exceeded()) {
+ return nullptr;
+ }
// We can reach here if we were unsuccessful in scheduling a
// collection (because another thread beat us to it) or if we were
@@ -981,27 +994,64 @@ void G1CollectedHeap::resize_heap_if_necessary() {
}
}
+void G1CollectedHeap::update_gc_overhead_counter() {
+ assert(SafepointSynchronize::is_at_safepoint(), "precondition");
+
+ if (!UseGCOverheadLimit) {
+ return;
+ }
+
+ bool gc_time_over_limit = (_policy->analytics()->long_term_pause_time_ratio() * 100) >= GCTimeLimit;
+ double free_space_percent = percent_of(num_free_or_available_regions() * HeapRegion::GrainBytes, max_capacity());
+ bool free_space_below_limit = free_space_percent < GCHeapFreeLimit;
+
+ log_debug(gc)("GC Overhead Limit: GC Time %f Free Space %f Counter %zu",
+ (_policy->analytics()->long_term_pause_time_ratio() * 100),
+ free_space_percent,
+ _gc_overhead_counter);
+
+ if (gc_time_over_limit && free_space_below_limit) {
+ _gc_overhead_counter++;
+ } else {
+ _gc_overhead_counter = 0;
+ }
+}
+
+bool G1CollectedHeap::gc_overhead_limit_exceeded() {
+ return _gc_overhead_counter >= GCOverheadLimitThreshold;
+}
+
HeapWord* G1CollectedHeap::satisfy_failed_allocation_helper(size_t word_size,
bool do_gc,
bool maximal_compaction,
bool expect_null_mutator_alloc_region,
bool* gc_succeeded) {
*gc_succeeded = true;
- // Let's attempt the allocation first.
- HeapWord* result =
- attempt_allocation_at_safepoint(word_size,
- expect_null_mutator_alloc_region);
- if (result != nullptr) {
- return result;
- }
+ // Skip allocation if GC overhead limit has been exceeded to let the mutator run
+ // into an OOME. It can either exit "gracefully" or try to free up memory asap.
+ // For the latter situation, keep running GCs. If the mutator frees up enough
+ // memory quickly enough, the overhead(s) will go below the threshold(s) again
+ // and the VM may continue running.
+ // If we did not continue garbage collections, the (gc overhead) limit may decrease
+ // enough by itself to not count as exceeding the limit any more, in the worst
+ // case bouncing back-and-forth all the time.
+ if (!gc_overhead_limit_exceeded()) {
+ // Let's attempt the allocation first.
+ HeapWord* result =
+ attempt_allocation_at_safepoint(word_size,
+ expect_null_mutator_alloc_region);
+ if (result != nullptr) {
+ return result;
+ }
- // In a G1 heap, we're supposed to keep allocation from failing by
- // incremental pauses. Therefore, at least for now, we'll favor
- // expansion over collection. (This might change in the future if we can
- // do something smarter than full collection to satisfy a failed alloc.)
- result = expand_and_allocate(word_size);
- if (result != nullptr) {
- return result;
+ // In a G1 heap, we're supposed to keep allocation from failing by
+ // incremental pauses. Therefore, at least for now, we'll favor
+ // expansion over collection. (This might change in the future if we can
+ // do something smarter than full collection to satisfy a failed alloc.)
+ result = expand_and_allocate(word_size);
+ if (result != nullptr) {
+ return result;
+ }
}
if (do_gc) {
@@ -1025,6 +1075,10 @@ HeapWord* G1CollectedHeap::satisfy_failed_allocation(size_t word_size,
bool* succeeded) {
assert_at_safepoint_on_vm_thread();
+ // Update GC overhead limits after the initial garbage collection leading to this
+ // allocation attempt.
+ update_gc_overhead_counter();
+
// Attempts to allocate followed by Full GC.
HeapWord* result =
satisfy_failed_allocation_helper(word_size,
@@ -1062,6 +1116,10 @@ HeapWord* G1CollectedHeap::satisfy_failed_allocation(size_t word_size,
assert(!soft_ref_policy()->should_clear_all_soft_refs(),
"Flag should have been handled and cleared prior to this point");
+ if (gc_overhead_limit_exceeded()) {
+ log_info(gc)("GC Overhead Limit exceeded too often (%zu).", GCOverheadLimitThreshold);
+ }
+
// What else? We might try synchronous finalization later. If the total
// space available is large enough for the allocation, then a more
// complete compaction phase than we've tried so far might be
@@ -1230,6 +1288,7 @@ class HumongousRegionSetChecker : public HeapRegionSetChecker {
G1CollectedHeap::G1CollectedHeap() :
CollectedHeap(),
+ _gc_overhead_counter(0),
_service_thread(nullptr),
_periodic_gc_task(nullptr),
_free_arena_memory_task(nullptr),
diff --git a/src/hotspot/share/gc/g1/g1CollectedHeap.hpp b/src/hotspot/share/gc/g1/g1CollectedHeap.hpp
index c247909dd708..352e5ea7d35f 100644
--- a/src/hotspot/share/gc/g1/g1CollectedHeap.hpp
+++ b/src/hotspot/share/gc/g1/g1CollectedHeap.hpp
@@ -170,6 +170,17 @@ class G1CollectedHeap : public CollectedHeap {
friend class G1CheckRegionAttrTableClosure;
private:
+ // GC Overhead Limit functionality related members.
+ //
+ // The goal is to return null for allocations prematurely (before really going
+ // OOME) in case both GC CPU usage (>= GCTimeLimit) and not much available free
+ // memory (<= GCHeapFreeLimit) so that applications can exit gracefully or try
+ // to keep running by easing off memory.
+ uintx _gc_overhead_counter; // The number of consecutive garbage collections we were over the limits.
+
+ void update_gc_overhead_counter();
+ bool gc_overhead_limit_exceeded();
+
G1ServiceThread* _service_thread;
G1ServiceTask* _periodic_gc_task;
G1MonotonicArenaFreeMemoryTask* _free_arena_memory_task;
diff --git a/src/hotspot/share/gc/shared/gcInitLogger.cpp b/src/hotspot/share/gc/shared/gcInitLogger.cpp
index 1dfc27c53337..5956122323d4 100644
--- a/src/hotspot/share/gc/shared/gcInitLogger.cpp
+++ b/src/hotspot/share/gc/shared/gcInitLogger.cpp
@@ -63,8 +63,8 @@ void GCInitLogger::print_cpu() {
}
void GCInitLogger::print_memory() {
- julong memory = os::physical_memory();
- log_info_p(gc, init)("Memory: " JULONG_FORMAT "%s",
+ physical_memory_size_type memory = os::physical_memory();
+ log_info_p(gc, init)("Memory: " PHYS_MEM_TYPE_FORMAT "%s",
byte_size_in_proper_unit(memory), proper_unit_for_byte_size(memory));
}
diff --git a/src/hotspot/share/gc/shared/gc_globals.hpp b/src/hotspot/share/gc/shared/gc_globals.hpp
index 5d7202685401..98cd6137e985 100644
--- a/src/hotspot/share/gc/shared/gc_globals.hpp
+++ b/src/hotspot/share/gc/shared/gc_globals.hpp
@@ -477,7 +477,7 @@
"Estimate of footprint other than Java Heap") \
range(0, max_uintx) \
\
- product(bool, UseGCOverheadLimit, true, \
+ product(bool, UseGCOverheadLimit, falseInDebug, \
"Use policy to limit of proportion of time spent in GC " \
"before an OutOfMemory error is thrown") \
\
diff --git a/src/hotspot/share/gc/x/xLargePages.cpp b/src/hotspot/share/gc/x/xLargePages.cpp
index 13da763c6a39..0afb4ac6d702 100644
--- a/src/hotspot/share/gc/x/xLargePages.cpp
+++ b/src/hotspot/share/gc/x/xLargePages.cpp
@@ -31,7 +31,8 @@ XLargePages::State XLargePages::_state;
void XLargePages::initialize() {
pd_initialize();
- log_info_p(gc, init)("Memory: " JULONG_FORMAT "M", os::physical_memory() / M);
+ const size_t memory = os::physical_memory();
+ log_info_p(gc, init)("Memory: " PROPERFMT, PROPERFMTARGS(memory));
log_info_p(gc, init)("Large Page Support: %s", to_string());
}
diff --git a/src/hotspot/share/gc/z/zLargePages.cpp b/src/hotspot/share/gc/z/zLargePages.cpp
index 88656d153811..9a35e246f4b6 100644
--- a/src/hotspot/share/gc/z/zLargePages.cpp
+++ b/src/hotspot/share/gc/z/zLargePages.cpp
@@ -31,7 +31,8 @@ ZLargePages::State ZLargePages::_state;
void ZLargePages::initialize() {
pd_initialize();
- log_info_p(gc, init)("Memory: " JULONG_FORMAT "M", os::physical_memory() / M);
+ const size_t memory = static_cast(os::physical_memory());
+ log_info_p(gc, init)("Memory: " PROPERFMT, PROPERFMTARGS(memory));
log_info_p(gc, init)("Large Page Support: %s", to_string());
}
diff --git a/src/hotspot/share/jfr/jni/jfrJniMethod.cpp b/src/hotspot/share/jfr/jni/jfrJniMethod.cpp
index 7157c346db01..e78bd11fb647 100644
--- a/src/hotspot/share/jfr/jni/jfrJniMethod.cpp
+++ b/src/hotspot/share/jfr/jni/jfrJniMethod.cpp
@@ -402,9 +402,9 @@ JVM_ENTRY_NO_ENV(jlong, jfr_host_total_memory(JNIEnv* env, jobject jvm))
#ifdef LINUX
// We want the host memory, not the container limit.
// os::physical_memory() would return the container limit.
- return os::Linux::physical_memory();
+ return static_cast(os::Linux::physical_memory());
#else
- return os::physical_memory();
+ return static_cast(os::physical_memory());
#endif
JVM_END
diff --git a/src/hotspot/share/jfr/leakprofiler/chains/dfsClosure.cpp b/src/hotspot/share/jfr/leakprofiler/chains/dfsClosure.cpp
index 4ba2e3329f81..d2d3fec79e38 100644
--- a/src/hotspot/share/jfr/leakprofiler/chains/dfsClosure.cpp
+++ b/src/hotspot/share/jfr/leakprofiler/chains/dfsClosure.cpp
@@ -35,6 +35,7 @@
#include "memory/resourceArea.hpp"
#include "oops/access.inline.hpp"
#include "oops/oop.inline.hpp"
+#include "runtime/os.hpp"
#include "utilities/align.hpp"
UnifiedOopRef DFSClosure::_reference_stack[max_dfs_depth];
@@ -68,9 +69,27 @@ void DFSClosure::find_leaks_from_root_set(EdgeStore* edge_store,
rs.process();
}
+static address calculate_headroom_limit() {
+ static constexpr size_t required_headroom = K * 64;
+ const Thread* const t = Thread::current_or_null();
+ return t->stack_end() + required_headroom;
+}
+
DFSClosure::DFSClosure(EdgeStore* edge_store, JFRBitSet* mark_bits, const Edge* start_edge)
:_edge_store(edge_store), _mark_bits(mark_bits), _start_edge(start_edge),
- _max_depth(max_dfs_depth), _depth(0), _ignore_root_set(false) {
+ _max_depth(max_dfs_depth), _depth(0), _ignore_root_set(false),
+ _headroom_limit(calculate_headroom_limit()) {
+}
+
+bool DFSClosure::have_headroom() const {
+ const address sp = (address) os::current_stack_pointer();
+#ifdef ASSERT
+ const Thread* const t = Thread::current_or_null();
+ assert(t->is_VM_thread(), "invariant");
+ assert(t->is_in_full_stack(_headroom_limit), "invariant");
+ assert(t->is_in_full_stack(sp), "invariant");
+#endif
+ return sp > _headroom_limit;
}
void DFSClosure::closure_impl(UnifiedOopRef reference, const oop pointee) {
@@ -98,7 +117,7 @@ void DFSClosure::closure_impl(UnifiedOopRef reference, const oop pointee) {
}
}
assert(_max_depth >= 1, "invariant");
- if (_depth < _max_depth - 1) {
+ if (_depth < _max_depth - 1 && have_headroom()) {
_depth++;
pointee->oop_iterate(this);
assert(_depth > 0, "invariant");
diff --git a/src/hotspot/share/jfr/leakprofiler/chains/dfsClosure.hpp b/src/hotspot/share/jfr/leakprofiler/chains/dfsClosure.hpp
index be0cd2a5d7eb..a22b5137380f 100644
--- a/src/hotspot/share/jfr/leakprofiler/chains/dfsClosure.hpp
+++ b/src/hotspot/share/jfr/leakprofiler/chains/dfsClosure.hpp
@@ -46,12 +46,15 @@ class DFSClosure : public BasicOopIterateClosure {
size_t _max_depth;
size_t _depth;
bool _ignore_root_set;
+ const address _headroom_limit;
DFSClosure(EdgeStore* edge_store, JFRBitSet* mark_bits, const Edge* start_edge);
void add_chain();
void closure_impl(UnifiedOopRef reference, const oop pointee);
+ bool have_headroom() const;
+
public:
virtual ReferenceIterationMode reference_iteration_mode() { return DO_FIELDS_EXCEPT_REFERENT; }
diff --git a/src/hotspot/share/jfr/leakprofiler/sampling/objectSampler.cpp b/src/hotspot/share/jfr/leakprofiler/sampling/objectSampler.cpp
index 311c54becd8e..465491cd1d5a 100644
--- a/src/hotspot/share/jfr/leakprofiler/sampling/objectSampler.cpp
+++ b/src/hotspot/share/jfr/leakprofiler/sampling/objectSampler.cpp
@@ -236,12 +236,25 @@ void ObjectSampler::add(HeapWord* obj, size_t allocated, traceid thread_id, bool
// quick reject, will not fit
return;
}
- sample = _list->reuse(_priority_queue->pop());
+ ObjectSample* popped = _priority_queue->pop();
+ size_t popped_span = popped->span();
+ ObjectSample* previous = popped->prev();
+ sample = _list->reuse(popped);
+ assert(sample != nullptr, "invariant");
+ if (previous != nullptr) {
+ push_span(previous, popped_span);
+ sample->set_span(span);
+ } else {
+ // The removed sample was the youngest sample in the list, which means the new sample is now the youngest
+ // sample. It should cover the spans of both.
+ sample->set_span(span + popped_span);
+ }
} else {
sample = _list->get();
+ assert(sample != nullptr, "invariant");
+ sample->set_span(span);
}
- assert(sample != nullptr, "invariant");
sample->set_thread_id(thread_id);
if (virtual_thread) {
sample->set_thread_is_virtual();
@@ -255,7 +268,6 @@ void ObjectSampler::add(HeapWord* obj, size_t allocated, traceid thread_id, bool
sample->set_stack_trace_hash(stacktrace_hash);
}
- sample->set_span(allocated);
sample->set_object(cast_to_oop(obj));
sample->set_allocated(allocated);
sample->set_allocation_time(JfrTicks::now());
@@ -282,14 +294,18 @@ void ObjectSampler::remove_dead(ObjectSample* sample) {
ObjectSample* const previous = sample->prev();
// push span onto previous
if (previous != nullptr) {
- _priority_queue->remove(previous);
- previous->add_span(sample->span());
- _priority_queue->push(previous);
+ push_span(previous, sample->span());
}
_priority_queue->remove(sample);
_list->release(sample);
}
+void ObjectSampler::push_span(ObjectSample* sample, size_t span) {
+ _priority_queue->remove(sample);
+ sample->add_span(span);
+ _priority_queue->push(sample);
+}
+
ObjectSample* ObjectSampler::last() const {
return _list->last();
}
diff --git a/src/hotspot/share/jfr/leakprofiler/sampling/objectSampler.hpp b/src/hotspot/share/jfr/leakprofiler/sampling/objectSampler.hpp
index 3789227b6008..6ae1b0a06833 100644
--- a/src/hotspot/share/jfr/leakprofiler/sampling/objectSampler.hpp
+++ b/src/hotspot/share/jfr/leakprofiler/sampling/objectSampler.hpp
@@ -64,6 +64,7 @@ class ObjectSampler : public CHeapObj {
void add(HeapWord* object, size_t size, traceid thread_id, bool virtual_thread, const JfrBlobHandle& bh, JavaThread* thread);
void scavenge();
void remove_dead(ObjectSample* sample);
+ void push_span(ObjectSample* sample, size_t span);
const ObjectSample* item_at(int index) const;
ObjectSample* item_at(int index);
diff --git a/src/hotspot/share/jfr/periodic/jfrPeriodic.cpp b/src/hotspot/share/jfr/periodic/jfrPeriodic.cpp
index ff52b4104fdb..80a160ab84ba 100644
--- a/src/hotspot/share/jfr/periodic/jfrPeriodic.cpp
+++ b/src/hotspot/share/jfr/periodic/jfrPeriodic.cpp
@@ -515,10 +515,13 @@ TRACE_REQUEST_FUNC(ThreadAllocationStatistics) {
* the total memory reported is the amount of memory configured for the guest OS by the hypervisor.
*/
TRACE_REQUEST_FUNC(PhysicalMemory) {
- u8 totalPhysicalMemory = os::physical_memory();
+ physical_memory_size_type totalPhysicalMemory = os::physical_memory();
EventPhysicalMemory event;
event.set_totalSize(totalPhysicalMemory);
- event.set_usedSize(totalPhysicalMemory - os::available_memory());
+ physical_memory_size_type avail_mem = 0;
+ // Return value ignored - defaulting to 0 on failure.
+ (void)os::available_memory(avail_mem);
+ event.set_usedSize(totalPhysicalMemory - avail_mem);
event.commit();
}
diff --git a/src/hotspot/share/jfr/recorder/jfrRecorder.cpp b/src/hotspot/share/jfr/recorder/jfrRecorder.cpp
index 09455a3ea1fa..0c191e3e1898 100644
--- a/src/hotspot/share/jfr/recorder/jfrRecorder.cpp
+++ b/src/hotspot/share/jfr/recorder/jfrRecorder.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2012, 2023, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2026, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -228,7 +228,7 @@ bool JfrRecorder::on_create_vm_2() {
}
bool JfrRecorder::on_create_vm_3() {
- assert(JvmtiEnvBase::get_phase() == JVMTI_PHASE_LIVE, "invalid init sequence");
+ JVMTI_ONLY( assert(JvmtiEnvBase::get_phase() == JVMTI_PHASE_LIVE, "invalid init sequence, phase is %d", (int)JvmtiEnvBase::get_phase()); )
return Arguments::is_dumping_archive() || launch_command_line_recordings(JavaThread::current());
}
diff --git a/src/hotspot/share/prims/jvmtiAgentList.cpp b/src/hotspot/share/prims/jvmtiAgentList.cpp
index 2a0f71728888..2857927ac31a 100644
--- a/src/hotspot/share/prims/jvmtiAgentList.cpp
+++ b/src/hotspot/share/prims/jvmtiAgentList.cpp
@@ -200,6 +200,11 @@ void JvmtiAgentList::load_xrun_agents() {
// Invokes Agent_OnAttach for agents loaded dynamically during runtime.
void JvmtiAgentList::load_agent(const char* agent_name, bool is_absolute_path,
const char* options, outputStream* st) {
+ if (JvmtiEnvBase::get_phase() != JVMTI_PHASE_LIVE) {
+ st->print_cr("Dynamic agent loading is only permitted in the live phase");
+ return;
+ }
+
JvmtiAgent* const agent = new JvmtiAgent(agent_name, options, is_absolute_path, /* dynamic agent */ true);
if (agent->load(st)) {
add(agent);
diff --git a/src/hotspot/share/prims/jvmtiClassFileReconstituter.cpp b/src/hotspot/share/prims/jvmtiClassFileReconstituter.cpp
index 0c33a7c29248..46c6bb8e2566 100644
--- a/src/hotspot/share/prims/jvmtiClassFileReconstituter.cpp
+++ b/src/hotspot/share/prims/jvmtiClassFileReconstituter.cpp
@@ -992,6 +992,11 @@ void JvmtiClassFileReconstituter::write_u8(u8 x) {
void JvmtiClassFileReconstituter::copy_bytecodes(const methodHandle& mh,
unsigned char* bytecodes) {
+ // We must copy bytecodes only from linked classes.
+ // Being linked guarantees we are not getting bytecodes at
+ // the same time the linking process is rewriting them.
+ guarantee(mh->method_holder()->is_linked(), "Bytecodes must be copied from a linked class");
+
// use a BytecodeStream to iterate over the bytecodes. JVM/fast bytecodes
// and the breakpoint bytecode are converted to their original bytecodes.
diff --git a/src/hotspot/share/prims/jvmtiEnhancedRedefineClasses.cpp b/src/hotspot/share/prims/jvmtiEnhancedRedefineClasses.cpp
index a0203ad852e2..0a9c3848b4af 100644
--- a/src/hotspot/share/prims/jvmtiEnhancedRedefineClasses.cpp
+++ b/src/hotspot/share/prims/jvmtiEnhancedRedefineClasses.cpp
@@ -1153,9 +1153,11 @@ jvmtiError VM_EnhancedRedefineClasses::load_new_class_versions_single_step(Old2N
}
}
+ physical_memory_size_type avail_mem = 0;
+ (void)os::available_memory(avail_mem);
log_debug(redefine, class, load)
- ("loading name=%s kind=%d (avail_mem=" UINT64_FORMAT "K)",
- the_class->external_name(), _class_load_kind, os::available_memory() >> 10);
+ ("loading name=%s kind=%d (avail_mem=" PHYS_MEM_TYPE_FORMAT "K)",
+ the_class->external_name(), _class_load_kind, avail_mem >> 10);
// class bytes...
const unsigned char* class_bytes;
@@ -1321,8 +1323,9 @@ jvmtiError VM_EnhancedRedefineClasses::load_new_class_versions_single_step(Old2N
_object_klass_redefined = true;
}
+ (void)os::available_memory(avail_mem);
log_debug(redefine, class, load)
- ("loaded name=%s (avail_mem=" UINT64_FORMAT "K)", the_class->external_name(), os::available_memory() >> 10);
+ ("loaded name=%s (avail_mem=" PHYS_MEM_TYPE_FORMAT "K)", the_class->external_name(), avail_mem >> 10);
}
return JVMTI_ERROR_NONE;
@@ -2376,9 +2379,12 @@ void VM_EnhancedRedefineClasses::redefine_single_class(Thread *current, Instance
// increment the classRedefinedCount field in the_class and in any
// direct and indirect subclasses of the_class
increment_class_counter(current, new_class);
+
+ physical_memory_size_type avail_mem = 0;
+ (void)os::available_memory(avail_mem);
log_info(redefine, class, load)
- ("redefined name=%s, count=%d (avail_mem=" UINT64_FORMAT "K)",
- new_class->external_name(), java_lang_Class::classRedefinedCount(new_class->java_mirror()), os::available_memory() >> 10);
+ ("redefined name=%s, count=%d (avail_mem=" PHYS_MEM_TYPE_FORMAT "K)",
+ new_class->external_name(), java_lang_Class::classRedefinedCount(new_class->java_mirror()), avail_mem >> 10);
Events::log_redefinition(current, "redefined class name=%s, count=%d",
new_class->external_name(),
java_lang_Class::classRedefinedCount(new_class->java_mirror()));
diff --git a/src/hotspot/share/prims/jvmtiEnv.cpp b/src/hotspot/share/prims/jvmtiEnv.cpp
index 29579cdf5513..79d2d195d8b0 100644
--- a/src/hotspot/share/prims/jvmtiEnv.cpp
+++ b/src/hotspot/share/prims/jvmtiEnv.cpp
@@ -462,6 +462,18 @@ JvmtiEnv::RetransformClasses(jint class_count, const jclass* classes) {
InstanceKlass* ik = InstanceKlass::cast(klass);
if (ik->get_cached_class_file_bytes() == nullptr) {
+ // Link the class to avoid races with the rewriter. This will call the verifier also
+ // on the class. Linking is also done in VM_RedefineClasses below, but we need
+ // to keep that for other VM_RedefineClasses callers.
+ JavaThread* THREAD = current_thread;
+ ik->link_class(THREAD);
+ if (HAS_PENDING_EXCEPTION) {
+ // Retransform/JVMTI swallows error messages. Using this class will rerun the verifier in a context
+ // that propagates the VerifyError, if thrown.
+ CLEAR_PENDING_EXCEPTION;
+ return JVMTI_ERROR_INVALID_CLASS;
+ }
+
// Not cached, we need to reconstitute the class file from the
// VM representation. We don't attach the reconstituted class
// bytes to the InstanceKlass here because they have not been
@@ -3700,7 +3712,8 @@ jvmtiError
JvmtiEnv::GetBytecodes(Method* method, jint* bytecode_count_ptr, unsigned char** bytecodes_ptr) {
NULL_CHECK(method, JVMTI_ERROR_INVALID_METHODID);
- methodHandle mh(Thread::current(), method);
+ JavaThread* current_thread = JavaThread::current();
+ methodHandle mh(current_thread, method);
jint size = (jint)mh->code_size();
jvmtiError err = allocate(size, bytecodes_ptr);
if (err != JVMTI_ERROR_NONE) {
@@ -3709,6 +3722,13 @@ JvmtiEnv::GetBytecodes(Method* method, jint* bytecode_count_ptr, unsigned char**
(*bytecode_count_ptr) = size;
// get byte codes
+ // Make sure the class is verified and rewritten first.
+ JavaThread* THREAD = current_thread;
+ mh->method_holder()->link_class(THREAD);
+ if (HAS_PENDING_EXCEPTION) {
+ CLEAR_PENDING_EXCEPTION;
+ return JVMTI_ERROR_INVALID_CLASS;
+ }
JvmtiClassFileReconstituter::copy_bytecodes(mh, *bytecodes_ptr);
return JVMTI_ERROR_NONE;
diff --git a/src/hotspot/share/prims/jvmtiRedefineClasses.cpp b/src/hotspot/share/prims/jvmtiRedefineClasses.cpp
index e2fc7a48867b..0cc156beb4a3 100644
--- a/src/hotspot/share/prims/jvmtiRedefineClasses.cpp
+++ b/src/hotspot/share/prims/jvmtiRedefineClasses.cpp
@@ -1375,10 +1375,12 @@ jvmtiError VM_RedefineClasses::load_new_class_versions() {
// constant pools
HandleMark hm(current);
InstanceKlass* the_class = get_ik(_class_defs[i].klass);
-
+ physical_memory_size_type avail_mem = 0;
+ // Return value ignored - defaulting to 0 on failure.
+ (void)os::available_memory(avail_mem);
log_debug(redefine, class, load)
- ("loading name=%s kind=%d (avail_mem=" UINT64_FORMAT "K)",
- the_class->external_name(), _class_load_kind, os::available_memory() >> 10);
+ ("loading name=%s kind=%d (avail_mem=" PHYS_MEM_TYPE_FORMAT "K)",
+ the_class->external_name(), _class_load_kind, avail_mem >> 10);
ClassFileStream st((u1*)_class_defs[i].class_bytes,
_class_defs[i].class_byte_count,
@@ -1544,9 +1546,10 @@ jvmtiError VM_RedefineClasses::load_new_class_versions() {
return JVMTI_ERROR_INTERNAL;
}
}
-
+ // Return value ignored - defaulting to 0 on failure.
+ (void)os::available_memory(avail_mem);
log_debug(redefine, class, load)
- ("loaded name=%s (avail_mem=" UINT64_FORMAT "K)", the_class->external_name(), os::available_memory() >> 10);
+ ("loaded name=%s (avail_mem=" PHYS_MEM_TYPE_FORMAT "K)", the_class->external_name(), avail_mem >> 10);
}
return JVMTI_ERROR_NONE;
@@ -4455,9 +4458,12 @@ void VM_RedefineClasses::redefine_single_class(Thread* current, jclass the_jclas
ResourceMark rm(current);
// increment the classRedefinedCount field in the_class and in any
// direct and indirect subclasses of the_class
+ physical_memory_size_type avail_mem = 0;
+ // Return value ignored - defaulting to 0 on failure.
+ (void)os::available_memory(avail_mem);
log_info(redefine, class, load)
- ("redefined name=%s, count=%d (avail_mem=" UINT64_FORMAT "K)",
- the_class->external_name(), java_lang_Class::classRedefinedCount(the_class->java_mirror()), os::available_memory() >> 10);
+ ("redefined name=%s, count=%d (avail_mem=" PHYS_MEM_TYPE_FORMAT "K)",
+ the_class->external_name(), java_lang_Class::classRedefinedCount(the_class->java_mirror()), avail_mem >> 10);
Events::log_redefinition(current, "redefined class name=%s, count=%d",
the_class->external_name(),
java_lang_Class::classRedefinedCount(the_class->java_mirror()));
diff --git a/src/hotspot/share/prims/whitebox.cpp b/src/hotspot/share/prims/whitebox.cpp
index c1dbb482f5fb..3288f5f27d61 100644
--- a/src/hotspot/share/prims/whitebox.cpp
+++ b/src/hotspot/share/prims/whitebox.cpp
@@ -2408,8 +2408,8 @@ WB_END
// Physical memory of the host machine (including containers)
WB_ENTRY(jlong, WB_HostPhysicalMemory(JNIEnv* env, jobject o))
- LINUX_ONLY(return os::Linux::physical_memory();)
- return os::physical_memory();
+ LINUX_ONLY(return static_cast(os::Linux::physical_memory());)
+ return static_cast(os::physical_memory());
WB_END
// Physical swap of the host machine (including containers), Linux only.
diff --git a/src/hotspot/share/runtime/abstract_vm_version.cpp b/src/hotspot/share/runtime/abstract_vm_version.cpp
index 8939b84bebee..0e800056a4e1 100644
--- a/src/hotspot/share/runtime/abstract_vm_version.cpp
+++ b/src/hotspot/share/runtime/abstract_vm_version.cpp
@@ -262,6 +262,8 @@ const char* Abstract_VM_Version::internal_vm_info_string() {
#define HOTSPOT_BUILD_COMPILER "MS VC++ 17.13 (VS2022)"
#elif _MSC_VER == 1944
#define HOTSPOT_BUILD_COMPILER "MS VC++ 17.14 (VS2022)"
+ #elif _MSC_VER == 1950
+ #define HOTSPOT_BUILD_COMPILER "MS VC++ 18.0 (VS2026)"
#else
#define HOTSPOT_BUILD_COMPILER "unknown MS VC++:" XSTR(_MSC_VER)
#endif
diff --git a/src/hotspot/share/runtime/arguments.cpp b/src/hotspot/share/runtime/arguments.cpp
index 976023e92348..58a84bd35289 100644
--- a/src/hotspot/share/runtime/arguments.cpp
+++ b/src/hotspot/share/runtime/arguments.cpp
@@ -1588,13 +1588,13 @@ void Arguments::set_heap_size() {
!FLAG_IS_DEFAULT(MaxRAM));
if (override_coop_limit) {
if (FLAG_IS_DEFAULT(MaxRAM)) {
- phys_mem = os::physical_memory();
+ phys_mem = static_cast(os::physical_memory());
FLAG_SET_ERGO(MaxRAM, (uint64_t)phys_mem);
} else {
phys_mem = (julong)MaxRAM;
}
} else {
- phys_mem = FLAG_IS_DEFAULT(MaxRAM) ? MIN2(os::physical_memory(), (julong)MaxRAM)
+ phys_mem = FLAG_IS_DEFAULT(MaxRAM) ? MIN2(static_cast(os::physical_memory()), (julong)MaxRAM)
: (julong)MaxRAM;
}
@@ -1730,7 +1730,8 @@ jint Arguments::set_aggressive_heap_flags() {
// Thus, we need to make sure we're using a julong for intermediate
// calculations.
julong initHeapSize;
- julong total_memory = os::physical_memory();
+ physical_memory_size_type phys_mem = os::physical_memory();
+ julong total_memory = static_cast(phys_mem);
if (total_memory < (julong) 256 * M) {
jio_fprintf(defaultStream::error_stream(),
diff --git a/src/hotspot/share/runtime/os.cpp b/src/hotspot/share/runtime/os.cpp
index 2e8d3bcdab15..a4b3409a1065 100644
--- a/src/hotspot/share/runtime/os.cpp
+++ b/src/hotspot/share/runtime/os.cpp
@@ -1175,12 +1175,13 @@ void os::print_summary_info(outputStream* st, char* buf, size_t buflen) {
#endif // PRODUCT
get_summary_cpu_info(buf, buflen);
st->print("%s, ", buf);
- size_t mem = physical_memory()/G;
+ physical_memory_size_type phys_mem = physical_memory();
+ physical_memory_size_type mem = phys_mem/G;
if (mem == 0) { // for low memory systems
- mem = physical_memory()/M;
- st->print("%d cores, " SIZE_FORMAT "M, ", processor_count(), mem);
+ mem = phys_mem/M;
+ st->print("%d cores, " PHYS_MEM_TYPE_FORMAT "M, ", processor_count(), mem);
} else {
- st->print("%d cores, " SIZE_FORMAT "G, ", processor_count(), mem);
+ st->print("%d cores, " PHYS_MEM_TYPE_FORMAT "G, ", processor_count(), mem);
}
get_summary_os_info(buf, buflen);
st->print_raw(buf);
@@ -1901,17 +1902,17 @@ bool os::is_server_class_machine() {
return true;
}
// Then actually look at the machine
- bool result = false;
- const unsigned int server_processors = 2;
- const julong server_memory = 2UL * G;
+ bool result = false;
+ const unsigned int server_processors = 2;
+ const physical_memory_size_type server_memory = 2UL * G;
// We seem not to get our full complement of memory.
// We allow some part (1/8?) of the memory to be "missing",
// based on the sizes of DIMMs, and maybe graphics cards.
- const julong missing_memory = 256UL * M;
-
+ const physical_memory_size_type missing_memory = 256UL * M;
+ physical_memory_size_type phys_mem = os::physical_memory();
/* Is this a server class machine? */
if ((os::active_processor_count() >= (int)server_processors) &&
- (os::physical_memory() >= (server_memory - missing_memory))) {
+ (phys_mem >= server_memory - missing_memory)) {
const unsigned int logical_processors =
VM_Version::logical_processors_per_package();
if (logical_processors > 1) {
diff --git a/src/hotspot/share/runtime/os.hpp b/src/hotspot/share/runtime/os.hpp
index f3e306479b4d..54f90f69605b 100644
--- a/src/hotspot/share/runtime/os.hpp
+++ b/src/hotspot/share/runtime/os.hpp
@@ -320,10 +320,10 @@ class os: AllStatic {
// For example, on Linux, "available" memory (`MemAvailable` in `/proc/meminfo`) is greater
// than "free" memory (`MemFree` in `/proc/meminfo`) because Linux can free memory
// aggressively (e.g. clear caches) so that it becomes available.
- static julong available_memory();
- static julong free_memory();
+ [[nodiscard]] static bool available_memory(physical_memory_size_type& value);
+ [[nodiscard]] static bool free_memory(physical_memory_size_type& value);
- static julong physical_memory();
+ static physical_memory_size_type physical_memory();
static bool has_allocatable_memory_limit(size_t* limit);
static bool is_server_class_machine();
@@ -926,7 +926,7 @@ class os: AllStatic {
// provided buffer as a scratch buffer. The status message which will be written
// into the error log either is file location or a short error message, depending
// on the checking result.
- static void check_dump_limit(char* buffer, size_t bufferSize);
+ static void check_core_dump_prerequisites(char* buffer, size_t bufferSize, bool check_only = false);
// Get the default path to the core file
// Returns the length of the string
diff --git a/src/hotspot/share/runtime/thread.cpp b/src/hotspot/share/runtime/thread.cpp
index ce4c3b9cc14d..b0c43d146245 100644
--- a/src/hotspot/share/runtime/thread.cpp
+++ b/src/hotspot/share/runtime/thread.cpp
@@ -36,6 +36,8 @@
#include "memory/resourceArea.hpp"
#include "oops/oop.inline.hpp"
#include "runtime/atomic.hpp"
+#include "runtime/globals.hpp"
+#include "runtime/globals_extension.hpp"
#include "runtime/handles.inline.hpp"
#include "runtime/javaThread.inline.hpp"
#include "runtime/nonJavaThread.hpp"
diff --git a/src/hotspot/share/runtime/threadSMR.cpp b/src/hotspot/share/runtime/threadSMR.cpp
index 1469c7a42aa6..a15bb1710618 100644
--- a/src/hotspot/share/runtime/threadSMR.cpp
+++ b/src/hotspot/share/runtime/threadSMR.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2017, 2023, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2017, 2026, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -727,7 +727,8 @@ JavaThread* ThreadsList::find_JavaThread_from_java_tid(jlong java_tid) const {
}
}
}
- } else if (!thread->is_exiting()) {
+ } else if (includes(thread) && !thread->is_exiting()) {
+ // The thread is protected by this list and has not yet exited
return thread;
}
return nullptr;
@@ -866,7 +867,7 @@ void ThreadsSMRSupport::add_thread(JavaThread *thread){
ThreadsList *old_list = xchg_java_thread_list(new_list);
free_list(old_list);
- if (ThreadIdTable::is_initialized()) {
+ if (ThreadIdTable::is_initialized_acquire()) {
jlong tid = SharedRuntime::get_java_tid(thread);
ThreadIdTable::add_thread(tid, thread);
}
diff --git a/src/hotspot/share/runtime/threads.cpp b/src/hotspot/share/runtime/threads.cpp
index f3b5cea106f7..091a25ad06d0 100644
--- a/src/hotspot/share/runtime/threads.cpp
+++ b/src/hotspot/share/runtime/threads.cpp
@@ -63,6 +63,7 @@
#include "runtime/flags/jvmFlagLimit.hpp"
#include "runtime/handles.inline.hpp"
#include "runtime/globals.hpp"
+#include "runtime/globals_extension.hpp"
#include "runtime/interfaceSupport.inline.hpp"
#include "runtime/java.hpp"
#include "runtime/javaCalls.hpp"
@@ -688,6 +689,11 @@ jint Threads::create_vm(JavaVMInitArgs* args, bool* canTryAgain) {
log_info(os)("Initialized VM with process ID %d", os::current_process_id());
+ if (!FLAG_IS_DEFAULT(CreateCoredumpOnCrash) && CreateCoredumpOnCrash) {
+ char buffer[2*JVM_MAXPATHLEN];
+ os::check_core_dump_prerequisites(buffer, sizeof(buffer), true);
+ }
+
// Signal Dispatcher needs to be started before VMInit event is posted
os::initialize_jdk_signal_support(CHECK_JNI_ERR);
@@ -1044,7 +1050,7 @@ void Threads::remove(JavaThread* p, bool is_daemon) {
MutexLocker throttle_ml(UseThreadsLockThrottleLock ? ThreadsLockThrottle_lock : nullptr);
MonitorLocker ml(Threads_lock);
- if (ThreadIdTable::is_initialized()) {
+ if (ThreadIdTable::is_initialized_acquire()) {
// This cleanup must be done before the current thread's GC barrier
// is detached since we need to touch the threadObj oop.
jlong tid = SharedRuntime::get_java_tid(p);
diff --git a/src/hotspot/share/services/management.cpp b/src/hotspot/share/services/management.cpp
index a9c50a8bf06d..5de75840f3d3 100644
--- a/src/hotspot/share/services/management.cpp
+++ b/src/hotspot/share/services/management.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2003, 2023, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2026, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -978,7 +978,7 @@ static jlong get_long_attribute(jmmLongAttribute att) {
return ClassLoadingService::class_method_data_size();
case JMM_OS_MEM_TOTAL_PHYSICAL_BYTES:
- return os::physical_memory();
+ return static_cast(os::physical_memory());
default:
return -1;
@@ -1130,6 +1130,7 @@ JVM_ENTRY(jint, jmm_GetThreadInfo(JNIEnv *env, jlongArray ids, jint maxDepth, jo
// create dummy snapshot
dump_result.add_thread_snapshot();
} else {
+ assert(dump_result.t_list()->includes(jt), "Must be protected");
dump_result.add_thread_snapshot(jt);
}
}
diff --git a/src/hotspot/share/services/threadIdTable.cpp b/src/hotspot/share/services/threadIdTable.cpp
index 168b2e085adf..3355fc26eaaf 100644
--- a/src/hotspot/share/services/threadIdTable.cpp
+++ b/src/hotspot/share/services/threadIdTable.cpp
@@ -1,6 +1,6 @@
/*
-* Copyright (c) 2019, 2022, Oracle and/or its affiliates. All rights reserved.
+* Copyright (c) 2019, 2026, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -25,7 +25,7 @@
#include "precompiled.hpp"
#include "classfile/javaClasses.inline.hpp"
-#include "runtime/atomic.hpp"
+#include "runtime/handles.hpp"
#include "runtime/interfaceSupport.inline.hpp"
#include "runtime/javaThread.inline.hpp"
#include "runtime/threadSMR.hpp"
@@ -83,24 +83,25 @@ class ThreadIdTableConfig : public AllStatic {
// Lazily creates the table and populates it with the given
// thread list
void ThreadIdTable::lazy_initialize(const ThreadsList *threads) {
- if (!_is_initialized) {
+ if (!Atomic::load_acquire(&_is_initialized)) {
{
// There is no obvious benefit in allowing the thread table
// to be concurrently populated during initialization.
MutexLocker ml(ThreadIdTableCreate_lock);
- if (_is_initialized) {
+ if (Atomic::load(&_is_initialized)) {
return;
}
create_table(threads->length());
- _is_initialized = true;
+ Atomic::release_store(&_is_initialized, true);
}
+
for (uint i = 0; i < threads->length(); i++) {
JavaThread* thread = threads->thread_at(i);
- oop tobj = thread->threadObj();
+ Handle tobj = Handle(JavaThread::current(), thread->threadObj());
if (tobj != nullptr) {
- jlong java_tid = java_lang_Thread::thread_id(tobj);
MutexLocker ml(Threads_lock);
if (!thread->is_exiting()) {
+ jlong java_tid = java_lang_Thread::thread_id(tobj());
// Must be inside the lock to ensure that we don't add a thread to the table
// that has just passed the removal point in Threads::remove().
add_thread(java_tid, thread);
@@ -213,7 +214,7 @@ class ThreadGet : public StackObj {
};
void ThreadIdTable::do_concurrent_work(JavaThread* jt) {
- assert(_is_initialized, "Thread table is not initialized");
+ assert(Atomic::load(&_is_initialized), "Thread table is not initialized");
_has_work = false;
double load_factor = get_load_factor();
log_debug(thread, table)("Concurrent work, load factor: %g", load_factor);
@@ -223,7 +224,8 @@ void ThreadIdTable::do_concurrent_work(JavaThread* jt) {
}
JavaThread* ThreadIdTable::add_thread(jlong tid, JavaThread* java_thread) {
- assert(_is_initialized, "Thread table is not initialized");
+ assert(Threads_lock->owned_by_self(), "Must hold Threads_lock");
+ assert(Atomic::load(&_is_initialized), "Thread table is not initialized");
Thread* thread = Thread::current();
ThreadIdTableLookup lookup(tid);
ThreadGet tg;
@@ -242,7 +244,7 @@ JavaThread* ThreadIdTable::add_thread(jlong tid, JavaThread* java_thread) {
}
JavaThread* ThreadIdTable::find_thread_by_tid(jlong tid) {
- assert(_is_initialized, "Thread table is not initialized");
+ assert(Atomic::load(&_is_initialized), "Thread table is not initialized");
Thread* thread = Thread::current();
ThreadIdTableLookup lookup(tid);
ThreadGet tg;
@@ -251,7 +253,8 @@ JavaThread* ThreadIdTable::find_thread_by_tid(jlong tid) {
}
bool ThreadIdTable::remove_thread(jlong tid) {
- assert(_is_initialized, "Thread table is not initialized");
+ assert(Threads_lock->owned_by_self(), "Must hold Threads_lock");
+ assert(Atomic::load(&_is_initialized), "Thread table is not initialized");
Thread* thread = Thread::current();
ThreadIdTableLookup lookup(tid);
return _local_table->remove(thread, lookup);
diff --git a/src/hotspot/share/services/threadIdTable.hpp b/src/hotspot/share/services/threadIdTable.hpp
index 12772aed88c0..a292d04452a2 100644
--- a/src/hotspot/share/services/threadIdTable.hpp
+++ b/src/hotspot/share/services/threadIdTable.hpp
@@ -1,6 +1,6 @@
/*
-* Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
+* Copyright (c) 2019, 2026, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -27,6 +27,7 @@
#define SHARE_SERVICES_THREADIDTABLE_HPP
#include "memory/allStatic.hpp"
+#include "runtime/atomic.hpp"
class JavaThread;
class ThreadsList;
@@ -41,7 +42,9 @@ class ThreadIdTable : public AllStatic {
public:
// Initialization
static void lazy_initialize(const ThreadsList* threads);
- static bool is_initialized() { return _is_initialized; }
+ static bool is_initialized_acquire() {
+ return Atomic::load_acquire(&_is_initialized);
+ }
// Lookup and list management
static JavaThread* find_thread_by_tid(jlong tid);
diff --git a/src/hotspot/share/utilities/globalDefinitions.hpp b/src/hotspot/share/utilities/globalDefinitions.hpp
index 9d4cae2a08d4..2711a4e30079 100644
--- a/src/hotspot/share/utilities/globalDefinitions.hpp
+++ b/src/hotspot/share/utilities/globalDefinitions.hpp
@@ -131,6 +131,7 @@ class oopDesc;
#define UINT64_FORMAT_X "0x%" PRIx64
#define UINT64_FORMAT_X_0 "0x%016" PRIx64
#define UINT64_FORMAT_W(width) "%" #width PRIu64
+#define PHYS_MEM_TYPE_FORMAT "%" PRIu64
// Format integers which change size between 32- and 64-bit.
#define SSIZE_FORMAT "%" PRIdPTR
@@ -426,6 +427,11 @@ inline size_t byte_size_in_exact_unit(size_t s) {
#define HEAP_CHANGE_FORMAT_ARGS(_name_, _prev_used_, _prev_capacity_, _used_, _capacity_) \
(_name_), (_prev_used_) / K, (_prev_capacity_) / K, (_used_) / K, (_capacity_) / K
+// This typedef is to address the issue of running a 32-bit VM. In this case the amount
+// of physical memory may not fit in size_t, so we have to have a larger type. Once 32-bit
+// is deprecated, one can use size_t.
+typedef uint64_t physical_memory_size_type;
+
//----------------------------------------------------------------------------------------------------
// VM type definitions
diff --git a/src/hotspot/share/utilities/vmError.cpp b/src/hotspot/share/utilities/vmError.cpp
index 9adbac965cf8..ef47ce60a079 100644
--- a/src/hotspot/share/utilities/vmError.cpp
+++ b/src/hotspot/share/utilities/vmError.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2003, 2023, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2024, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2017, 2020 SAP SE. All rights reserved.
* Copyright (c) 2023, Red Hat, Inc. and/or its affiliates.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
@@ -1740,7 +1740,7 @@ void VMError::report_and_die(int id, const char* message, const char* detail_fmt
ShowMessageBoxOnError = false;
}
- os::check_dump_limit(buffer, sizeof(buffer));
+ os::check_core_dump_prerequisites(buffer, sizeof(buffer));
// reset signal handlers or exception filter; make sure recursive crashes
// are handled properly.
@@ -2392,10 +2392,12 @@ static void print_process_memory_usage_platform(outputStream *st)
os::Linux::meminfo_t info;
if (os::Linux::query_process_memory_info(&info)) {
ssize_t phys_total_kb = os::physical_memory() / K;
- ssize_t phys_avail_kb = os::available_memory() / K;
+ physical_memory_size_type avail_mem = 0;
+ (void)os::available_memory(avail_mem);
+ physical_memory_size_type phys_avail_kb = avail_mem / K;
int rss_percentile = (int)(info.vmrss * 100.0 / phys_total_kb);
st->print_cr("Resident Set Size: " SSIZE_FORMAT "K (%d%% of "
- SSIZE_FORMAT "K total physical memory with " SSIZE_FORMAT "K free physical memory)",
+ SSIZE_FORMAT "K total physical memory with " PHYS_MEM_TYPE_FORMAT "K free physical memory)",
info.vmrss, rss_percentile, phys_total_kb, phys_avail_kb);
} else {
st->print_cr("Could not open /proc/self/status to get process memory related information");
@@ -2415,10 +2417,12 @@ static void print_process_memory_usage_platform(outputStream *st)
if (ret != 0) {
ssize_t rss_kb = pmex.WorkingSetSize / K;
ssize_t phys_total_kb = os::physical_memory() / K;
- ssize_t phys_avail_kb = os::available_memory() / K;
+ physical_memory_size_type avail_mem = 0;
+ (void)os::available_memory(avail_mem);
+ physical_memory_size_type phys_avail_kb = avail_mem / K;
int rss_percentile = (int)(rss_kb * 100.0 / phys_total_kb);
st->print_cr("Resident Set Size: " SSIZE_FORMAT "K (%d%% of "
- SSIZE_FORMAT "K total physical memory with " SSIZE_FORMAT "K free physical memory)",
+ SSIZE_FORMAT "K total physical memory with " PHYS_MEM_TYPE_FORMAT "K free physical memory)",
rss_kb, rss_percentile, phys_total_kb, phys_avail_kb);
} else {
st->print_cr("GetProcessMemoryInfo() call did not succeed");
@@ -2437,10 +2441,12 @@ static void print_process_memory_usage_platform(outputStream *st)
if (ret == KERN_SUCCESS) {
ssize_t rss_kb = info.resident_size / K;
ssize_t phys_total_kb = os::physical_memory() / K;
- ssize_t phys_avail_kb = os::available_memory() / K;
+ physical_memory_size_type avail_mem = 0;
+ (void)os::available_memory(avail_mem);
+ physical_memory_size_type phys_avail_kb = avail_mem / K;
int rss_percentile = (int)(rss_kb * 100.0 / phys_total_kb);
st->print_cr("Resident Set Size: " SSIZE_FORMAT "K (%d%% of "
- SSIZE_FORMAT "K total physical memory with " SSIZE_FORMAT "K free physical memory)",
+ SSIZE_FORMAT "K total physical memory with " PHYS_MEM_TYPE_FORMAT "K free physical memory)",
rss_kb, rss_percentile, phys_total_kb, phys_avail_kb);
} else {
st->print_cr("task_info() call did not succeed");
diff --git a/src/java.base/linux/classes/jdk/internal/platform/cgroupv2/CgroupV2Subsystem.java b/src/java.base/linux/classes/jdk/internal/platform/cgroupv2/CgroupV2Subsystem.java
index ddb4d8e27183..3bdd7dc2a64e 100644
--- a/src/java.base/linux/classes/jdk/internal/platform/cgroupv2/CgroupV2Subsystem.java
+++ b/src/java.base/linux/classes/jdk/internal/platform/cgroupv2/CgroupV2Subsystem.java
@@ -154,22 +154,39 @@ private long getFromCpuMax(int tokenIdx) {
@Override
public long getCpuShares() {
long sharesRaw = getLongVal("cpu.weight");
- if (sharesRaw == 100 || sharesRaw <= 0) {
+ // cg v2 value must be in range [1,10000]
+ if (sharesRaw == 100 || sharesRaw <= 0 || sharesRaw > 10000) {
return CgroupSubsystem.LONG_RETVAL_UNLIMITED;
}
int shares = (int)sharesRaw;
// CPU shares (OCI) value needs to get translated into
// a proper Cgroups v2 value. See:
- // https://github.com/containers/crun/blob/master/crun.1.md#cpu-controller
+ // https://github.com/containers/crun/blob/1.24/crun.1.md#cpu-controller
//
// Use the inverse of (x == OCI value, y == cgroupsv2 value):
- // ((262142 * y - 1)/9999) + 2 = x
+ // y = 10^(log2(x)^2/612 + 125/612 * log2(x) - 7.0/34.0)
//
- int x = 262142 * shares - 1;
- double frac = x/9999.0;
- x = ((int)frac) + 2;
+ // By re-arranging it to the standard quadratic form:
+ // log2(x)^2 + 125 * log2(x) - (126 + 612 * log_10(y)) = 0
+ //
+ // Therefore, log2(x) = (-125 + sqrt( 125^2 - 4 * (-(126 + 612 * log_10(y)))))/2
+ //
+ // As a result we have the inverse (we can discount substraction of the
+ // square root value since those values result in very small numbers and the
+ // cpu shares values - OCI - are in range [2-262144])
+ //
+ // x = 2^((-125 + sqrt(16129 + 2448* log10(y)))/2)
+ //
+ double logMultiplicand = Math.log10(shares);
+ double discriminant = 16129 + 2448 * logMultiplicand;
+ double squareRoot = Math.sqrt(discriminant);
+ double exponent = (-125 + squareRoot)/2;
+ double scaledValue = Math.pow(2, exponent);
+
+ int x = (int)scaledValue;
if ( x <= PER_CPU_SHARES ) {
- return PER_CPU_SHARES; // mimic cgroups v1
+ // Return the back-mapped value.
+ return x;
}
int f = x/PER_CPU_SHARES;
int lower_multiple = f * PER_CPU_SHARES;
diff --git a/src/java.base/share/classes/java/net/InetAddress.java b/src/java.base/share/classes/java/net/InetAddress.java
index fcc2e2700269..9fd5f4e59c9c 100644
--- a/src/java.base/share/classes/java/net/InetAddress.java
+++ b/src/java.base/share/classes/java/net/InetAddress.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1995, 2023, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1995, 2024, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -194,8 +194,8 @@
* caching. Likewise, a system admin can configure a different
* negative caching TTL value when needed or extend the usage of the stale data.
*
- *
Three Java security properties control the TTL values used for
- * positive and negative host name resolution caching:
+ *
Three Java {@linkplain java.security.Security security} properties control
+ * the TTL values used for positive and negative host name resolution caching:
*
*
*
networkaddress.cache.ttl
diff --git a/src/java.base/share/classes/java/net/doc-files/net-properties.html b/src/java.base/share/classes/java/net/doc-files/net-properties.html
index fc401e90b6b0..24f7a12a07fd 100644
--- a/src/java.base/share/classes/java/net/doc-files/net-properties.html
+++ b/src/java.base/share/classes/java/net/doc-files/net-properties.html
@@ -1,6 +1,6 @@
", 3);
+ if (cend < 0) return false;
+ i = (unsigned) cend + 3;
+ continue;
+ }
+ if (i + 9 <= len && !memcmp (svg + i, "", 3);
+ if (cend < 0) return false;
+ i = (unsigned) cend + 3;
+ continue;
+ }
+
+ bool closing = (i + 1 < len && svg[i + 1] == '/');
+ bool special = (i + 1 < len && (svg[i + 1] == '!' || svg[i + 1] == '?'));
+
+ unsigned gt = i + 1;
+ char quote = 0;
+ while (gt < len)
+ {
+ char c = svg[gt];
+ if (quote)
+ {
+ if (c == quote) quote = 0;
+ }
+ else
+ {
+ if (c == '"' || c == '\'')
+ quote = c;
+ else if (c == '>')
+ break;
+ }
+ gt++;
+ }
+ if (gt >= len)
+ return false;
+
+ if (special)
+ {
+ i = gt + 1;
+ continue;
+ }
+
+ unsigned p = i + (closing ? 2 : 1);
+ while (p < gt && isspace ((unsigned char) svg[p])) p++;
+ const char *name = svg + p;
+ unsigned name_len = 0;
+ while (p + name_len < gt)
+ {
+ unsigned char c = (unsigned char) name[name_len];
+ if (!(isalnum (c) || c == '_' || c == '-' || c == ':'))
+ break;
+ name_len++;
+ }
+ bool is_defs = (name_len == 4 && !memcmp (name, "defs", 4));
+
+ if (closing)
+ {
+ if (!depth)
+ {
+ i = gt + 1;
+ continue;
+ }
+
+ open_elem_t e = stack[--depth];
+ unsigned end = gt + 1;
+
+ if (e.id.len)
+ {
+ if (unlikely (!id_entries->push_or_fail (id_entry_t {e.id, (uint32_t) e.start, (uint32_t) end})))
+ return false;
+
+ if (e.in_defs_content)
+ {
+ if (unlikely (!defs_entries->push_or_fail ()))
+ return false;
+ auto &slot = defs_entries->tail ();
+ slot.id = e.id;
+ slot.start = e.start;
+ slot.end = end;
+ }
+
+ hb_codepoint_t gid;
+ if (parse_glyph_id_span (e.id, &gid))
+ {
+ if (unlikely (!glyph_spans->push_or_fail (glyph_entry_t {gid, (uint32_t) e.start, (uint32_t) end})))
+ return false;
+ }
+ }
+
+ if (e.is_defs && defs_depth)
+ defs_depth--;
+
+ i = end;
+ continue;
+ }
+
+ SVG::svg_id_span_t id = {};
+ parse_id_in_start_tag (svg, i, gt, &id);
+
+ unsigned r = gt;
+ while (r > i && isspace ((unsigned char) svg[r - 1])) r--;
+ bool self_closing = (r > i && svg[r - 1] == '/');
+
+ open_elem_t e = {};
+ e.start = i;
+ e.id = id;
+ e.in_defs_content = defs_depth > 0;
+ e.is_defs = is_defs;
+
+ if (self_closing)
+ {
+ unsigned end = gt + 1;
+ if (e.id.len)
+ {
+ if (unlikely (!id_entries->push_or_fail (id_entry_t {e.id, (uint32_t) e.start, (uint32_t) end})))
+ return false;
+
+ if (e.in_defs_content)
+ {
+ if (unlikely (!defs_entries->push_or_fail ()))
+ return false;
+ auto &slot = defs_entries->tail ();
+ slot.id = e.id;
+ slot.start = e.start;
+ slot.end = end;
+ }
+
+ hb_codepoint_t gid;
+ if (parse_glyph_id_span (e.id, &gid))
+ {
+ if (unlikely (!glyph_spans->push_or_fail (glyph_entry_t {gid, (uint32_t) e.start, (uint32_t) end})))
+ return false;
+ }
+ }
+ }
+ else
+ {
+ if (unlikely (depth >= MAX_DEPTH))
+ return false;
+ stack[depth++] = e;
+ if (is_defs)
+ defs_depth++;
+ }
+
+ i = gt + 1;
+ }
+
+ return true;
+}
+
+} /* namespace _hb_svg_cache_impl */
+
+inline
+SVG::accelerator_t::accelerator_t (hb_face_t *face)
+{
+ table = hb_sanitize_context_t ().reference_table