diff --git a/make/Main.gmk b/make/Main.gmk index fbd394c147282..cdff43b82f3a7 100644 --- a/make/Main.gmk +++ b/make/Main.gmk @@ -278,6 +278,18 @@ $(eval $(call SetupTarget, eclipse-mixed-env, \ ARGS := --always-make, \ )) +$(eval $(call SetupTarget, hotspot-xcode-project, \ + MAKEFILE := ide/xcode/hotspot/CreateXcodeProject, \ + TARGET := build, \ + DEPS := hotspot compile-commands-hotspot jdk-image, \ +)) + +$(eval $(call SetupTarget, open-hotspot-xcode-project, \ + MAKEFILE := ide/xcode/hotspot/CreateXcodeProject, \ + TARGET := open, \ + DEPS := hotspot-xcode-project, \ +)) + ALL_TARGETS += $(HOTSPOT_VARIANT_TARGETS) $(HOTSPOT_VARIANT_GENSRC_TARGETS) \ $(HOTSPOT_VARIANT_LIBS_TARGETS) $(HOTSPOT_VARIANT_STATIC_LIBS_TARGETS) diff --git a/make/common/FileUtils.gmk b/make/common/FileUtils.gmk index cda5932395fca..ea1d0b6d4af05 100644 --- a/make/common/FileUtils.gmk +++ b/make/common/FileUtils.gmk @@ -189,6 +189,11 @@ else endef endif +define copy-and-chmod-executable + $(install-file) + $(CHMOD) a+rx $@ +endef + ################################################################################ # Recursive wildcard function. Walks down directories recursively and matches diff --git a/make/common/JavaCompilation.gmk b/make/common/JavaCompilation.gmk index 1503c86aff1df..ca363f7cb5474 100644 --- a/make/common/JavaCompilation.gmk +++ b/make/common/JavaCompilation.gmk @@ -282,8 +282,26 @@ define SetupJavaCompilationBody $1_FLAGS += -Xlint:$$(call CommaList, $$(addprefix -, $$($1_DISABLED_WARNINGS))) endif - ifneq ($$($1_CLASSPATH), ) - $1_FLAGS += -cp $$(call PathList, $$($1_CLASSPATH)) + $1_AUGMENTED_CLASSPATH := $$($1_CLASSPATH) + $1_API_TARGET := $$($1_BIN)$$($1_MODULE_SUBDIR)/_the.$1_pubapi + $1_API_INTERNAL := $$($1_BIN)$$($1_MODULE_SUBDIR)/_the.$1_internalapi + + ifeq ($$($1_CREATE_API_DIGEST), true) + $1_API_DIGEST_FLAGS := \ + -Xplugin:"depend $$($1_API_TARGET)" \ + "-XDinternalAPIPath=$$($1_API_INTERNAL)" \ + "-XDLOG_LEVEL=$(LOG_LEVEL)" \ + # + + $1_EXTRA_DEPS := $$(BUILDTOOLS_OUTPUTDIR)/depend/_the.COMPILE_DEPEND_batch + # including the compilation output on the classpath, so that incremental + # compilations in unnamed module can refer to other classes from the same + # source root, which are not being recompiled in this compilation: + $1_AUGMENTED_CLASSPATH += $$(BUILDTOOLS_OUTPUTDIR)/depend $$($1_BIN) + endif + + ifneq ($$($1_AUGMENTED_CLASSPATH), ) + $1_FLAGS += -cp $$(call PathList, $$($1_AUGMENTED_CLASSPATH)) endif # Make sure the dirs exist, or that one of the EXTRA_FILES, that may not @@ -411,9 +429,6 @@ define SetupJavaCompilationBody $1_MODFILELIST := $$($1_BIN)$$($1_MODULE_SUBDIR)/_the.$1_batch.modfiles $1_MODFILELIST_FIXED := $$($1_MODFILELIST).fixed - $1_API_TARGET := $$($1_BIN)$$($1_MODULE_SUBDIR)/_the.$1_pubapi - $1_API_INTERNAL := $$($1_BIN)$$($1_MODULE_SUBDIR)/_the.$1_internalapi - # Put headers in a temp dir to filter out those that actually # changed before copying them to the real header dir. ifneq (,$$($1_HEADERS)) @@ -442,17 +457,6 @@ define SetupJavaCompilationBody $1_VARDEPS_FILE := $$(call DependOnVariable, $1_VARDEPS, \ $$($1_BIN)$$($1_MODULE_SUBDIR)/_the.$1.vardeps) - ifeq ($$($1_CREATE_API_DIGEST), true) - $1_API_DIGEST_FLAGS := \ - -classpath $$(BUILDTOOLS_OUTPUTDIR)/depend \ - -Xplugin:"depend $$($1_API_TARGET)" \ - "-XDinternalAPIPath=$$($1_API_INTERNAL)" \ - "-XDLOG_LEVEL=$(LOG_LEVEL)" \ - # - - $1_EXTRA_DEPS := $$(BUILDTOOLS_OUTPUTDIR)/depend/_the.COMPILE_DEPEND_batch - endif - # Create a file with all sources, to pass to javac in an @file. # $$($1_VARDEPS_FILE) is used as dependency to track changes in set of # list of files. diff --git a/make/common/NativeCompilation.gmk b/make/common/NativeCompilation.gmk index abd4f65f7536e..5f1c6539cdbd4 100644 --- a/make/common/NativeCompilation.gmk +++ b/make/common/NativeCompilation.gmk @@ -222,7 +222,7 @@ define SetupNativeCompilationBody ifeq ($(GENERATE_COMPILE_COMMANDS_ONLY), true) # Override all targets (this is a hack) - $1 := $$($1_ALL_OBJS_JSON) + $1 := $$($1_ALL_OBJS_JSON) $$($1_LDFLAGS_FILE) endif endef diff --git a/make/common/native/Link.gmk b/make/common/native/Link.gmk index ca03c6ee6b12f..d64df1bebb996 100644 --- a/make/common/native/Link.gmk +++ b/make/common/native/Link.gmk @@ -198,4 +198,16 @@ define CreateDynamicLibraryOrExecutable $(CODESIGN) -f -s $$($1_CODESIGN_OPTS) --entitlements \ $$(call GetEntitlementsFile, $$@) $$@) endif + + # This is for IDE integration purposes only, and is not normally generated + $1_LDFLAGS_FILE := $$(MAKESUPPORT_OUTPUTDIR)/compile-commands/$$($1_NAME)-ldflags.txt + + $1_ALL_LD_ARGS := $$($1_LDFLAGS) $$($1_EXTRA_LDFLAGS) $$($1_SYSROOT_LDFLAGS) \ + $$($1_LIBS) $$($1_EXTRA_LIBS) + + $$($1_LDFLAGS_FILE): $$($1_VARDEPS_FILE) + $$(call LogInfo, Creating compile commands linker flags output for $$($1_BASENAME)) + $$(call MakeDir, $$(dir $$@)) + $$(ECHO) $$($1_ALL_LD_ARGS) > $$@ + endef diff --git a/make/conf/module-loader-map.conf b/make/conf/module-loader-map.conf index e904031186dee..1062b780a79ff 100644 --- a/make/conf/module-loader-map.conf +++ b/make/conf/module-loader-map.conf @@ -94,48 +94,26 @@ PLATFORM_MODULES_windows= \ NATIVE_ACCESS_MODULES= \ java.base \ - java.datatransfer \ java.desktop \ java.instrument \ - java.logging \ java.management \ - java.management.rmi \ - java.naming \ - java.net.http \ java.prefs \ java.rmi \ - java.scripting \ - java.se \ java.security.jgss \ - java.security.sasl \ java.smartcardio \ - java.sql \ - java.sql.rowset \ - java.transaction.xa \ - java.xml \ - java.xml.crypto \ jdk.accessibility \ - jdk.charsets \ + jdk.attach \ jdk.crypto.cryptoki \ - jdk.dynalink \ - jdk.httpserver \ - jdk.incubator.vector \ + jdk.crypto.mscapi \ + jdk.hotspot.agent \ jdk.internal.le \ jdk.internal.vm.ci \ + jdk.jdi \ jdk.jfr \ - jdk.jsobject \ - jdk.localedata \ + jdk.jpackage \ jdk.management \ jdk.management.agent \ - jdk.management.jfr \ - jdk.naming.dns \ - jdk.naming.rmi \ jdk.net \ - jdk.nio.mapmode \ jdk.sctp \ jdk.security.auth \ - jdk.security.jgss \ - jdk.unsupported \ - jdk.xml.dom \ - jdk.zipfs \ # diff --git a/make/ide/visualstudio/hotspot/CreateVSProject.gmk b/make/ide/visualstudio/hotspot/CreateVSProject.gmk index cd093d3c6de85..11efad2b4f23d 100644 --- a/make/ide/visualstudio/hotspot/CreateVSProject.gmk +++ b/make/ide/visualstudio/hotspot/CreateVSProject.gmk @@ -1,5 +1,5 @@ # -# Copyright (c) 2016, 2023, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2016, 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 @@ -83,7 +83,7 @@ ifeq ($(call isTargetOs, windows), true) ################################################################################ # Build the ProjectCreator java tool. - TOOLS_OUTPUTDIR := $(HOTSPOT_OUTPUTDIR)/support/ide_classes + TOOLS_OUTPUTDIR := $(MAKESUPPORT_OUTPUTDIR)/ide/visualstudio $(eval $(call SetupJavaCompilation, BUILD_PROJECT_CREATOR, \ TARGET_RELEASE := $(TARGET_RELEASE_BOOTJDK), \ diff --git a/make/ide/xcode/hotspot/CreateXcodeProject.gmk b/make/ide/xcode/hotspot/CreateXcodeProject.gmk new file mode 100644 index 0000000000000..db8f7f401eff4 --- /dev/null +++ b/make/ide/xcode/hotspot/CreateXcodeProject.gmk @@ -0,0 +1,112 @@ +# +# Copyright (c) 2023, 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 +# under the terms of the GNU General Public License version 2 only, as +# published by the Free Software Foundation. Oracle designates this +# particular file as subject to the "Classpath" exception as provided +# by Oracle in the LICENSE file that accompanied this code. +# +# This code is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +# version 2 for more details (a copy is included in the LICENSE file that +# accompanied this code). +# +# You should have received a copy of the GNU General Public License version +# 2 along with this work; if not, write to the Free Software Foundation, +# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. +# +# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA +# or visit www.oracle.com if you need additional information or have any +# questions. +# + +# This must be the first rule +default: all + +include $(SPEC) +include MakeBase.gmk +include CopyFiles.gmk +include Execute.gmk +include JavaCompilation.gmk + +ifeq ($(call isTargetOs, macosx), true) + ############################################################################## + # Build the XcodeProjectMaker java tool. + + PROJECT_MAKER_DIR := $(TOPDIR)/make/ide/xcode/hotspot + TOOLS_OUTPUTDIR := $(MAKESUPPORT_OUTPUTDIR)/ide/xcode + IDE_OUTPUTDIR := $(OUTPUTDIR)/xcode + PROJECT_FILE_NAME := hotspot.xcodeproj + + COMPILE_COMMAND_FILE := $(OUTPUTDIR)/compile_commands.json + LINKER_FLAGS_FILE := $(MAKESUPPORT_OUTPUTDIR)/compile-commands/jvm-ldflags.txt + + $(eval $(call SetupJavaCompilation, BUILD_PROJECT_CREATOR, \ + TARGET_RELEASE := $(TARGET_RELEASE_BOOTJDK), \ + SRC := $(PROJECT_MAKER_DIR)/src/classes, \ + BIN := $(TOOLS_OUTPUTDIR), \ + DISABLED_WARNINGS := rawtypes unchecked serial, \ + )) + + TARGETS += $(BUILD_PROJECT_CREATOR) + + # Run the XcodeProjectMaker tool + PROJECT_CREATOR_TOOL := $(JAVA_SMALL) -cp $(TOOLS_OUTPUTDIR) XcodeProjectMaker + + ifneq ($(findstring $(LOG_LEVEL), debug trace), ) + XCODE_PROJ_DEBUG_OPTION := -d + endif + + XCODE_PROJ_VARDEPS := $(WORKSPACE_ROOT) $(IDE_OUTPUTDIR) \ + $(PROJECT_MAKER_DIR)/data $(COMPILE_COMMAND_FILE) $(LINKER_FLAGS_FILE) + XCODE_PROJ_VARDEPS_FILE := $(call DependOnVariable, XCODE_PROJ_VARDEPS, \ + $(TOOLS_OUTPUTDIR)/xcodeproj.vardeps) + + $(eval $(call SetupExecute, build_xcode_project, \ + WARN := Generating Xcode project file, \ + DEPS := $(BUILD_PROJECT_CREATOR) $(COMPILE_COMMAND_FILE) \ + $(LINKER_FLAGS_FILE) $(XCODE_PROJ_VARDEPS_FILE), \ + OUTPUT_DIR := $(TOOLS_OUTPUTDIR), \ + COMMAND := $(PROJECT_CREATOR_TOOL) $(WORKSPACE_ROOT) $(IDE_OUTPUTDIR) \ + $(PROJECT_MAKER_DIR)/data $(COMPILE_COMMAND_FILE) \ + $(LINKER_FLAGS_FILE) $(XCODE_PROJ_DEBUG_OPTION), \ + )) + + TARGETS += $(build_xcode_project) + + $(eval $(call SetupCopyFiles, copy_xcode_project, \ + DEST := $(IDE_OUTPUTDIR), \ + FILES := $(PROJECT_MAKER_DIR)/data/script_before.sh $(PROJECT_MAKER_DIR)/data/script_after.sh , \ + MACRO := copy-and-chmod-executable, \ + )) + + TARGETS += $(copy_xcode_project) + + $(eval $(call SetupExecute, open_xcode_project, \ + INFO := Opening Xcode project file, \ + DEPS := $(build_xcodeproject_TARGET) FORCE, \ + OUTPUT_DIR := $(TOOLS_OUTPUTDIR), \ + COMMAND := open $(IDE_OUTPUTDIR)/$(PROJECT_FILE_NAME), \ + )) + + TARGETS += $(open_xcode_project) + + # Always call open without considering dependencies being up to date + FORCE: + + build: $(build_xcode_project) $(copy_xcode_project) + + open: $(open_xcode_project) + + all: $(TARGETS) +else + build: + open: + all: + $(info Xcode projects are only supported on macOS) +endif + +.PHONY: default all build open diff --git a/make/ide/xcode/hotspot/data/Breakpoints_v2.xcbkptlist.template b/make/ide/xcode/hotspot/data/Breakpoints_v2.xcbkptlist.template new file mode 100644 index 0000000000000..42f6c9a689aaa --- /dev/null +++ b/make/ide/xcode/hotspot/data/Breakpoints_v2.xcbkptlist.template @@ -0,0 +1,41 @@ + + + + + + + + + + + + + + + + + + + diff --git a/make/ide/xcode/hotspot/data/jvm.xcscheme.template b/make/ide/xcode/hotspot/data/jvm.xcscheme.template new file mode 100644 index 0000000000000..894d4ffc46fd9 --- /dev/null +++ b/make/ide/xcode/hotspot/data/jvm.xcscheme.template @@ -0,0 +1,112 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/make/ide/xcode/hotspot/data/project.pbxproj.template b/make/ide/xcode/hotspot/data/project.pbxproj.template new file mode 100644 index 0000000000000..2af90477210c5 --- /dev/null +++ b/make/ide/xcode/hotspot/data/project.pbxproj.template @@ -0,0 +1,207 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 48; + objects = { + +/* Begin PBXBuildFile section */ +TEMPLATE_PBXBUILDFILE +/* End PBXBuildFile section */ + +/* Begin PBXFileReference section */ + D60000000000000000000003 /* script_before.sh */ = {isa = PBXFileReference; lastKnownFileType = text.script.sh; path = script_before.sh; sourceTree = ""; }; + D60000000000000000000002 /* script_after.sh */ = {isa = PBXFileReference; lastKnownFileType = text.script.sh; path = script_after.sh; sourceTree = ""; }; + D60000000000000000000006 /* libjvm.dylib */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.dylib"; includeInIndex = 0; path = libjvm.dylib; sourceTree = BUILT_PRODUCTS_DIR; }; +TEMPLATE_PBXFILEREFERENCE +/* End PBXFileReference section */ + +/* Begin PBXGroup section */ + D60000000000000000000004 /* scripts */ = { + isa = PBXGroup; + children = ( + D60000000000000000000003 /* script_before.sh */, + D60000000000000000000002 /* script_after.sh */, + ); + name = scripts; + sourceTree = ""; + }; + D60000000000000000000005 /* Products */ = { + isa = PBXGroup; + children = ( + D60000000000000000000006 /* libjvm.dylib */, + ); + name = Products; + sourceTree = ""; + }; + D60000000000000000000001 = { + isa = PBXGroup; + children = ( + D60000000000000000000004 /* scripts */, +TEMPLATE_GROUP_GENSRC /* gensrc */, +TEMPLATE_GROUP_SRC /* src */, +TEMPLATE_GROUP_TEST /* test */, + D60000000000000000000005 /* Products */, + ); + sourceTree = ""; + }; +TEMPLATE_GROUPS +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + D60000000000000000000000 /* jvm */ = { + isa = PBXNativeTarget; + buildConfigurationList = D6000000000000000000000F /* Build configuration list for PBXNativeTarget "jvm" */; + buildPhases = ( + D60000000000000000000007 /* Run script_before */, + D60000000000000000000008 /* Sources */, + D6000000000000000000000A /* Run script_after */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = jvm; + productName = jvm; + productReference = D60000000000000000000006 /* libjvm.dylib */; + productType = "com.apple.product-type.library.dynamic"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + D60000000000000000000010 /* Project object */ = { + isa = PBXProject; + attributes = { + LastUpgradeCheck = 0900; + ORGANIZATIONNAME = Oracle; + TargetAttributes = { + D60000000000000000000000 = { + CreatedOnToolsVersion = 9.0; + ProvisioningStyle = Automatic; + }; + }; + }; + buildConfigurationList = D6000000000000000000000E /* Build configuration list for PBXProject "jvm" */; + compatibilityVersion = "Xcode 8.0"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + ); + mainGroup = D60000000000000000000001; + productRefGroup = D60000000000000000000005 /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + D60000000000000000000000 /* jvm */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXShellScriptBuildPhase section */ + D60000000000000000000007 /* Run script_before */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Run script_before"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "cd $PROJECT_DIR;\ntime ./script_before.sh;\n"; + }; + D6000000000000000000000A /* Run script_after */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Run script_after"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "cd $PROJECT_DIR;\ntime ./script_after.sh;\n"; + }; +/* End PBXShellScriptBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + D60000000000000000000008 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( +TEMPLATE_PBXSOURCESSBUILDPHASE + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin XCBuildConfiguration section */ + D6000000000000000000000B /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CODE_SIGN_IDENTITY = "-"; + CONFIGURATION_BUILD_DIR = build/jdk/lib/server; + CONFIGURATION_TEMP_DIR = build; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + MTL_ENABLE_DEBUG_INFO = NO; + OBJROOT = build; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = macosx; + }; + name = Release; + }; + D6000000000000000000000D /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + CONFIGURATION_BUILD_DIR = "$(BUILD_DIR)"; + EXECUTABLE_PREFIX = lib; + FRAMEWORK_SEARCH_PATHS = ( +TEMPLATE_FRAMEWORK_SEARCH_PATHS + ); + OTHER_CFLAGS = ( +TEMPLATE_OTHER_CFLAGS + ); + OTHER_LDFLAGS = ( +TEMPLATE_OTHER_LDFLAGS + ); + PRODUCT_NAME = "$(TARGET_NAME)"; + SKIP_INSTALL = YES; + SYMROOT = build/jdk/lib/server; + USER_HEADER_SEARCH_PATHS = ( +TEMPLATE_USER_HEADER_SEARCH_PATHS + ); + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + D6000000000000000000000E /* Build configuration list for PBXProject "jvm" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + D6000000000000000000000B /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + D6000000000000000000000F /* Build configuration list for PBXNativeTarget "jvm" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + D6000000000000000000000D /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = D60000000000000000000010 /* Project object */; +} diff --git a/make/ide/xcode/hotspot/data/runJ2Demo.xcscheme.template b/make/ide/xcode/hotspot/data/runJ2Demo.xcscheme.template new file mode 100644 index 0000000000000..fc38775300496 --- /dev/null +++ b/make/ide/xcode/hotspot/data/runJ2Demo.xcscheme.template @@ -0,0 +1,112 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/make/ide/xcode/hotspot/data/script_after.sh b/make/ide/xcode/hotspot/data/script_after.sh new file mode 100644 index 0000000000000..8ce4507faf1ae --- /dev/null +++ b/make/ide/xcode/hotspot/data/script_after.sh @@ -0,0 +1,34 @@ +#!/bin/bash +# +# 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 +# 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. +# + +echo "running script_after.sh" + +readonly JDK_LIB_PATH="build/jdk/lib/server/libjvm.dylib"; + +if [ ! -f ${JDK_LIB_PATH} ] ; then +{ + echo ">>>>>>> Cannot find ${JDK_LIB_PATH}, the build failed!?"; + exit 1; +} +fi diff --git a/make/ide/xcode/hotspot/data/script_before.sh b/make/ide/xcode/hotspot/data/script_before.sh new file mode 100644 index 0000000000000..5ba7e62e428be --- /dev/null +++ b/make/ide/xcode/hotspot/data/script_before.sh @@ -0,0 +1,67 @@ +#!/bin/bash +# +# 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 +# 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. +# + +echo "running script_before.sh" + +readonly JDK_BUILD_PATH=".."; +readonly JAVAC_LOCATE_PATTERN="images/jdk/bin/javac"; +readonly HOTSPOT_TOUCH_FILE="../../../src/hotspot/os/posix/jvm_posix.cpp"; + +echo ">>>>>>> Making a copy of JDK ..."; + +javac_file_array=( $(find ${JDK_BUILD_PATH} | grep ${JAVAC_LOCATE_PATTERN}) ); +javac_file=${javac_file_array[0]}; +if [ -z ${javac_file} ] ; then +{ + echo ">>>>>>> ERROR: could not locate ${JAVAC_LOCATE_PATTERN} (did you remember to do \"make images\"?)"; + exit 1; +} +fi + +jdk_build_path=$(dirname $(dirname ${javac_file})); +if [ ! -f "build/${JAVAC_LOCATE_PATTERN}" ] ; then +{ + echo ">>>>>>> Copying jdk over..."; + rsync -a "${jdk_build_path}" "build/"; +} +fi + +# the following files will be supplied by the Xcode build +rm -rf "build/jdk/lib/server/libjvm.dylib"; +rm -rf "build/jdk/lib/server/libjvm.dylib.dSYM"; + +echo ">>>>>>> DONE"; + +echo ">>>>>>> Touching ${HOTSPOT_TOUCH_FILE} to force HotspotVM rebuilt"; +if [ ! -f ${HOTSPOT_TOUCH_FILE} ] ; then +{ + echo ">>>>>>> Cannot find ${HOTSPOT_TOUCH_FILE}"; + exit 1; +} +fi +touch ${HOTSPOT_TOUCH_FILE}; + +echo ">>>>>>> DONE"; + +echo ">>>>>>> Xcode should be building the HotspotVM now..."; diff --git a/make/ide/xcode/hotspot/src/classes/DiskFile.java b/make/ide/xcode/hotspot/src/classes/DiskFile.java new file mode 100644 index 0000000000000..bef90b427ae43 --- /dev/null +++ b/make/ide/xcode/hotspot/src/classes/DiskFile.java @@ -0,0 +1,291 @@ +/* + * 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +import java.io.File; +import java.nio.file.Path; +import java.util.ArrayList; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Locale; +import java.util.Map; +import java.util.Set; +import java.util.TreeSet; + +public class DiskFile extends LinkedHashMap implements Comparable { + // xcode id ex: D50000000000000000000000 + private static long xcodeIdCount = 0xF0000001; + private final Path path; + private final boolean directory; + private final String xcodeId; + private final String xcodeId2; + private Iterable compilerFlags; + + public DiskFile(String path, boolean directory) { + this(stringToPath(path), directory); + } + + private DiskFile(Path path, boolean directory) { + this.path = path; + this.directory = directory; + this.compilerFlags = null; + this.xcodeId = getNextXcodeId(); + this.xcodeId2 = getNextXcodeId(); + } + + private static Path stringToPath(String string) { + if (string != null) { + return new File(string).toPath(); + } else { + return null; + } + } + + private static Path clipPath(Path path, String clip) { + return clipPath(path.toString(), clip); + } + + private static Path clipPath(String path, String clip) { + String subpath = path; + if (path.contains(clip)) { + subpath = clip; + } + int index = path.indexOf(subpath); + return stringToPath(path.substring(index)); + } + + private String getNextXcodeId() { + String id = "D5FFFFFF" + Long.toHexString(xcodeIdCount).toUpperCase(Locale.ROOT); + xcodeIdCount++; + + return id; + } + + private String getPath() { + return this.path.toString(); + } + + public boolean isDirectory() { + return this.directory; + } + + public void markAsCompiled(List compilerFlags) { + this.compilerFlags = compilerFlags; + } + + private boolean isCompiled() { + return (this.compilerFlags != null); + } + + public String getXcodeId() { + return this.xcodeId; + } + + public String generatePbxSourcesBuildPhase() { + String string = ""; + if (isCompiled()) { + String fileName = getFileName(); + string += String.format(" %s /* %s in Sources */,\n", this.xcodeId2, fileName); + } else if (isDirectory()) { + for (Map.Entry entry : entrySet()) { + DiskFile file = entry.getValue(); + string += file.generatePbxSourcesBuildPhase(); + } + } + return string; + } + + // D5FFFFFFFFFFFFFFF0006506 /* vm_version.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D5FFFFFFFFFFFFFFF0006505 /* vm_version.cpp */; settings = {COMPILER_FLAGS = HEREHERE; }; }; + public String generatePbxBuildFile() { + String string = ""; + if (isCompiled()) { + String flagsString = ""; + for (String flag : this.compilerFlags) { + flagsString += flag.replace("\"", "\\\\\"") + " "; + } + String fileName = getFileName(); + string += String.format(" %s /* %s in Sources */ = {isa = PBXBuildFile; fileRef = %s /* %s */; settings = {COMPILER_FLAGS = \"%s\"; }; };\n", this.xcodeId2, fileName, this.xcodeId, fileName, flagsString); + } else if (isDirectory()) { + for (Map.Entry entry : entrySet()) { + DiskFile file = entry.getValue(); + string += file.generatePbxBuildFile(); + } + } + return string; + } + + public String generatePbxFileReference(String relativePathToRoot) { + String string = ""; + if (!isDirectory()) { + String fileName = getFileName(); + String suffix = getFileNameSuffix(); + string += String.format(" %s /* %s */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = %s%s; name = %s; path = \"%s%s\"; sourceTree = \"\"; };\n", this.xcodeId, fileName, fileName, suffix, fileName, relativePathToRoot, getPath()); + } else if (isDirectory()) { + for (Map.Entry entry : entrySet()) { + DiskFile file = entry.getValue(); + string += file.generatePbxFileReference(relativePathToRoot); + } + } + return string; + } + + public String generatePbxGroup() { + String string = String.format(" %s /* %s */ = {\n isa = PBXGroup;\n children = (\n", this.xcodeId, getFileName()); + + Set sortedSet = new TreeSet<>(values()); + + for (DiskFile file : sortedSet) { + string += String.format(" %s /* %s */,\n", file.getXcodeId(), file.getFileName()); + } + string += String.format(" );\n name = %s;\n sourceTree = \"\";\n };\n", getFileName()); + + for (DiskFile file : sortedSet) { + if (file.isDirectory()) { + string += file.generatePbxGroup(); + } + } + + return string; + } + + private ArrayList getFiles(ArrayList array) { + for (Map.Entry entry : entrySet()) { + DiskFile file = entry.getValue(); + if (file.isDirectory()) { + array.add(file); + array = file.getFiles(array); + } else { + array.add(file); + } + } + return array; + } + + public ArrayList getFiles() { + return getFiles(new ArrayList<>()); + } + + public String getFilePath() { + return this.path.toString(); + } + + private String getFileName() { + Path fileName = this.path.getFileName(); + if (fileName != null) { + return fileName.toString(); + } else { + return this.path.toString(); + } + } + + private String getFileNameNoSuffix() { + String string; + Path fileName = this.path.getFileName(); + if (fileName != null) { + string = fileName.toString(); + int index = string.indexOf('.'); + if (index >= 0) { + string = string.substring(0, index); + } + } else { + string = this.path.toString(); + } + return string; + } + + private String getFileNameSuffix() { + String fileName = getFileName(); + int index = fileName.indexOf('.'); + if (index >= 0) { + return fileName.substring(index); + } else { + return ""; + } + } + + public DiskFile getChild(String fileName) { + DiskFile child = null; + for (Map.Entry entry : entrySet()) { + DiskFile file = entry.getValue(); + if (file.getFileName().equals(fileName)) { + child = entry.getValue(); + break; + } else if (file.isDirectory()) { + child = file.getChild(fileName); + if (child != null) { + break; + } + } + } + return child; + } + + private DiskFile getParent(Path path) { + Path pathParent = path.getParent(); + DiskFile parent = get(pathParent); + if (parent == null) { + if (this.path.equals(pathParent)) { + parent = this; + } else { + parent = getParent(pathParent).get(pathParent); + } + parent.putIfAbsent(path, new DiskFile(path, true)); + } + return parent; + } + + public void addFile(Path path, String clip) { + path = clipPath(path, clip); + DiskFile parent = getParent(path); + parent.put(path, new DiskFile(path, false)); + } + + public void addDirectory(Path path, String clip) { + path = clipPath(path, clip); + DiskFile parent = getParent(path); + parent.putIfAbsent(path, new DiskFile(path, true)); + } + + @Override + public int compareTo(DiskFile file) { + // ".hpp", then ".inline.hpp", then ".cpp" + int equal = getFileNameNoSuffix().compareTo(file.getFileNameNoSuffix()); + if (equal == 0) { + String suffix1 = getFileNameSuffix(); + String suffix2 = file.getFileNameSuffix(); + if (!suffix1.equals(".inline.hpp") && !suffix2.equals(".inline.hpp")) { + // .hpp before .cpp + equal = -(getFileNameSuffix().compareTo(file.getFileNameSuffix())); + } else if (suffix1.equals(".inline.hpp") && suffix2.equals(".hpp")) { + return 1; + } else if (suffix1.equals(".inline.hpp") && suffix2.equals(".cpp")) { + return -1; + } else if (suffix1.equals(".hpp") && suffix2.equals(".inline.hpp")) { + return -1; + } else if (suffix1.equals(".cpp") && suffix2.equals(".inline.hpp")) { + return 1; + } + } + return equal; + } +} diff --git a/make/ide/xcode/hotspot/src/classes/XcodeProjectMaker.java b/make/ide/xcode/hotspot/src/classes/XcodeProjectMaker.java new file mode 100644 index 0000000000000..9e262a8277811 --- /dev/null +++ b/make/ide/xcode/hotspot/src/classes/XcodeProjectMaker.java @@ -0,0 +1,754 @@ +/* + * 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +import java.io.File; +import java.io.IOException; +import java.nio.file.FileSystemLoopException; +import java.nio.file.FileVisitResult; +import java.nio.file.FileVisitor; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.nio.file.attribute.BasicFileAttributes; +import java.nio.file.attribute.PosixFilePermission; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.TreeSet; + +public final class XcodeProjectMaker { + private static final String JDK_SCRIPT_TOKEN_1 = "configure"; + private static final String JDK_SCRIPT_TOKEN_2 = ".jcheck"; + private static final String COMPILER_LINE_HEADER = "-I"; + private static final String COMPILER_IFRAMEWORK = "-iframework"; + private static final String COMPILER_FFRAMEWORK = "-F"; + private static final String SRC_HOTSPOT_PATH = "/src/hotspot"; + private static final String TEST_HOTSPOT_PATH = "/test/hotspot/gtest"; + private static final String ALIAS_JAVA_OLD = "java_old.sh"; + private static final String ALIAS_JAVA_NEW = "java_new.sh"; + private static final String JDK_BIN_JAVA = "/jdk/bin/java"; + private static final String FILE_TOKEN = "\"file\": "; + private static final String COMMAND_TOKEN = "\"command\": "; + private static final String QUOTE_START_TOKEN = "'\\\""; + private static final String QUOTE_END_TOKEN = "\\\"'"; + private static final String VERSION = "2.0.0"; + private static final String EXCLUDE_PARSE_TOKEN_1 = "gtest"; + private static final String TEMPLATE_FRAMEWORK_SEARCH_PATHS = "TEMPLATE_FRAMEWORK_SEARCH_PATHS"; + private static final String TEMPLATE_OTHER_CFLAGS = "TEMPLATE_OTHER_CFLAGS"; + private static final String TEMPLATE_OTHER_LDFLAGS = "TEMPLATE_OTHER_LDFLAGS"; + private static final String TEMPLATE_USER_HEADER_SEARCH_PATHS = "TEMPLATE_USER_HEADER_SEARCH_PATHS"; + private static final String TEMPLATE_GROUP_GENSRC = "TEMPLATE_GROUP_GENSRC"; + private static final String TEMPLATE_GROUP_SRC = "TEMPLATE_GROUP_SRC"; + private static final String TEMPLATE_GROUP_TEST = "TEMPLATE_GROUP_TEST"; + private static final String TEMPLATE_GROUPS = "TEMPLATE_GROUPS"; + private static final String TEMPLATE_PBXBUILDFILE = "TEMPLATE_PBXBUILDFILE"; + private static final String TEMPLATE_PBXFILEREFERENCE = "TEMPLATE_PBXFILEREFERENCE"; + private static final String TEMPLATE_PBXSOURCESSBUILDPHASE = "TEMPLATE_PBXSOURCESSBUILDPHASE"; + private static final String TEMPLATE_JDK_PATH = "TEMPLATE_JDK_PATH"; + private static final String HOTSPOT_PBXPROJ = "hotspot.xcodeproj"; + private static final String PBXPROJ = "project.pbxproj"; + private static final String XCSAHAREDDATA = "xcshareddata"; + private static final String XCSCHEMES = "xcschemes"; + private static final String JVM_XCSCHEME = "jvm.xcscheme"; + private static final String J2D_XCSCHEME = "runJ2Demo.xcscheme"; + private static final String XCDEBUGGER = "xcdebugger"; + private static final String XCBKPTLIST = "Breakpoints_v2.xcbkptlist"; + private static final String TEMPLATE_PBXPROJ = PBXPROJ + ".template"; + private static final String TEMPLATE_JVM_XCSCHEME = JVM_XCSCHEME + ".template"; + private static final String TEMPLATE_J2D_XCSCHEME = J2D_XCSCHEME + ".template"; + private static final String TEMPLATE_XCBKPTLIST = XCBKPTLIST + ".template"; + private static final String[] EXCLUDE_FILES_PREFIX = {"."}; + private static final String[] EXCLUDE_FILES_POSTFIX = {".log", ".cmdline"}; + private static final String[] COMPILER_FLAGS_INCLUDE = {"-m", "-f", "-D", "-W"}; + private static final String[] COMPILER_FLAGS_IS = {"-g", "-Os", "-0"}; + private static final String[] COMPILER_FLAGS_EXCLUDE = {"-DTHIS_FILE", "-DGTEST_OS_MAC", "-mmacosx-version-min", "-Werror"}; // "-Werror" causes Xcode to stop compiling + private static final int EXIT4 = -4; + private static final int EXIT5 = -5; + private static final int EXIT6 = -6; + private static final int EXIT7 = -7; + + private final HashMap> compiledFiles = new HashMap<>(); + private final TreeSet compilerFlags = new TreeSet<>(); + private List linkerFlags = List.of(); + private final TreeSet headerPaths = new TreeSet<>(); + private final boolean debugLog; + private String projectMakerDataPath = null; + private String generatedHotspotPath = null; + private String iframework = null; + private String fframework = null; + private DiskFile rootGensrc = new DiskFile("/", true); + private DiskFile rootSrc = new DiskFile("/", true); + private DiskFile rootTest = new DiskFile("/", true); + + public XcodeProjectMaker(boolean debugLog) { + this.debugLog = debugLog; + } + + public static void main(String[] args) { + String workspaceRoot = args[0]; + String outputDir = args[1]; + String pathToProjectMakerData = args[2]; + String pathToCompileCommands = args[3]; + String pathToLinkerOptionsFile = args[4]; + String linkerOptionsString = readFile(pathToLinkerOptionsFile); + boolean debugLog = args.length > 5 && args[5].equals("-d"); + + File xcodeFolder = new File(outputDir); + xcodeFolder.mkdirs(); + String workspaceRootPathFromOutputDir = findRelativePathToWorkspaceRoot(outputDir); + + if (debugLog) { + System.out.println(); + System.out.println("Version " + VERSION); + System.out.println(); + System.out.println(" Path to workspace root is \"" + workspaceRoot + "\""); + System.out.println("Path to compile commands file is \"" + pathToCompileCommands + "\""); + System.out.println(" Xcode project will be placed in \"" + outputDir + "\""); + System.out.println(); + } + + XcodeProjectMaker maker = new XcodeProjectMaker(debugLog); + maker.parseHotspotCompileCommands(pathToCompileCommands); + maker.linkerFlags = List.of(linkerOptionsString.split(" ")); + maker.projectMakerDataPath = pathToProjectMakerData; + + maker.printLogDetails(); + + maker.prepareFiles(workspaceRoot); + maker.makeXcodeProj(outputDir, workspaceRootPathFromOutputDir); + + String pathToBuild = getFileParent(outputDir); + maker.makeAliases(outputDir, pathToBuild); + + System.out.println(); + System.out.println("The Xcode project for hotspot was succesfully created"); + System.out.println("It can be found in '" + outputDir + "/" + HOTSPOT_PBXPROJ + "'"); + System.out.println(); + } + + // find a path to what looks like jdk + private static String findRelativePathToWorkspaceRoot(String root) { + String pathToWorkspaceRoot = null; + String path = root; + boolean found1 = false; + boolean found2 = false; + + while (!found1 && !found2) { + File folder = new File(path); + File[] files = folder.listFiles(); + for (File file : files) { + String fileName = file.toPath().getFileName().toString(); + if (fileName.equals(JDK_SCRIPT_TOKEN_1)) { + found1 = true; + } + if (fileName.equals(JDK_SCRIPT_TOKEN_2)) { + found2 = true; + } + if (found1 && found2) { + break; + } + } + + if (!found1 && !found2) { + path = Paths.get(path).getParent().toString(); + if (pathToWorkspaceRoot == null) { + pathToWorkspaceRoot = ".."; + } else { + pathToWorkspaceRoot += "/.."; + } + } + } + return pathToWorkspaceRoot; + } + + private static String readFile(File file) { + return readFile(file.toPath()); + } + + private static String readFile(String path) { + return readFile(Paths.get(path)); + } + + private static String readFile(Path path) { + try { + return Files.readString(path); + } catch (IOException e) { + e.printStackTrace(); + return null; + } + } + + private static void writeFile(File file, String string) { + writeFile(file.toPath(), string); + } + + private static void writeFile(Path path, String string) { + try { + Files.writeString(path, string); + } catch (IOException e) { + e.printStackTrace(); + System.exit(EXIT4); + } + } + + private static boolean excludeFile(Path path) { + return excludeFile(path.toString()); + } + + private static boolean excludeFile(String string) { + return excludeFile(string, null); + } + + private static boolean excludeFile(String string, String exclude) { + if (exclude != null) { + if (contains(string, exclude)) { + return true; + } + } + for (String excludeFilesPrefix : EXCLUDE_FILES_PREFIX) { + if (string.startsWith(excludeFilesPrefix)) { + return true; + } + } + for (String excludeFilesPostfix : EXCLUDE_FILES_POSTFIX) { + if (string.endsWith(excludeFilesPostfix)) { + return true; + } + } + return false; + } + + private static boolean isExcludeCompilerFlag(String string) { + boolean flag = false; + for (String exclude : COMPILER_FLAGS_EXCLUDE) { + if (string.contains(exclude)) { + flag = true; + break; + } + } + return flag; + } + + private static boolean isCompilerFlag(String string) { + boolean flag = false; + for (String include : COMPILER_FLAGS_INCLUDE) { + if (string.startsWith(include)) { + flag = true; + break; + } + } + for (String is : COMPILER_FLAGS_IS) { + if (string.equals(is)) { + flag = true; + break; + } + } + if (isExcludeCompilerFlag(string)) { + flag = false; + } + return flag; + } + + private static String strip(String string) { + return string.substring(2, string.length() - 1); + } + + private static String strip(String string, String token) { + int start = string.indexOf(token); + int end = start + token.length(); + return strip(string.substring(end)); + } + + private static boolean contains(String string, String token) { + return ((string.length() >= token.length()) && (string.contains(token))); + } + + private static String getFileParent(String path) { + return Paths.get(path).getParent().toString(); + } + + private static String extractPath(String string, String from, String to) { + String result = null; + String[] tokens = string.split("/"); + int i = 0; + for (; i < tokens.length; i++) { + if (tokens[i].equals(from)) { + result = ""; + break; + } + } + for (; i < tokens.length; i++) { + result += "/" + tokens[i]; + if (tokens[i].equals(to)) { + break; + } + } + return result; + } + + private void extractCommonCompilerFlags() { + // heuristic, find average count of number of flags used by each compiled file + int countFiles = 0; + int countFlags = 0; + + for (Map.Entry> entry : this.compiledFiles.entrySet()) { + countFiles++; + List flags = entry.getValue(); + countFlags += flags.size(); + } + + // when finding common flags, only consider files with this many flags + int flagCutoff = (countFlags / countFiles) / 2; + + // collect all flags + for (Map.Entry> entry : this.compiledFiles.entrySet()) { + List flags = entry.getValue(); + if (flags.size() > flagCutoff) { + this.compilerFlags.addAll(flags); + } + } + + // find flags to remove + Set removeFlags = new TreeSet<>(); + for (Map.Entry> entry : this.compiledFiles.entrySet()) { + List flags = entry.getValue(); + if (flags.size() > flagCutoff) { + for (String common : this.compilerFlags) { + if (!flags.contains(common)) { + removeFlags.add(common); + } + } + } + } + + // leave only common flags + for (String flag : removeFlags) { + this.compilerFlags.remove(flag); + } + + // remove common flags from each compiler file, leaving only the unique ones + for (Map.Entry> entry : this.compiledFiles.entrySet()) { + List flags = entry.getValue(); + if (flags.size() > flagCutoff) { + for (String common : this.compilerFlags) { + flags.remove(common); + } + } + } + } + + private void extractCompilerFlags(String line) { + boolean verboseCompilerTokens = false; + String file = null; + ArrayList flags = null; + + String[] commands = line.split(","); + for (String command : commands) { + if (contains(command, FILE_TOKEN)) { + file = strip(command, FILE_TOKEN); + //verbose_compiler_tokens = Contains(file, "vm_version.cpp"); + } else if (contains(command, COMMAND_TOKEN)) { + String tokens = strip(command, COMMAND_TOKEN); + String[] arguments = tokens.split(" "); + if (arguments.length >= 3) { + flags = new ArrayList<>(); + for (int a = 2; a < arguments.length; a++) { + String argument = arguments[a]; + if (isCompilerFlag(argument)) { + // catch argument like -DVMTYPE=\"Minimal\" + if (contains(argument, "\\\\\\\"") && argument.endsWith("\\\\\\\"")) { + // TODO: more robust fix needed here + argument = argument.replace("\\", ""); + argument = argument.replaceFirst("\"", "~.~"); // temp token ~.~ + argument = argument.replace("\"", "\\\"'"); + argument = argument.replace("~.~", "'\\\""); + } + + // argument like -DHOTSPOT_VM_DISTRO='\"Java HotSpot(TM)\"' + // gets split up, so reconstruct as single string + if (contains(argument, QUOTE_START_TOKEN) && !argument.endsWith(QUOTE_END_TOKEN)) { + String fullArgument = argument; + do { + ++a; + argument = arguments[a]; + fullArgument = fullArgument + " " + argument; + } while (!argument.endsWith(QUOTE_END_TOKEN)); + argument = fullArgument; + } + flags.add(argument); + if (verboseCompilerTokens) { + System.out.println(" FOUND COMPILER FLAG: " + argument); + } + } else if (argument.startsWith(COMPILER_LINE_HEADER)) { + this.headerPaths.add(argument.substring(2)); + } else if (argument.equals(COMPILER_IFRAMEWORK)) { + if (iframework == null) { + ++a; + this.iframework = arguments[a]; // gets the value, so skip it for the next loop + } + } else if (argument.equals(COMPILER_FFRAMEWORK)) { + if (fframework == null) { + ++a; + this.fframework = arguments[a]; // gets the value, so skip it for the next loop + } + } + } + } + } + } + + if ((file != null) && (flags != null)) { + this.compiledFiles.put(file, flags); + } else { + System.err.println(" WARNING: extractCompilerFlags returns file:" + file + ", flags:" + flags); + } + + if (verboseCompilerTokens) { + System.exit(0); + } + } + + public void parseHotspotCompileCommands(String path) { + String content = readFile(path); + String[] parts = content.split("\\{"); // } + + int found = 0; + for (String line : parts) { + if (!contains(line, EXCLUDE_PARSE_TOKEN_1) && !line.startsWith("[")) { + extractCompilerFlags(line); + found++; + } + } + if (debugLog) { + System.out.println("Found total of " + found + " files that make up the libjvm.dylib"); + } + extractCommonCompilerFlags(); + + // figure out "gensrc" folder + // from: "/Users/gerard/Desktop/jdk_test/jdk10/build/macosx-x86_64-normal-server-fastdebug/hotspot/variant-server/gensrc/adfiles/ad_x86_clone.cpp" + // to: "/build/macosx-x86_64-normal-server-fastdebug/hotspot/variant-server/gensrc" + for (Map.Entry> entry : this.compiledFiles.entrySet()) { + String file = entry.getKey(); + if (file.contains("gensrc")) { + this.generatedHotspotPath = extractPath(file, "build", "gensrc"); + //generatedHotspotPath = "/build/macosx-x64/hotspot/variant-server/gensrc"; + //generatedHotspotPath = "/build/macosx-x86_64-normal-server-fastdebug/hotspot/variant-server/gensrc"; + } + } + } + + // https://docs.oracle.com/javase/tutorial/displayCode.html?code=https://docs.oracle.com/javase/tutorial/essential/io/examples/Copy.java + private DiskFile getHotspotFiles(DiskFile root, String workspaceRoot, String hotspotPath) { + File file = new File(workspaceRoot + "/" + hotspotPath); + if (!file.exists()) { + return null; + } + + try { + final Path rootDir = Paths.get(workspaceRoot + hotspotPath); + Files.walkFileTree(rootDir, new HotspotFileVisitor(root, hotspotPath)); + } catch (IOException ex) { + System.err.println("ex: " + ex); + } + + return root; + } + + public void prepareFiles(String workspaceRoot) { + this.rootGensrc = getHotspotFiles(this.rootGensrc, workspaceRoot, this.generatedHotspotPath); + this.rootSrc = getHotspotFiles(this.rootSrc, workspaceRoot, SRC_HOTSPOT_PATH); + this.rootTest = getHotspotFiles(this.rootTest, workspaceRoot, TEST_HOTSPOT_PATH); + + // make a copy of files from the log + Set logFiles = new TreeSet<>(this.compiledFiles.keySet()); + + int totalMarkedFiles = 0; + DiskFile[] roots = { this.rootGensrc, this.rootSrc }; + for (DiskFile root : roots) { + List diskFiles = root.getFiles(); + for (DiskFile diskFile : diskFiles) { + if (!diskFile.isDirectory()) { + String logFileProcessed = null; + String diskFilePath = diskFile.getFilePath(); + for (String logFilePath : logFiles) { + if (contains(logFilePath, diskFilePath)) { + totalMarkedFiles++; + + logFileProcessed = logFilePath; + + // mark the file as needing compilation + diskFile.markAsCompiled(this.compiledFiles.get(logFilePath)); + + // break early if found + break; + } + } + if (logFileProcessed != null) { + // remove the file, so we don't have to search through it again + logFiles.remove(logFileProcessed); + } + } + } + } + + if (this.compiledFiles.size() != totalMarkedFiles) { + System.err.println("\nError: was expecting to compile " + this.compiledFiles.size() + " files, but marked " + totalMarkedFiles); + for (String file : logFiles) { + System.err.println("file: " + file); + } + System.exit(EXIT5); + } + + if (!logFiles.isEmpty()) { + System.err.println("\nError: unprocessed files left over:"); + for (String logFile : logFiles) { + System.err.println(" " + logFile); + } + System.exit(EXIT6); + } + } + + public void printLogDetails() { + if (!debugLog) return; + + System.out.println("\nFound " + this.compilerFlags.size() + " common compiler flags:"); + for (String flag : this.compilerFlags) { + System.out.println(" " + flag); + } + + System.out.println("\nList of compiled files (each one uses common compiler flags plus extra ones as specified):"); + int count = 1; + for (Map.Entry> entry : this.compiledFiles.entrySet()) { + String file = entry.getKey(); + System.out.format("%4d: %s\n", (count), file); + count++; + List flags = entry.getValue(); + for (String flag : flags) { + System.out.println(" " + flag); + } + } + + System.out.println("\nFound " + this.linkerFlags.size() + " linker flags:"); + for (String flag : this.linkerFlags) { + System.out.println(" " + flag); + } + + System.out.println("\nFound " + this.headerPaths.size() + " header paths:"); + for (String header : this.headerPaths) { + System.out.println(" " + header); + } + + System.out.println("\nFrameworks:"); + System.out.println(" -iframework " + iframework); + System.out.println(" -f " + fframework); + } + + private String makeProjectPbxproj(String workspaceRootPathFromOutputDir, String string) { + String cFlags = ""; + for (String flag : this.compilerFlags) { + cFlags += " \"" + flag.replace("\"", "\\\\\"") + "\",\n"; + } + cFlags = cFlags.substring(0, cFlags.length() - 2); + string = string.replaceFirst(TEMPLATE_OTHER_CFLAGS, cFlags); + + String ldFlags = ""; + for (String flag : this.linkerFlags) { + ldFlags += " \"" + flag + "\",\n"; + } + ldFlags = ldFlags.substring(0, ldFlags.length() - 2); + string = string.replaceFirst(TEMPLATE_OTHER_LDFLAGS, ldFlags); + + String headerPaths = ""; + for (String header : this.headerPaths) { + headerPaths += " \"" + header + "\",\n"; + } + headerPaths = headerPaths.substring(0, headerPaths.length() - 2); + string = string.replaceFirst(TEMPLATE_USER_HEADER_SEARCH_PATHS, headerPaths); + + String frameworkPaths = ""; + if (fframework != null) { + frameworkPaths += " \"" + fframework + "\"\n"; + } + string = string.replaceFirst(TEMPLATE_FRAMEWORK_SEARCH_PATHS, frameworkPaths); + + DiskFile gensrcFile = this.rootGensrc.getChild("gensrc"); + string = string.replaceFirst(TEMPLATE_GROUP_GENSRC, " " + gensrcFile.getXcodeId()); + + DiskFile srcFile = this.rootSrc.getChild("src"); + string = string.replaceFirst(TEMPLATE_GROUP_SRC, " " + srcFile.getXcodeId()); + + DiskFile testFile = this.rootTest.getChild("test"); + string = string.replaceFirst(TEMPLATE_GROUP_TEST, " " + testFile.getXcodeId()); + + String gensrcGroups = gensrcFile.generatePbxGroup(); + String srcGroups = srcFile.generatePbxGroup(); + String testGroups = testFile.generatePbxGroup(); + string = string.replaceFirst(TEMPLATE_GROUPS, gensrcGroups + srcGroups + testGroups); + + String gensrcFiles = gensrcFile.generatePbxFileReference(workspaceRootPathFromOutputDir); + String srcFiles = srcFile.generatePbxFileReference(workspaceRootPathFromOutputDir); + String testFiles = testFile.generatePbxFileReference(workspaceRootPathFromOutputDir); + string = string.replaceFirst(TEMPLATE_PBXFILEREFERENCE, gensrcFiles + srcFiles + testFiles); + + String gensrcCompiled = gensrcFile.generatePbxBuildFile(); + String compiled = srcFile.generatePbxBuildFile(); + string = string.replaceFirst(TEMPLATE_PBXBUILDFILE, gensrcCompiled + compiled); + + String gensrcBuilt = gensrcFile.generatePbxSourcesBuildPhase(); + String built = srcFile.generatePbxSourcesBuildPhase(); + string = string.replaceFirst(TEMPLATE_PBXSOURCESSBUILDPHASE, gensrcBuilt + built); + + return string; + } + + private String makeTemplateXcscheme(String outputDir, String string) { + string = string.replaceAll(TEMPLATE_JDK_PATH, outputDir); + + return string; + } + + public void makeXcodeProj(String outputDir, String workspaceRootPathFromOutputDir) { + /* + jvm.xcodeproj <-- folder + project.pbxproj <-- file + xcshareddata <-- folder + xcschemes <-- folder + jvm.xcscheme <-- file + xcdebugger <-- folder + Breakpoints_v2.xcbkptlist <-- file + */ + File xcodeDir = new File(outputDir); + File jvmXcodeprojDir = new File(xcodeDir, HOTSPOT_PBXPROJ); + File projectPbxprojFile = new File(jvmXcodeprojDir, PBXPROJ); + File xcshareddataDir = new File(jvmXcodeprojDir, XCSAHAREDDATA); + File xcschemesDir = new File(xcshareddataDir, XCSCHEMES); + File jvmXcschemeFile = new File(xcschemesDir, JVM_XCSCHEME); + File j2DemoXcschemeFile = new File(xcschemesDir, J2D_XCSCHEME); + File xcdebuggerDir = new File(xcshareddataDir, XCDEBUGGER); + File jBreakpointsV2XcbkptlistFile = new File(xcdebuggerDir, XCBKPTLIST); + + if (xcodeDir.exists()) { + xcodeDir.delete(); + } + + jvmXcodeprojDir.mkdirs(); + xcshareddataDir.mkdirs(); + xcschemesDir.mkdirs(); + xcdebuggerDir.mkdirs(); + + File dataDir = new File(projectMakerDataPath); + File templateProjectPbxprojFile = new File(dataDir, TEMPLATE_PBXPROJ); + File templateJvmXcschemeFile = new File(dataDir, TEMPLATE_JVM_XCSCHEME); + File templateJ2DemoXcschemeFile = new File(dataDir, TEMPLATE_J2D_XCSCHEME); + File templateJBreakpointsV2XcbkptlistFile = new File(dataDir, TEMPLATE_XCBKPTLIST); + + String projectPbxprojString = readFile(templateProjectPbxprojFile); + String jvmXcschemeString = readFile(templateJvmXcschemeFile); + String j2DemoXcschemeString = readFile(templateJ2DemoXcschemeFile); + String jBreakpointsV2XcbkptlistString = readFile(templateJBreakpointsV2XcbkptlistFile); + + writeFile(projectPbxprojFile, makeProjectPbxproj(workspaceRootPathFromOutputDir, projectPbxprojString)); + writeFile(jvmXcschemeFile, makeTemplateXcscheme(outputDir, jvmXcschemeString)); + writeFile(j2DemoXcschemeFile, makeTemplateXcscheme(outputDir, j2DemoXcschemeString)); + writeFile(jBreakpointsV2XcbkptlistFile, jBreakpointsV2XcbkptlistString); + } + + public void makeAliases(String outputDir, String pathToBuild) { + File xcodeDir = new File(outputDir); + File jdkOldSh = new File(xcodeDir, ALIAS_JAVA_OLD); + File jdkNewSh = new File(xcodeDir, ALIAS_JAVA_NEW); + + writeFile(jdkOldSh, "#!/bin/bash\n" + pathToBuild + JDK_BIN_JAVA + " $@"); + writeFile(jdkNewSh, "#!/bin/bash\n" + outputDir + "/build" + JDK_BIN_JAVA + " $@"); + + try { + Set permissions = new HashSet<>(); + permissions.add(PosixFilePermission.OWNER_READ); + permissions.add(PosixFilePermission.OWNER_WRITE); + permissions.add(PosixFilePermission.OWNER_EXECUTE); + permissions.add(PosixFilePermission.GROUP_READ); + permissions.add(PosixFilePermission.OTHERS_READ); + Files.setPosixFilePermissions(jdkOldSh.toPath(), permissions); + Files.setPosixFilePermissions(jdkNewSh.toPath(), permissions); + } catch (IOException ex) { + System.err.println("Warning: unable to change file permissions"); + System.err.println(ex); + } + } + + private static class HotspotFileVisitor implements FileVisitor { + private final DiskFile root; + private final String hotspotPath; + + public HotspotFileVisitor(DiskFile root, String hotspotPath) { + this.root = root; + this.hotspotPath = hotspotPath; + } + + @Override + public FileVisitResult preVisitDirectory(Path path, BasicFileAttributes attrs) { + if (excludeFile(path)) { + return FileVisitResult.SKIP_SUBTREE; + } else { + // consider folders based on their names + Path file = path.getFileName(); + if (!excludeFile(file)) { + root.addDirectory(path, hotspotPath); + return FileVisitResult.CONTINUE; + } else { + // skip folders with names beginning with ".", etc + return FileVisitResult.SKIP_SUBTREE; + } + } + } + + @Override + public FileVisitResult visitFile(Path path, BasicFileAttributes attrs) { + Path file = path.getFileName(); + if (!excludeFile(file)) { + //System.err.println(path.toString()); + root.addFile(path, hotspotPath); + } + return FileVisitResult.CONTINUE; + } + + @Override + public FileVisitResult postVisitDirectory(Path path, IOException exc) { + return FileVisitResult.CONTINUE; + } + + @Override + public FileVisitResult visitFileFailed(Path path, IOException exc) { + if (exc instanceof FileSystemLoopException) { + System.err.println("cycle detected: " + path); + } else { + System.err.format("Unable to process: %s: %s\n", path, exc); + } + return FileVisitResult.CONTINUE; + } + } +} diff --git a/make/modules/java.base/Copy.gmk b/make/modules/java.base/Copy.gmk index 911fff60ea898..5a4a5d400f240 100644 --- a/make/modules/java.base/Copy.gmk +++ b/make/modules/java.base/Copy.gmk @@ -1,5 +1,5 @@ # -# Copyright (c) 2014, 2022, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2014, 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 @@ -51,27 +51,25 @@ endif ifeq ($(call isTargetOs, windows)+$(CREATING_BUILDJDK), true+false) # Chmod to avoid permission issues if bundles are unpacked on unix platforms. - define copy-and-chmod - $(install-file) - $(CHMOD) a+rx $@ - endef - # Use separate macro calls in case the source files are not in the same # directory. - $(eval $(call SetupCopyFiles,COPY_MSVCR, \ + $(eval $(call SetupCopyFiles, COPY_MSVCR, \ DEST := $(LIB_DST_DIR), \ FILES := $(MSVCR_DLL), \ - MACRO := copy-and-chmod)) + MACRO := copy-and-chmod-executable, \ + )) - $(eval $(call SetupCopyFiles,COPY_VCRUNTIME_1, \ + $(eval $(call SetupCopyFiles, COPY_VCRUNTIME_1, \ DEST := $(LIB_DST_DIR), \ FILES := $(VCRUNTIME_1_DLL), \ - MACRO := copy-and-chmod)) + MACRO := copy-and-chmod-executable, \ + )) - $(eval $(call SetupCopyFiles,COPY_MSVCP, \ + $(eval $(call SetupCopyFiles, COPY_MSVCP, \ DEST := $(LIB_DST_DIR), \ FILES := $(MSVCP_DLL), \ - MACRO := copy-and-chmod)) + MACRO := copy-and-chmod-executable, \ + )) TARGETS += $(COPY_MSVCR) $(COPY_VCRUNTIME_1) $(COPY_MSVCP) @@ -80,7 +78,7 @@ ifeq ($(call isTargetOs, windows)+$(CREATING_BUILDJDK), true+false) DEST := $(LIB_DST_DIR), \ SRC := $(UCRT_DLL_DIR), \ FILES := $(wildcard $(UCRT_DLL_DIR)/*.dll), \ - MACRO := copy-and-chmod, \ + MACRO := copy-and-chmod-executable, \ )) TARGETS += $(COPY_UCRT_DLLS) diff --git a/make/test/BuildMicrobenchmark.gmk b/make/test/BuildMicrobenchmark.gmk index 32d26be22702b..61c84b31a22d6 100644 --- a/make/test/BuildMicrobenchmark.gmk +++ b/make/test/BuildMicrobenchmark.gmk @@ -94,6 +94,7 @@ $(eval $(call SetupJavaCompilation, BUILD_JDK_MICROBENCHMARK, \ TARGET_RELEASE := $(TARGET_RELEASE_NEWJDK_UPGRADED), \ SMALL_JAVA := false, \ CLASSPATH := $(JMH_COMPILE_JARS), \ + CREATE_API_DIGEST := true, \ DISABLED_WARNINGS := restricted this-escape processing rawtypes removal cast \ serial preview dangling-doc-comments, \ SRC := $(MICROBENCHMARK_SRC), \ diff --git a/make/test/BuildTestLib.gmk b/make/test/BuildTestLib.gmk index d48f263f6f96d..dceae073ff385 100644 --- a/make/test/BuildTestLib.gmk +++ b/make/test/BuildTestLib.gmk @@ -64,7 +64,7 @@ $(eval $(call SetupJavaCompilation, BUILD_TEST_LIB_JAR, \ BIN := $(TEST_LIB_SUPPORT)/test-lib_classes, \ HEADERS := $(TEST_LIB_SUPPORT)/test-lib_headers, \ JAR := $(TEST_LIB_SUPPORT)/test-lib.jar, \ - DISABLED_WARNINGS := try deprecation rawtypes unchecked serial cast removal preview dangling-doc-comments, \ + DISABLED_WARNINGS := try deprecation rawtypes unchecked serial cast removal preview restricted dangling-doc-comments, \ JAVAC_FLAGS := --add-exports java.base/sun.security.util=ALL-UNNAMED \ --add-exports java.base/jdk.internal.classfile=ALL-UNNAMED \ --add-exports java.base/jdk.internal.classfile.attribute=ALL-UNNAMED \ diff --git a/src/demo/share/jfc/SwingSet2/resources/images/About.jpg b/src/demo/share/jfc/SwingSet2/resources/images/About.jpg index 272173c67463c..c6c8e22970bff 100644 Binary files a/src/demo/share/jfc/SwingSet2/resources/images/About.jpg and b/src/demo/share/jfc/SwingSet2/resources/images/About.jpg differ diff --git a/src/hotspot/cpu/ppc/assembler_ppc.cpp b/src/hotspot/cpu/ppc/assembler_ppc.cpp index 26fc1aacad3a3..dc8180bfedf50 100644 --- a/src/hotspot/cpu/ppc/assembler_ppc.cpp +++ b/src/hotspot/cpu/ppc/assembler_ppc.cpp @@ -292,31 +292,54 @@ void Assembler::stb(Register d, RegisterOrConstant roc, Register s1, Register tm } } -void Assembler::add(Register d, RegisterOrConstant roc, Register s1) { +void Assembler::add(Register d, Register s, RegisterOrConstant roc) { if (roc.is_constant()) { intptr_t c = roc.as_constant(); assert(is_simm(c, 16), "too big"); - addi(d, s1, (int)c); + addi(d, s, (int)c); + } else { + add(d, s, roc.as_register()); } - else add(d, roc.as_register(), s1); } -void Assembler::subf(Register d, RegisterOrConstant roc, Register s1) { +void Assembler::sub(Register d, Register s, RegisterOrConstant roc) { if (roc.is_constant()) { intptr_t c = roc.as_constant(); assert(is_simm(-c, 16), "too big"); - addi(d, s1, (int)-c); + addi(d, s, (int)-c); + } else { + sub(d, s, roc.as_register()); + } +} + +void Assembler::xorr(Register d, Register s, RegisterOrConstant roc) { + if (roc.is_constant()) { + intptr_t c = roc.as_constant(); + assert(is_uimm(c, 16), "too big"); + xori(d, s, (int)c); + } else { + xorr(d, s, roc.as_register()); } - else subf(d, roc.as_register(), s1); } -void Assembler::cmpd(ConditionRegister d, RegisterOrConstant roc, Register s1) { +void Assembler::cmpw(ConditionRegister d, Register s, RegisterOrConstant roc) { if (roc.is_constant()) { intptr_t c = roc.as_constant(); assert(is_simm(c, 16), "too big"); - cmpdi(d, s1, (int)c); + cmpwi(d, s, (int)c); + } else { + cmpw(d, s, roc.as_register()); + } +} + +void Assembler::cmpd(ConditionRegister d, Register s, RegisterOrConstant roc) { + if (roc.is_constant()) { + intptr_t c = roc.as_constant(); + assert(is_simm(c, 16), "too big"); + cmpdi(d, s, (int)c); + } else { + cmpd(d, s, roc.as_register()); } - else cmpd(d, roc.as_register(), s1); } // Load a 64 bit constant. Patchable. diff --git a/src/hotspot/cpu/ppc/assembler_ppc.hpp b/src/hotspot/cpu/ppc/assembler_ppc.hpp index d18574f50a949..d445108098b86 100644 --- a/src/hotspot/cpu/ppc/assembler_ppc.hpp +++ b/src/hotspot/cpu/ppc/assembler_ppc.hpp @@ -2512,9 +2512,13 @@ class Assembler : public AbstractAssembler { void stw( Register d, RegisterOrConstant roc, Register s1 = noreg, Register tmp = noreg); void sth( Register d, RegisterOrConstant roc, Register s1 = noreg, Register tmp = noreg); void stb( Register d, RegisterOrConstant roc, Register s1 = noreg, Register tmp = noreg); - void add( Register d, RegisterOrConstant roc, Register s1); - void subf(Register d, RegisterOrConstant roc, Register s1); - void cmpd(ConditionRegister d, RegisterOrConstant roc, Register s1); + void add( Register d, Register s, RegisterOrConstant roc); + void add( Register d, RegisterOrConstant roc, Register s) { add(d, s, roc); } + void sub( Register d, Register s, RegisterOrConstant roc); + void xorr(Register d, Register s, RegisterOrConstant roc); + void xorr(Register d, RegisterOrConstant roc, Register s) { xorr(d, s, roc); } + void cmpw(ConditionRegister d, Register s, RegisterOrConstant roc); + void cmpd(ConditionRegister d, Register s, RegisterOrConstant roc); // Load pointer d from s1+roc. void ld_ptr(Register d, RegisterOrConstant roc, Register s1 = noreg) { ld(d, roc, s1); } diff --git a/src/hotspot/cpu/ppc/c1_LIRAssembler_ppc.cpp b/src/hotspot/cpu/ppc/c1_LIRAssembler_ppc.cpp index 0c1e23c635329..88d635f2b856f 100644 --- a/src/hotspot/cpu/ppc/c1_LIRAssembler_ppc.cpp +++ b/src/hotspot/cpu/ppc/c1_LIRAssembler_ppc.cpp @@ -2620,7 +2620,7 @@ void LIR_Assembler::emit_compare_and_swap(LIR_OpCompareAndSwap* op) { __ cmpxchgw(BOOL_RESULT, /*current_value=*/R0, cmp_value, new_value, addr, MacroAssembler::MemBarNone, MacroAssembler::cmpxchgx_hint_atomic_update(), - noreg, /*check without ldarx first*/true); + noreg, nullptr, /*check without ldarx first*/true); } if (support_IRIW_for_not_multiple_copy_atomic_cpu) { diff --git a/src/hotspot/cpu/ppc/gc/shenandoah/shenandoahBarrierSetAssembler_ppc.cpp b/src/hotspot/cpu/ppc/gc/shenandoah/shenandoahBarrierSetAssembler_ppc.cpp index 62aa9a2bf5930..3cb5c5a628f39 100644 --- a/src/hotspot/cpu/ppc/gc/shenandoah/shenandoahBarrierSetAssembler_ppc.cpp +++ b/src/hotspot/cpu/ppc/gc/shenandoah/shenandoahBarrierSetAssembler_ppc.cpp @@ -669,7 +669,7 @@ void ShenandoahBarrierSetAssembler::cmpxchg_oop(MacroAssembler *masm, Register b // no special processing is required. if (UseCompressedOops) { __ cmpxchgw(CCR0, current_value, expected, new_val, base_addr, MacroAssembler::MemBarNone, - false, success_flag, true); + false, success_flag, nullptr, true); } else { __ cmpxchgd(CCR0, current_value, expected, new_val, base_addr, MacroAssembler::MemBarNone, false, success_flag, nullptr, true); diff --git a/src/hotspot/cpu/ppc/gc/z/zBarrierSetAssembler_ppc.cpp b/src/hotspot/cpu/ppc/gc/z/zBarrierSetAssembler_ppc.cpp index 9e606054fe910..89ab1b1edeeb4 100644 --- a/src/hotspot/cpu/ppc/gc/z/zBarrierSetAssembler_ppc.cpp +++ b/src/hotspot/cpu/ppc/gc/z/zBarrierSetAssembler_ppc.cpp @@ -335,7 +335,7 @@ void ZBarrierSetAssembler::store_barrier_medium(MacroAssembler* masm, // Try to self-heal null values for atomic accesses bool need_restore = false; if (!ind_or_offs.is_constant() || ind_or_offs.as_constant() != 0) { - __ add(ref_base, ind_or_offs, ref_base); + __ add(ref_base, ref_base, ind_or_offs); need_restore = true; } __ ld(R0, in_bytes(ZThreadLocalData::store_good_mask_offset()), R16_thread); @@ -343,7 +343,7 @@ void ZBarrierSetAssembler::store_barrier_medium(MacroAssembler* masm, MacroAssembler::MemBarNone, MacroAssembler::cmpxchgx_hint_atomic_update(), noreg, need_restore ? nullptr : &slow_path); if (need_restore) { - __ subf(ref_base, ind_or_offs, ref_base); + __ sub(ref_base, ref_base, ind_or_offs); __ bne(CCR0, slow_path); } } else { diff --git a/src/hotspot/cpu/ppc/macroAssembler_ppc.cpp b/src/hotspot/cpu/ppc/macroAssembler_ppc.cpp index 3b48b4020ccb3..0af384a36fabe 100644 --- a/src/hotspot/cpu/ppc/macroAssembler_ppc.cpp +++ b/src/hotspot/cpu/ppc/macroAssembler_ppc.cpp @@ -1620,7 +1620,7 @@ void MacroAssembler::atomic_get_and_modify_generic(Register dest_current_value, // Temps, addr_base and exchange_value are killed if size < 4 and processor does not support respective instructions. // Only signed types are supported with size < 4. void MacroAssembler::cmpxchg_loop_body(ConditionRegister flag, Register dest_current_value, - Register compare_value, Register exchange_value, + RegisterOrConstant compare_value, Register exchange_value, Register addr_base, Register tmp1, Register tmp2, Label &retry, Label &failed, bool cmpxchgx_hint, int size) { // Sub-word instructions are available since Power 8. @@ -1634,7 +1634,7 @@ void MacroAssembler::cmpxchg_loop_body(ConditionRegister flag, Register dest_cur modval = exchange_value; if (instruction_type != size) { - assert_different_registers(tmp1, tmp2, dest_current_value, compare_value, exchange_value, addr_base); + assert_different_registers(tmp1, tmp2, dest_current_value, compare_value.register_or_noreg(), exchange_value, addr_base); shift_amount = tmp1; val32 = tmp2; modval = tmp2; @@ -1695,21 +1695,23 @@ void MacroAssembler::cmpxchg_loop_body(ConditionRegister flag, Register dest_cur // CmpxchgX sets condition register to cmpX(current, compare). void MacroAssembler::cmpxchg_generic(ConditionRegister flag, Register dest_current_value, - Register compare_value, Register exchange_value, + RegisterOrConstant compare_value, Register exchange_value, Register addr_base, Register tmp1, Register tmp2, - int semantics, bool cmpxchgx_hint, - Register int_flag_success, bool contention_hint, bool weak, int size) { + int semantics, bool cmpxchgx_hint, Register int_flag_success, + Label* failed_ext, bool contention_hint, bool weak, int size) { Label retry; - Label failed; + Label failed_int; + Label& failed = (failed_ext != nullptr) ? *failed_ext : failed_int; Label done; // Save one branch if result is returned via register and // result register is different from the other ones. bool use_result_reg = (int_flag_success != noreg); - bool preset_result_reg = (int_flag_success != dest_current_value && int_flag_success != compare_value && + bool preset_result_reg = (int_flag_success != dest_current_value && int_flag_success != compare_value.register_or_noreg() && int_flag_success != exchange_value && int_flag_success != addr_base && int_flag_success != tmp1 && int_flag_success != tmp2); assert(!weak || flag == CCR0, "weak only supported with CCR0"); + assert(int_flag_success == noreg || failed_ext == nullptr, "cannot have both"); assert(size == 1 || size == 2 || size == 4, "unsupported"); if (use_result_reg && preset_result_reg) { @@ -1760,7 +1762,7 @@ void MacroAssembler::cmpxchg_generic(ConditionRegister flag, Register dest_curre b(done); } - bind(failed); + bind(failed_int); if (use_result_reg && !preset_result_reg) { li(int_flag_success, 0); } @@ -1787,10 +1789,11 @@ void MacroAssembler::cmpxchg_generic(ConditionRegister flag, Register dest_curre // To avoid the costly compare exchange the value is tested beforehand. // Several special cases exist to avoid that unnecessary information is generated. // -void MacroAssembler::cmpxchgd(ConditionRegister flag, - Register dest_current_value, RegisterOrConstant compare_value, Register exchange_value, - Register addr_base, int semantics, bool cmpxchgx_hint, - Register int_flag_success, Label* failed_ext, bool contention_hint, bool weak) { +void MacroAssembler::cmpxchgd(ConditionRegister flag, Register dest_current_value, + RegisterOrConstant compare_value, Register exchange_value, + Register addr_base, + int semantics, bool cmpxchgx_hint, Register int_flag_success, + Label* failed_ext, bool contention_hint, bool weak) { Label retry; Label failed_int; Label& failed = (failed_ext != nullptr) ? *failed_ext : failed_int; @@ -1810,7 +1813,7 @@ void MacroAssembler::cmpxchgd(ConditionRegister flag, // Add simple guard in order to reduce risk of starving under high contention (recommended by IBM). if (contention_hint) { // Don't try to reserve if cmp fails. ld(dest_current_value, 0, addr_base); - cmpd(flag, compare_value, dest_current_value); + cmpd(flag, dest_current_value, compare_value); bne(flag, failed); } @@ -1823,7 +1826,7 @@ void MacroAssembler::cmpxchgd(ConditionRegister flag, bind(retry); ldarx(dest_current_value, addr_base, cmpxchgx_hint); - cmpd(flag, compare_value, dest_current_value); + cmpd(flag, dest_current_value, compare_value); if (UseStaticBranchPredictionInCompareAndSwapPPC64) { bne_predict_not_taken(flag, failed); } else { @@ -2902,7 +2905,11 @@ void MacroAssembler::compiler_fast_unlock_lightweight_object(ConditionRegister f // Check for monitor (0b10). ld(mark, oopDesc::mark_offset_in_bytes(), obj); andi_(t, mark, markWord::monitor_value); - bne(CCR0, inflated); + if (!UseObjectMonitorTable) { + bne(CCR0, inflated); + } else { + bne(CCR0, push_and_slow); + } #ifdef ASSERT // Check header not unlocked (0b01). diff --git a/src/hotspot/cpu/ppc/macroAssembler_ppc.hpp b/src/hotspot/cpu/ppc/macroAssembler_ppc.hpp index 15b5e26f8f634..9a0cf3d8da0e2 100644 --- a/src/hotspot/cpu/ppc/macroAssembler_ppc.hpp +++ b/src/hotspot/cpu/ppc/macroAssembler_ppc.hpp @@ -482,13 +482,14 @@ class MacroAssembler: public Assembler { Register addr_base, Register tmp1, Register tmp2, Register tmp3, bool cmpxchgx_hint, bool is_add, int size); void cmpxchg_loop_body(ConditionRegister flag, Register dest_current_value, - Register compare_value, Register exchange_value, + RegisterOrConstant compare_value, Register exchange_value, Register addr_base, Register tmp1, Register tmp2, Label &retry, Label &failed, bool cmpxchgx_hint, int size); - void cmpxchg_generic(ConditionRegister flag, - Register dest_current_value, Register compare_value, Register exchange_value, Register addr_base, - Register tmp1, Register tmp2, - int semantics, bool cmpxchgx_hint, Register int_flag_success, bool contention_hint, bool weak, int size); + void cmpxchg_generic(ConditionRegister flag, Register dest_current_value, + RegisterOrConstant compare_value, Register exchange_value, + Register addr_base, Register tmp1, Register tmp2, + int semantics, bool cmpxchgx_hint, Register int_flag_success, + Label* failed_ext, bool contention_hint, bool weak, int size); public: // Temps and addr_base are killed if processor does not support Power 8 instructions. // Result will be sign extended. @@ -528,33 +529,37 @@ class MacroAssembler: public Assembler { Register tmp, bool cmpxchgx_hint); // Temps, addr_base and exchange_value are killed if processor does not support Power 8 instructions. // compare_value must be at least 32 bit sign extended. Result will be sign extended. - void cmpxchgb(ConditionRegister flag, - Register dest_current_value, Register compare_value, Register exchange_value, Register addr_base, - Register tmp1, Register tmp2, int semantics, bool cmpxchgx_hint = false, - Register int_flag_success = noreg, bool contention_hint = false, bool weak = false) { + void cmpxchgb(ConditionRegister flag, Register dest_current_value, + RegisterOrConstant compare_value, Register exchange_value, + Register addr_base, Register tmp1, Register tmp2, + int semantics, bool cmpxchgx_hint = false, Register int_flag_success = noreg, + Label* failed = nullptr, bool contention_hint = false, bool weak = false) { cmpxchg_generic(flag, dest_current_value, compare_value, exchange_value, addr_base, tmp1, tmp2, - semantics, cmpxchgx_hint, int_flag_success, contention_hint, weak, 1); + semantics, cmpxchgx_hint, int_flag_success, failed, contention_hint, weak, 1); } // Temps, addr_base and exchange_value are killed if processor does not support Power 8 instructions. // compare_value must be at least 32 bit sign extended. Result will be sign extended. - void cmpxchgh(ConditionRegister flag, - Register dest_current_value, Register compare_value, Register exchange_value, Register addr_base, - Register tmp1, Register tmp2, int semantics, bool cmpxchgx_hint = false, - Register int_flag_success = noreg, bool contention_hint = false, bool weak = false) { + void cmpxchgh(ConditionRegister flag, Register dest_current_value, + RegisterOrConstant compare_value, Register exchange_value, + Register addr_base, Register tmp1, Register tmp2, + int semantics, bool cmpxchgx_hint = false, Register int_flag_success = noreg, + Label* failed = nullptr, bool contention_hint = false, bool weak = false) { cmpxchg_generic(flag, dest_current_value, compare_value, exchange_value, addr_base, tmp1, tmp2, - semantics, cmpxchgx_hint, int_flag_success, contention_hint, weak, 2); + semantics, cmpxchgx_hint, int_flag_success, failed, contention_hint, weak, 2); } - void cmpxchgw(ConditionRegister flag, - Register dest_current_value, Register compare_value, Register exchange_value, Register addr_base, - int semantics, bool cmpxchgx_hint = false, - Register int_flag_success = noreg, bool contention_hint = false, bool weak = false) { + void cmpxchgw(ConditionRegister flag, Register dest_current_value, + RegisterOrConstant compare_value, Register exchange_value, + Register addr_base, + int semantics, bool cmpxchgx_hint = false, Register int_flag_success = noreg, + Label* failed = nullptr, bool contention_hint = false, bool weak = false) { cmpxchg_generic(flag, dest_current_value, compare_value, exchange_value, addr_base, noreg, noreg, - semantics, cmpxchgx_hint, int_flag_success, contention_hint, weak, 4); + semantics, cmpxchgx_hint, int_flag_success, failed, contention_hint, weak, 4); } - void cmpxchgd(ConditionRegister flag, - Register dest_current_value, RegisterOrConstant compare_value, Register exchange_value, - Register addr_base, int semantics, bool cmpxchgx_hint = false, - Register int_flag_success = noreg, Label* failed = nullptr, bool contention_hint = false, bool weak = false); + void cmpxchgd(ConditionRegister flag, Register dest_current_value, + RegisterOrConstant compare_value, Register exchange_value, + Register addr_base, + int semantics, bool cmpxchgx_hint = false, Register int_flag_success = noreg, + Label* failed = nullptr, bool contention_hint = false, bool weak = false); // interface method calling void lookup_interface_method(Register recv_klass, diff --git a/src/hotspot/cpu/ppc/ppc.ad b/src/hotspot/cpu/ppc/ppc.ad index b34d3ef150140..e7e066ebcc6d3 100644 --- a/src/hotspot/cpu/ppc/ppc.ad +++ b/src/hotspot/cpu/ppc/ppc.ad @@ -7390,7 +7390,7 @@ instruct compareAndSwapB_regP_regI_regI(iRegIdst res, iRegPdst mem_ptr, iRegIsrc // CmpxchgX sets CCR0 to cmpX(src1, src2) and Rres to 'true'/'false'. __ cmpxchgb(CCR0, R0, $src1$$Register, $src2$$Register, $mem_ptr$$Register, noreg, noreg, MacroAssembler::MemBarNone, MacroAssembler::cmpxchgx_hint_atomic_update(), - $res$$Register, true); + $res$$Register, nullptr, true); if (support_IRIW_for_not_multiple_copy_atomic_cpu) { __ isync(); } else { @@ -7409,7 +7409,7 @@ instruct compareAndSwapB4_regP_regI_regI(iRegIdst res, rarg3RegP mem_ptr, iRegIs // CmpxchgX sets CCR0 to cmpX(src1, src2) and Rres to 'true'/'false'. __ cmpxchgb(CCR0, R0, $src1$$Register, $src2$$Register, $mem_ptr$$Register, $tmp1$$Register, $tmp2$$Register, MacroAssembler::MemBarNone, MacroAssembler::cmpxchgx_hint_atomic_update(), - $res$$Register, true); + $res$$Register, nullptr, true); if (support_IRIW_for_not_multiple_copy_atomic_cpu) { __ isync(); } else { @@ -7428,7 +7428,7 @@ instruct compareAndSwapS_regP_regI_regI(iRegIdst res, iRegPdst mem_ptr, iRegIsrc // CmpxchgX sets CCR0 to cmpX(src1, src2) and Rres to 'true'/'false'. __ cmpxchgh(CCR0, R0, $src1$$Register, $src2$$Register, $mem_ptr$$Register, noreg, noreg, MacroAssembler::MemBarNone, MacroAssembler::cmpxchgx_hint_atomic_update(), - $res$$Register, true); + $res$$Register, nullptr, true); if (support_IRIW_for_not_multiple_copy_atomic_cpu) { __ isync(); } else { @@ -7447,7 +7447,7 @@ instruct compareAndSwapS4_regP_regI_regI(iRegIdst res, rarg3RegP mem_ptr, iRegIs // CmpxchgX sets CCR0 to cmpX(src1, src2) and Rres to 'true'/'false'. __ cmpxchgh(CCR0, R0, $src1$$Register, $src2$$Register, $mem_ptr$$Register, $tmp1$$Register, $tmp2$$Register, MacroAssembler::MemBarNone, MacroAssembler::cmpxchgx_hint_atomic_update(), - $res$$Register, true); + $res$$Register, nullptr, true); if (support_IRIW_for_not_multiple_copy_atomic_cpu) { __ isync(); } else { @@ -7465,7 +7465,7 @@ instruct compareAndSwapI_regP_regI_regI(iRegIdst res, iRegPdst mem_ptr, iRegIsrc // CmpxchgX sets CCR0 to cmpX(src1, src2) and Rres to 'true'/'false'. __ cmpxchgw(CCR0, R0, $src1$$Register, $src2$$Register, $mem_ptr$$Register, MacroAssembler::MemBarNone, MacroAssembler::cmpxchgx_hint_atomic_update(), - $res$$Register, true); + $res$$Register, nullptr, true); if (support_IRIW_for_not_multiple_copy_atomic_cpu) { __ isync(); } else { @@ -7483,7 +7483,7 @@ instruct compareAndSwapN_regP_regN_regN(iRegIdst res, iRegPdst mem_ptr, iRegNsrc // CmpxchgX sets CCR0 to cmpX(src1, src2) and Rres to 'true'/'false'. __ cmpxchgw(CCR0, R0, $src1$$Register, $src2$$Register, $mem_ptr$$Register, MacroAssembler::MemBarNone, MacroAssembler::cmpxchgx_hint_atomic_update(), - $res$$Register, true); + $res$$Register, nullptr, true); if (support_IRIW_for_not_multiple_copy_atomic_cpu) { __ isync(); } else { @@ -7541,7 +7541,7 @@ instruct weakCompareAndSwapB_regP_regI_regI(iRegIdst res, iRegPdst mem_ptr, iReg // CmpxchgX sets CCR0 to cmpX(src1, src2) and Rres to 'true'/'false'. __ cmpxchgb(CCR0, R0, $src1$$Register, $src2$$Register, $mem_ptr$$Register, noreg, noreg, MacroAssembler::MemBarNone, - MacroAssembler::cmpxchgx_hint_atomic_update(), $res$$Register, true, /*weak*/ true); + MacroAssembler::cmpxchgx_hint_atomic_update(), $res$$Register, nullptr, true, /*weak*/ true); %} ins_pipe(pipe_class_default); %} @@ -7555,7 +7555,7 @@ instruct weakCompareAndSwapB4_regP_regI_regI(iRegIdst res, rarg3RegP mem_ptr, iR // CmpxchgX sets CCR0 to cmpX(src1, src2) and Rres to 'true'/'false'. __ cmpxchgb(CCR0, R0, $src1$$Register, $src2$$Register, $mem_ptr$$Register, $tmp1$$Register, $tmp2$$Register, MacroAssembler::MemBarNone, - MacroAssembler::cmpxchgx_hint_atomic_update(), $res$$Register, true, /*weak*/ true); + MacroAssembler::cmpxchgx_hint_atomic_update(), $res$$Register, nullptr, true, /*weak*/ true); %} ins_pipe(pipe_class_default); %} @@ -7569,7 +7569,7 @@ instruct weakCompareAndSwapB_acq_regP_regI_regI(iRegIdst res, iRegPdst mem_ptr, // CmpxchgX sets CCR0 to cmpX(src1, src2) and Rres to 'true'/'false'. __ cmpxchgb(CCR0, R0, $src1$$Register, $src2$$Register, $mem_ptr$$Register, noreg, noreg, support_IRIW_for_not_multiple_copy_atomic_cpu ? MacroAssembler::MemBarAcq : MacroAssembler::MemBarFenceAfter, - MacroAssembler::cmpxchgx_hint_atomic_update(), $res$$Register, true, /*weak*/ true); + MacroAssembler::cmpxchgx_hint_atomic_update(), $res$$Register, nullptr, true, /*weak*/ true); %} ins_pipe(pipe_class_default); %} @@ -7583,7 +7583,7 @@ instruct weakCompareAndSwapB4_acq_regP_regI_regI(iRegIdst res, rarg3RegP mem_ptr // CmpxchgX sets CCR0 to cmpX(src1, src2) and Rres to 'true'/'false'. __ cmpxchgb(CCR0, R0, $src1$$Register, $src2$$Register, $mem_ptr$$Register, $tmp1$$Register, $tmp2$$Register, support_IRIW_for_not_multiple_copy_atomic_cpu ? MacroAssembler::MemBarAcq : MacroAssembler::MemBarFenceAfter, - MacroAssembler::cmpxchgx_hint_atomic_update(), $res$$Register, true, /*weak*/ true); + MacroAssembler::cmpxchgx_hint_atomic_update(), $res$$Register, nullptr, true, /*weak*/ true); %} ins_pipe(pipe_class_default); %} @@ -7597,7 +7597,7 @@ instruct weakCompareAndSwapS_regP_regI_regI(iRegIdst res, iRegPdst mem_ptr, iReg // CmpxchgX sets CCR0 to cmpX(src1, src2) and Rres to 'true'/'false'. __ cmpxchgh(CCR0, R0, $src1$$Register, $src2$$Register, $mem_ptr$$Register, noreg, noreg, MacroAssembler::MemBarNone, - MacroAssembler::cmpxchgx_hint_atomic_update(), $res$$Register, true, /*weak*/ true); + MacroAssembler::cmpxchgx_hint_atomic_update(), $res$$Register, nullptr, true, /*weak*/ true); %} ins_pipe(pipe_class_default); %} @@ -7611,7 +7611,7 @@ instruct weakCompareAndSwapS4_regP_regI_regI(iRegIdst res, rarg3RegP mem_ptr, iR // CmpxchgX sets CCR0 to cmpX(src1, src2) and Rres to 'true'/'false'. __ cmpxchgh(CCR0, R0, $src1$$Register, $src2$$Register, $mem_ptr$$Register, $tmp1$$Register, $tmp2$$Register, MacroAssembler::MemBarNone, - MacroAssembler::cmpxchgx_hint_atomic_update(), $res$$Register, true, /*weak*/ true); + MacroAssembler::cmpxchgx_hint_atomic_update(), $res$$Register, nullptr, true, /*weak*/ true); %} ins_pipe(pipe_class_default); %} @@ -7625,7 +7625,7 @@ instruct weakCompareAndSwapS_acq_regP_regI_regI(iRegIdst res, iRegPdst mem_ptr, // CmpxchgX sets CCR0 to cmpX(src1, src2) and Rres to 'true'/'false'. __ cmpxchgh(CCR0, R0, $src1$$Register, $src2$$Register, $mem_ptr$$Register, noreg, noreg, support_IRIW_for_not_multiple_copy_atomic_cpu ? MacroAssembler::MemBarAcq : MacroAssembler::MemBarFenceAfter, - MacroAssembler::cmpxchgx_hint_atomic_update(), $res$$Register, true, /*weak*/ true); + MacroAssembler::cmpxchgx_hint_atomic_update(), $res$$Register, nullptr, true, /*weak*/ true); %} ins_pipe(pipe_class_default); %} @@ -7639,7 +7639,7 @@ instruct weakCompareAndSwapS4_acq_regP_regI_regI(iRegIdst res, rarg3RegP mem_ptr // CmpxchgX sets CCR0 to cmpX(src1, src2) and Rres to 'true'/'false'. __ cmpxchgh(CCR0, R0, $src1$$Register, $src2$$Register, $mem_ptr$$Register, $tmp1$$Register, $tmp2$$Register, support_IRIW_for_not_multiple_copy_atomic_cpu ? MacroAssembler::MemBarAcq : MacroAssembler::MemBarFenceAfter, - MacroAssembler::cmpxchgx_hint_atomic_update(), $res$$Register, true, /*weak*/ true); + MacroAssembler::cmpxchgx_hint_atomic_update(), $res$$Register, nullptr, true, /*weak*/ true); %} ins_pipe(pipe_class_default); %} @@ -7653,7 +7653,7 @@ instruct weakCompareAndSwapI_regP_regI_regI(iRegIdst res, iRegPdst mem_ptr, iReg // CmpxchgX sets CCR0 to cmpX(src1, src2) and Rres to 'true'/'false'. __ cmpxchgw(CCR0, R0, $src1$$Register, $src2$$Register, $mem_ptr$$Register, MacroAssembler::MemBarNone, - MacroAssembler::cmpxchgx_hint_atomic_update(), $res$$Register, true, /*weak*/ true); + MacroAssembler::cmpxchgx_hint_atomic_update(), $res$$Register, nullptr, true, /*weak*/ true); %} ins_pipe(pipe_class_default); %} @@ -7669,7 +7669,7 @@ instruct weakCompareAndSwapI_acq_regP_regI_regI(iRegIdst res, iRegPdst mem_ptr, // value is never passed to caller. __ cmpxchgw(CCR0, R0, $src1$$Register, $src2$$Register, $mem_ptr$$Register, support_IRIW_for_not_multiple_copy_atomic_cpu ? MacroAssembler::MemBarAcq : MacroAssembler::MemBarFenceAfter, - MacroAssembler::cmpxchgx_hint_atomic_update(), $res$$Register, true, /*weak*/ true); + MacroAssembler::cmpxchgx_hint_atomic_update(), $res$$Register, nullptr, true, /*weak*/ true); %} ins_pipe(pipe_class_default); %} @@ -7683,7 +7683,7 @@ instruct weakCompareAndSwapN_regP_regN_regN(iRegIdst res, iRegPdst mem_ptr, iReg // CmpxchgX sets CCR0 to cmpX(src1, src2) and Rres to 'true'/'false'. __ cmpxchgw(CCR0, R0, $src1$$Register, $src2$$Register, $mem_ptr$$Register, MacroAssembler::MemBarNone, - MacroAssembler::cmpxchgx_hint_atomic_update(), $res$$Register, true, /*weak*/ true); + MacroAssembler::cmpxchgx_hint_atomic_update(), $res$$Register, nullptr, true, /*weak*/ true); %} ins_pipe(pipe_class_default); %} @@ -7699,7 +7699,7 @@ instruct weakCompareAndSwapN_acq_regP_regN_regN(iRegIdst res, iRegPdst mem_ptr, // value is never passed to caller. __ cmpxchgw(CCR0, R0, $src1$$Register, $src2$$Register, $mem_ptr$$Register, support_IRIW_for_not_multiple_copy_atomic_cpu ? MacroAssembler::MemBarAcq : MacroAssembler::MemBarFenceAfter, - MacroAssembler::cmpxchgx_hint_atomic_update(), $res$$Register, true, /*weak*/ true); + MacroAssembler::cmpxchgx_hint_atomic_update(), $res$$Register, nullptr, true, /*weak*/ true); %} ins_pipe(pipe_class_default); %} @@ -7776,7 +7776,7 @@ instruct compareAndExchangeB_regP_regI_regI(iRegIdst res, iRegPdst mem_ptr, iReg // CmpxchgX sets CCR0 to cmpX(src1, src2) and Rres to 'true'/'false'. __ cmpxchgb(CCR0, $res$$Register, $src1$$Register, $src2$$Register, $mem_ptr$$Register, noreg, noreg, MacroAssembler::MemBarNone, MacroAssembler::cmpxchgx_hint_atomic_update(), - noreg, true); + noreg, nullptr, true); %} ins_pipe(pipe_class_default); %} @@ -7790,7 +7790,7 @@ instruct compareAndExchangeB4_regP_regI_regI(iRegIdst res, rarg3RegP mem_ptr, iR // CmpxchgX sets CCR0 to cmpX(src1, src2) and Rres to 'true'/'false'. __ cmpxchgb(CCR0, $res$$Register, $src1$$Register, $src2$$Register, $mem_ptr$$Register, $tmp1$$Register, R0, MacroAssembler::MemBarNone, MacroAssembler::cmpxchgx_hint_atomic_update(), - noreg, true); + noreg, nullptr, true); %} ins_pipe(pipe_class_default); %} @@ -7804,7 +7804,7 @@ instruct compareAndExchangeB_acq_regP_regI_regI(iRegIdst res, iRegPdst mem_ptr, // CmpxchgX sets CCR0 to cmpX(src1, src2) and Rres to 'true'/'false'. __ cmpxchgb(CCR0, $res$$Register, $src1$$Register, $src2$$Register, $mem_ptr$$Register, noreg, noreg, MacroAssembler::MemBarNone, MacroAssembler::cmpxchgx_hint_atomic_update(), - noreg, true); + noreg, nullptr, true); if (support_IRIW_for_not_multiple_copy_atomic_cpu) { __ isync(); } else { @@ -7824,7 +7824,7 @@ instruct compareAndExchangeB4_acq_regP_regI_regI(iRegIdst res, rarg3RegP mem_ptr // CmpxchgX sets CCR0 to cmpX(src1, src2) and Rres to 'true'/'false'. __ cmpxchgb(CCR0, $res$$Register, $src1$$Register, $src2$$Register, $mem_ptr$$Register, $tmp1$$Register, R0, MacroAssembler::MemBarNone, MacroAssembler::cmpxchgx_hint_atomic_update(), - noreg, true); + noreg, nullptr, true); if (support_IRIW_for_not_multiple_copy_atomic_cpu) { __ isync(); } else { @@ -7844,7 +7844,7 @@ instruct compareAndExchangeS_regP_regI_regI(iRegIdst res, iRegPdst mem_ptr, iReg // CmpxchgX sets CCR0 to cmpX(src1, src2) and Rres to 'true'/'false'. __ cmpxchgh(CCR0, $res$$Register, $src1$$Register, $src2$$Register, $mem_ptr$$Register, noreg, noreg, MacroAssembler::MemBarNone, MacroAssembler::cmpxchgx_hint_atomic_update(), - noreg, true); + noreg, nullptr, true); %} ins_pipe(pipe_class_default); %} @@ -7858,7 +7858,7 @@ instruct compareAndExchangeS4_regP_regI_regI(iRegIdst res, rarg3RegP mem_ptr, iR // CmpxchgX sets CCR0 to cmpX(src1, src2) and Rres to 'true'/'false'. __ cmpxchgh(CCR0, $res$$Register, $src1$$Register, $src2$$Register, $mem_ptr$$Register, $tmp1$$Register, R0, MacroAssembler::MemBarNone, MacroAssembler::cmpxchgx_hint_atomic_update(), - noreg, true); + noreg, nullptr, true); %} ins_pipe(pipe_class_default); %} @@ -7872,7 +7872,7 @@ instruct compareAndExchangeS_acq_regP_regI_regI(iRegIdst res, iRegPdst mem_ptr, // CmpxchgX sets CCR0 to cmpX(src1, src2) and Rres to 'true'/'false'. __ cmpxchgh(CCR0, $res$$Register, $src1$$Register, $src2$$Register, $mem_ptr$$Register, noreg, noreg, MacroAssembler::MemBarNone, MacroAssembler::cmpxchgx_hint_atomic_update(), - noreg, true); + noreg, nullptr, true); if (support_IRIW_for_not_multiple_copy_atomic_cpu) { __ isync(); } else { @@ -7892,7 +7892,7 @@ instruct compareAndExchangeS4_acq_regP_regI_regI(iRegIdst res, rarg3RegP mem_ptr // CmpxchgX sets CCR0 to cmpX(src1, src2) and Rres to 'true'/'false'. __ cmpxchgh(CCR0, $res$$Register, $src1$$Register, $src2$$Register, $mem_ptr$$Register, $tmp1$$Register, R0, MacroAssembler::MemBarNone, MacroAssembler::cmpxchgx_hint_atomic_update(), - noreg, true); + noreg, nullptr, true); if (support_IRIW_for_not_multiple_copy_atomic_cpu) { __ isync(); } else { @@ -7912,7 +7912,7 @@ instruct compareAndExchangeI_regP_regI_regI(iRegIdst res, iRegPdst mem_ptr, iReg // CmpxchgX sets CCR0 to cmpX(src1, src2) and Rres to 'true'/'false'. __ cmpxchgw(CCR0, $res$$Register, $src1$$Register, $src2$$Register, $mem_ptr$$Register, MacroAssembler::MemBarNone, MacroAssembler::cmpxchgx_hint_atomic_update(), - noreg, true); + noreg, nullptr, true); %} ins_pipe(pipe_class_default); %} @@ -7926,7 +7926,7 @@ instruct compareAndExchangeI_acq_regP_regI_regI(iRegIdst res, iRegPdst mem_ptr, // CmpxchgX sets CCR0 to cmpX(src1, src2) and Rres to 'true'/'false'. __ cmpxchgw(CCR0, $res$$Register, $src1$$Register, $src2$$Register, $mem_ptr$$Register, MacroAssembler::MemBarNone, MacroAssembler::cmpxchgx_hint_atomic_update(), - noreg, true); + noreg, nullptr, true); if (support_IRIW_for_not_multiple_copy_atomic_cpu) { __ isync(); } else { @@ -7946,7 +7946,7 @@ instruct compareAndExchangeN_regP_regN_regN(iRegNdst res, iRegPdst mem_ptr, iReg // CmpxchgX sets CCR0 to cmpX(src1, src2) and Rres to 'true'/'false'. __ cmpxchgw(CCR0, $res$$Register, $src1$$Register, $src2$$Register, $mem_ptr$$Register, MacroAssembler::MemBarNone, MacroAssembler::cmpxchgx_hint_atomic_update(), - noreg, true); + noreg, nullptr, true); %} ins_pipe(pipe_class_default); %} @@ -7960,7 +7960,7 @@ instruct compareAndExchangeN_acq_regP_regN_regN(iRegNdst res, iRegPdst mem_ptr, // CmpxchgX sets CCR0 to cmpX(src1, src2) and Rres to 'true'/'false'. __ cmpxchgw(CCR0, $res$$Register, $src1$$Register, $src2$$Register, $mem_ptr$$Register, MacroAssembler::MemBarNone, MacroAssembler::cmpxchgx_hint_atomic_update(), - noreg, true); + noreg, nullptr, true); if (support_IRIW_for_not_multiple_copy_atomic_cpu) { __ isync(); } else { diff --git a/src/hotspot/cpu/ppc/vtableStubs_ppc_64.cpp b/src/hotspot/cpu/ppc/vtableStubs_ppc_64.cpp index 28ba04d833bed..1e6f748dec800 100644 --- a/src/hotspot/cpu/ppc/vtableStubs_ppc_64.cpp +++ b/src/hotspot/cpu/ppc/vtableStubs_ppc_64.cpp @@ -195,7 +195,7 @@ VtableStub* VtableStubs::create_itable_stub(int itable_index) { #ifndef PRODUCT if (DebugVtables) { Label ok; - __ cmpd(CCR0, R19_method, 0); + __ cmpdi(CCR0, R19_method, 0); __ bne(CCR0, ok); __ stop("method is null"); __ bind(ok); diff --git a/src/hotspot/cpu/riscv/assembler_riscv.hpp b/src/hotspot/cpu/riscv/assembler_riscv.hpp index 79279be7acc1b..cba3dd919dafb 100644 --- a/src/hotspot/cpu/riscv/assembler_riscv.hpp +++ b/src/hotspot/cpu/riscv/assembler_riscv.hpp @@ -1835,8 +1835,10 @@ enum Nf { // Vector Unit-Stride Segment Load Instructions INSN(vlseg3e8_v, 0b0000111, 0b000, 0b00000, 0b00, 0b0, g3); + INSN(vlseg4e8_v, 0b0000111, 0b000, 0b00000, 0b00, 0b0, g4); // Vector Unit-Stride Segment Store Instructions + INSN(vsseg3e8_v, 0b0100111, 0b000, 0b00000, 0b00, 0b0, g3); INSN(vsseg4e8_v, 0b0100111, 0b000, 0b00000, 0b00, 0b0, g4); #undef INSN diff --git a/src/hotspot/cpu/riscv/gc/shared/barrierSetAssembler_riscv.cpp b/src/hotspot/cpu/riscv/gc/shared/barrierSetAssembler_riscv.cpp index efdf3765965f7..d96d405aa2282 100644 --- a/src/hotspot/cpu/riscv/gc/shared/barrierSetAssembler_riscv.cpp +++ b/src/hotspot/cpu/riscv/gc/shared/barrierSetAssembler_riscv.cpp @@ -265,7 +265,7 @@ void BarrierSetAssembler::nmethod_entry_barrier(MacroAssembler* masm, Label* slo } case NMethodPatchingType::conc_instruction_and_data_patch: { - // If we patch code we need both a code patching and a loadload + // If we patch code we need both a cmodx fence and a loadload // fence. It's not super cheap, so we use a global epoch mechanism // to hide them in a slow path. // The high level idea of the global epoch mechanism is to detect @@ -273,11 +273,19 @@ void BarrierSetAssembler::nmethod_entry_barrier(MacroAssembler* masm, Label* slo // last nmethod was disarmed. This implies that the required // fencing has been performed for all preceding nmethod disarms // as well. Therefore, we do not need any further fencing. + __ la(t1, ExternalAddress((address)&_patching_epoch)); - // Embed an artificial data dependency to order the guard load - // before the epoch load. - __ srli(ra, t0, 32); - __ orr(t1, t1, ra); + if (!UseZtso) { + // Embed a synthetic data dependency between the load of the guard and + // the load of the epoch. This guarantees that these loads occur in + // order, while allowing other independent instructions to be reordered. + // Note: This may be slower than using a membar(load|load) (fence r,r). + // Because processors will not start the second load until the first comes back. + // This means you can’t overlap the two loads, + // which is stronger than needed for ordering (stronger than TSO). + __ srli(ra, t0, 32); + __ orr(t1, t1, ra); + } // Read the global epoch value. __ lwu(t1, t1); // Combine the guard value (low order) with the epoch value (high order). diff --git a/src/hotspot/cpu/riscv/stubGenerator_riscv.cpp b/src/hotspot/cpu/riscv/stubGenerator_riscv.cpp index f214c489557d6..8792dea7de5eb 100644 --- a/src/hotspot/cpu/riscv/stubGenerator_riscv.cpp +++ b/src/hotspot/cpu/riscv/stubGenerator_riscv.cpp @@ -5322,6 +5322,279 @@ class StubGenerator: public StubCodeGenerator { return (address) start; } + /** + * vector registers: + * input VectorRegister's: intputV1-V4, for m2 they could be v2, v4, v6, for m1 they could be v2, v4, v6, v8 + * index VectorRegister's: idxV1-V3, for m2 they could be v8, v10, v12, v14, for m1 they could be v10, v12, v14, v16 + * output VectorRegister's: outputV1-V4, for m2 they could be v16, v18, v20, v22, for m1 they could be v18, v20, v22 + * + * NOTE: each field will occupy a single vector register group + */ + void base64_vector_decode_round(Register src, Register dst, Register codec, + Register size, Register stepSrc, Register stepDst, Register failedIdx, Register minusOne, + VectorRegister inputV1, VectorRegister inputV2, VectorRegister inputV3, VectorRegister inputV4, + VectorRegister idxV1, VectorRegister idxV2, VectorRegister idxV3, VectorRegister idxV4, + VectorRegister outputV1, VectorRegister outputV2, VectorRegister outputV3, + Assembler::LMUL lmul) { + // set vector register type/len + __ vsetvli(x0, size, Assembler::e8, lmul, Assembler::ma, Assembler::ta); + + // segmented load src into v registers: mem(src) => vr(4) + __ vlseg4e8_v(inputV1, src); + + // src = src + register_group_len_bytes * 4 + __ add(src, src, stepSrc); + + // decoding + // 1. indexed load: vr(4) => vr(4) + __ vluxei8_v(idxV1, codec, inputV1); + __ vluxei8_v(idxV2, codec, inputV2); + __ vluxei8_v(idxV3, codec, inputV3); + __ vluxei8_v(idxV4, codec, inputV4); + + // 2. check wrong data + __ vor_vv(outputV1, idxV1, idxV2); + __ vor_vv(outputV2, idxV3, idxV4); + __ vor_vv(outputV1, outputV1, outputV2); + __ vmseq_vi(v0, outputV1, -1); + __ vfirst_m(failedIdx, v0); + Label NoFailure; + __ beq(failedIdx, minusOne, NoFailure); + __ vsetvli(x0, failedIdx, Assembler::e8, lmul, Assembler::mu, Assembler::tu); + __ slli(stepDst, failedIdx, 1); + __ add(stepDst, failedIdx, stepDst); + __ BIND(NoFailure); + + // 3. compute the decoded data: vr(4) => vr(3) + __ vsll_vi(idxV1, idxV1, 2); + __ vsrl_vi(outputV1, idxV2, 4); + __ vor_vv(outputV1, outputV1, idxV1); + + __ vsll_vi(idxV2, idxV2, 4); + __ vsrl_vi(outputV2, idxV3, 2); + __ vor_vv(outputV2, outputV2, idxV2); + + __ vsll_vi(idxV3, idxV3, 6); + __ vor_vv(outputV3, idxV4, idxV3); + + // segmented store encoded data in v registers back to dst: vr(3) => mem(dst) + __ vsseg3e8_v(outputV1, dst); + + // dst = dst + register_group_len_bytes * 3 + __ add(dst, dst, stepDst); + } + + /** + * int j.u.Base64.Decoder.decodeBlock(byte[] src, int sp, int sl, byte[] dst, int dp, boolean isURL, boolean isMIME) + * + * Input arguments: + * c_rarg0 - src, source array + * c_rarg1 - sp, src start offset + * c_rarg2 - sl, src end offset + * c_rarg3 - dst, dest array + * c_rarg4 - dp, dst start offset + * c_rarg5 - isURL, Base64 or URL character set + * c_rarg6 - isMIME, Decoding MIME block + */ + address generate_base64_decodeBlock() { + + static const uint8_t fromBase64[256] = { + 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, + 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, + 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 62u, 255u, 255u, 255u, 63u, + 52u, 53u, 54u, 55u, 56u, 57u, 58u, 59u, 60u, 61u, 255u, 255u, 255u, 255u, 255u, 255u, + 255u, 0u, 1u, 2u, 3u, 4u, 5u, 6u, 7u, 8u, 9u, 10u, 11u, 12u, 13u, 14u, + 15u, 16u, 17u, 18u, 19u, 20u, 21u, 22u, 23u, 24u, 25u, 255u, 255u, 255u, 255u, 255u, + 255u, 26u, 27u, 28u, 29u, 30u, 31u, 32u, 33u, 34u, 35u, 36u, 37u, 38u, 39u, 40u, + 41u, 42u, 43u, 44u, 45u, 46u, 47u, 48u, 49u, 50u, 51u, 255u, 255u, 255u, 255u, 255u, + 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, + 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, + 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, + 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, + 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, + 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, + 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, + 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, + }; + + static const uint8_t fromBase64URL[256] = { + 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, + 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, + 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 62u, 255u, 255u, + 52u, 53u, 54u, 55u, 56u, 57u, 58u, 59u, 60u, 61u, 255u, 255u, 255u, 255u, 255u, 255u, + 255u, 0u, 1u, 2u, 3u, 4u, 5u, 6u, 7u, 8u, 9u, 10u, 11u, 12u, 13u, 14u, + 15u, 16u, 17u, 18u, 19u, 20u, 21u, 22u, 23u, 24u, 25u, 255u, 255u, 255u, 255u, 63u, + 255u, 26u, 27u, 28u, 29u, 30u, 31u, 32u, 33u, 34u, 35u, 36u, 37u, 38u, 39u, 40u, + 41u, 42u, 43u, 44u, 45u, 46u, 47u, 48u, 49u, 50u, 51u, 255u, 255u, 255u, 255u, 255u, + 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, + 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, + 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, + 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, + 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, + 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, + 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, + 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, 255u, + }; + + __ align(CodeEntryAlignment); + StubCodeMark mark(this, "StubRoutines", "decodeBlock"); + address start = __ pc(); + __ enter(); + + Register src = c_rarg0; + Register soff = c_rarg1; + Register send = c_rarg2; + Register dst = c_rarg3; + Register doff = c_rarg4; + Register isURL = c_rarg5; + Register isMIME = c_rarg6; + + Register codec = c_rarg7; + Register dstBackup = x31; + Register length = x28; // t3, total length of src data in bytes + + Label ProcessData, Exit; + Label ProcessScalar, ScalarLoop; + + // passed in length (send - soff) is guaranteed to be > 4, + // and in this intrinsic we only process data of length in multiple of 4, + // it's not guaranteed to be multiple of 4 by java level, so do it explicitly + __ sub(length, send, soff); + __ andi(length, length, -4); + // real src/dst to process data + __ add(src, src, soff); + __ add(dst, dst, doff); + // backup of dst, used to calculate the return value at exit + __ mv(dstBackup, dst); + + // load the codec base address + __ la(codec, ExternalAddress((address) fromBase64)); + __ beqz(isURL, ProcessData); + __ la(codec, ExternalAddress((address) fromBase64URL)); + __ BIND(ProcessData); + + // vector version + if (UseRVV) { + // for MIME case, it has a default length limit of 76 which could be + // different(smaller) from (send - soff), so in MIME case, we go through + // the scalar code path directly. + __ bnez(isMIME, ScalarLoop); + + Label ProcessM1, ProcessM2; + + Register failedIdx = soff; + Register stepSrcM1 = send; + Register stepSrcM2 = doff; + Register stepDst = isURL; + Register size = x29; // t4 + Register minusOne = x30; // t5 + + __ mv(minusOne, -1); + __ mv(size, MaxVectorSize * 2); + __ mv(stepSrcM1, MaxVectorSize * 4); + __ slli(stepSrcM2, stepSrcM1, 1); + __ mv(stepDst, MaxVectorSize * 2 * 3); + + __ blt(length, stepSrcM2, ProcessM1); + + + // Assembler::m2 + __ BIND(ProcessM2); + base64_vector_decode_round(src, dst, codec, + size, stepSrcM2, stepDst, failedIdx, minusOne, + v2, v4, v6, v8, // inputs + v10, v12, v14, v16, // indexes + v18, v20, v22, // outputs + Assembler::m2); + __ sub(length, length, stepSrcM2); + + // error check + __ bne(failedIdx, minusOne, Exit); + + __ bge(length, stepSrcM2, ProcessM2); + + + // Assembler::m1 + __ BIND(ProcessM1); + __ blt(length, stepSrcM1, ProcessScalar); + + __ srli(size, size, 1); + __ srli(stepDst, stepDst, 1); + base64_vector_decode_round(src, dst, codec, + size, stepSrcM1, stepDst, failedIdx, minusOne, + v1, v2, v3, v4, // inputs + v5, v6, v7, v8, // indexes + v9, v10, v11, // outputs + Assembler::m1); + __ sub(length, length, stepSrcM1); + + // error check + __ bne(failedIdx, minusOne, Exit); + + __ BIND(ProcessScalar); + __ beqz(length, Exit); + } + + // scalar version + { + Register byte0 = soff, byte1 = send, byte2 = doff, byte3 = isURL; + Register combined32Bits = x29; // t5 + + // encoded: [byte0[5:0] : byte1[5:0] : byte2[5:0]] : byte3[5:0]] => + // plain: [byte0[5:0]+byte1[5:4] : byte1[3:0]+byte2[5:2] : byte2[1:0]+byte3[5:0]] + __ BIND(ScalarLoop); + + // load 4 bytes encoded src data + __ lbu(byte0, Address(src, 0)); + __ lbu(byte1, Address(src, 1)); + __ lbu(byte2, Address(src, 2)); + __ lbu(byte3, Address(src, 3)); + __ addi(src, src, 4); + + // get codec index and decode (ie. load from codec by index) + __ add(byte0, codec, byte0); + __ add(byte1, codec, byte1); + __ lb(byte0, Address(byte0, 0)); + __ lb(byte1, Address(byte1, 0)); + __ add(byte2, codec, byte2); + __ add(byte3, codec, byte3); + __ lb(byte2, Address(byte2, 0)); + __ lb(byte3, Address(byte3, 0)); + __ slliw(byte0, byte0, 18); + __ slliw(byte1, byte1, 12); + __ orr(byte0, byte0, byte1); + __ orr(byte0, byte0, byte3); + __ slliw(byte2, byte2, 6); + // For performance consideration, `combined32Bits` is constructed for 2 purposes at the same time, + // 1. error check below + // 2. decode below + __ orr(combined32Bits, byte0, byte2); + + // error check + __ bltz(combined32Bits, Exit); + + // store 3 bytes decoded data + __ sraiw(byte0, combined32Bits, 16); + __ sraiw(byte1, combined32Bits, 8); + __ sb(byte0, Address(dst, 0)); + __ sb(byte1, Address(dst, 1)); + __ sb(combined32Bits, Address(dst, 2)); + + __ sub(length, length, 4); + __ addi(dst, dst, 3); + // loop back + __ bnez(length, ScalarLoop); + } + + __ BIND(Exit); + __ sub(c_rarg0, dst, dstBackup); + + __ leave(); + __ ret(); + + return (address) start; + } + void adler32_process_bytes(Register buff, Register s1, Register s2, VectorRegister vtable, VectorRegister vzero, VectorRegister vbytes, VectorRegister vs1acc, VectorRegister vs2acc, Register temp0, Register temp1, Register temp2, Register temp3, @@ -5980,6 +6253,7 @@ static const int64_t right_3_bits = right_n_bits(3); if (UseBASE64Intrinsics) { StubRoutines::_base64_encodeBlock = generate_base64_encodeBlock(); + StubRoutines::_base64_decodeBlock = generate_base64_decodeBlock(); } if (UseAdler32Intrinsics) { diff --git a/src/hotspot/cpu/s390/macroAssembler_s390.cpp b/src/hotspot/cpu/s390/macroAssembler_s390.cpp index b31d08f9fde10..d527b4d2aea11 100644 --- a/src/hotspot/cpu/s390/macroAssembler_s390.cpp +++ b/src/hotspot/cpu/s390/macroAssembler_s390.cpp @@ -6286,6 +6286,7 @@ void MacroAssembler::compiler_fast_unlock_lightweight_object(Register obj, Regis BLOCK_COMMENT("compiler_fast_lightweight_unlock {"); { // Lightweight Unlock + NearLabel push_and_slow_path; // Check if obj is top of lock-stack. z_lgf(top, Address(Z_thread, ls_top_offset)); @@ -6315,7 +6316,11 @@ void MacroAssembler::compiler_fast_unlock_lightweight_object(Register obj, Regis // Check for monitor (0b10). z_lg(mark, Address(obj, mark_offset)); z_tmll(mark, markWord::monitor_value); - z_brnaz(inflated); + if (!UseObjectMonitorTable) { + z_brnaz(inflated); + } else { + z_brnaz(push_and_slow_path); + } #ifdef ASSERT // Check header not unlocked (0b01). @@ -6334,6 +6339,7 @@ void MacroAssembler::compiler_fast_unlock_lightweight_object(Register obj, Regis branch_optimized(Assembler::bcondEqual, unlocked); } + bind(push_and_slow_path); // Restore lock-stack and handle the unlock in runtime. z_lgf(top, Address(Z_thread, ls_top_offset)); DEBUG_ONLY(z_stg(obj, Address(Z_thread, top));) diff --git a/src/hotspot/os/linux/globals_linux.hpp b/src/hotspot/os/linux/globals_linux.hpp index 1cb0b553c5273..90cb00fb7e683 100644 --- a/src/hotspot/os/linux/globals_linux.hpp +++ b/src/hotspot/os/linux/globals_linux.hpp @@ -38,10 +38,8 @@ product(bool, UseOprofile, false, \ "enable support for Oprofile profiler") \ \ - /* NB: The default value of UseLinuxPosixThreadCPUClocks may be */ \ - /* overridden in Arguments::parse_each_vm_init_arg. */ \ product(bool, UseLinuxPosixThreadCPUClocks, true, \ - "enable fast Linux Posix clocks where available") \ + "(Deprecated) enable fast Linux Posix clocks where available") \ \ product(bool, UseTransparentHugePages, false, \ "Use MADV_HUGEPAGE for large pages") \ diff --git a/src/hotspot/os/windows/attachListener_windows.cpp b/src/hotspot/os/windows/attachListener_windows.cpp index 7e455cf0a49f2..3f6ca941c209b 100644 --- a/src/hotspot/os/windows/attachListener_windows.cpp +++ b/src/hotspot/os/windows/attachListener_windows.cpp @@ -318,7 +318,7 @@ void Win32AttachOperation::complete(jint result, bufferedStream* result_stream) BOOL fSuccess; char msg[32]; - _snprintf(msg, sizeof(msg), "%d\n", result); + os::snprintf(msg, sizeof(msg), "%d\n", result); msg[sizeof(msg) - 1] = '\0'; fSuccess = write_pipe(hPipe, msg, (int)strlen(msg)); diff --git a/src/hotspot/os/windows/os_windows.cpp b/src/hotspot/os/windows/os_windows.cpp index cb0fe95269b9f..1d1d9d3e1a4ed 100644 --- a/src/hotspot/os/windows/os_windows.cpp +++ b/src/hotspot/os/windows/os_windows.cpp @@ -1776,14 +1776,14 @@ void * os::dll_load(const char *name, char *ebuf, int ebuflen) { } if (lib_arch_str != nullptr) { - ::_snprintf(ebuf, ebuflen - 1, - "Can't load %s-bit .dll on a %s-bit platform", - lib_arch_str, running_arch_str); + os::snprintf(ebuf, ebuflen - 1, + "Can't load %s-bit .dll on a %s-bit platform", + lib_arch_str, running_arch_str); } else { // don't know what architecture this dll was build for - ::_snprintf(ebuf, ebuflen - 1, - "Can't load this .dll (machine code=0x%x) on a %s-bit platform", - lib_arch, running_arch_str); + os::snprintf(ebuf, ebuflen - 1, + "Can't load this .dll (machine code=0x%x) on a %s-bit platform", + lib_arch, running_arch_str); } JFR_ONLY(load_event.set_error_msg(ebuf);) return nullptr; diff --git a/src/hotspot/os/windows/perfMemory_windows.cpp b/src/hotspot/os/windows/perfMemory_windows.cpp index a71101731fb98..06b057315cbdd 100644 --- a/src/hotspot/os/windows/perfMemory_windows.cpp +++ b/src/hotspot/os/windows/perfMemory_windows.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 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 @@ -165,7 +165,7 @@ static char* get_user_tmp_dir(const char* user) { char* dirname = NEW_C_HEAP_ARRAY(char, nbytes, mtInternal); // construct the path name to user specific tmp directory - _snprintf(dirname, nbytes, "%s\\%s_%s", tmpdir, perfdir, user); + os::snprintf(dirname, nbytes, "%s\\%s_%s", tmpdir, perfdir, user); return dirname; } @@ -455,7 +455,7 @@ static char *get_sharedmem_objectname(const char* user, int vmid) { // nbytes += UINT_CHARS; char* name = NEW_C_HEAP_ARRAY(char, nbytes, mtInternal); - _snprintf(name, nbytes, "%s_%s_%u", PERFDATA_NAME, user, vmid); + os::snprintf(name, nbytes, "%s_%s_%u", PERFDATA_NAME, user, vmid); return name; } @@ -471,7 +471,7 @@ static char* get_sharedmem_filename(const char* dirname, int vmid) { size_t nbytes = strlen(dirname) + UINT_CHARS + 2; char* name = NEW_C_HEAP_ARRAY(char, nbytes, mtInternal); - _snprintf(name, nbytes, "%s\\%d", dirname, vmid); + os::snprintf(name, nbytes, "%s\\%d", dirname, vmid); return name; } diff --git a/src/hotspot/share/c1/c1_GraphBuilder.cpp b/src/hotspot/share/c1/c1_GraphBuilder.cpp index 780ced7f433b2..dc4475a4b8101 100644 --- a/src/hotspot/share/c1/c1_GraphBuilder.cpp +++ b/src/hotspot/share/c1/c1_GraphBuilder.cpp @@ -2116,7 +2116,7 @@ void GraphBuilder::invoke(Bytecodes::Code code) { } if (cha_monomorphic_target != nullptr) { - assert(!target->can_be_statically_bound() || target == cha_monomorphic_target, ""); + assert(!target->can_be_statically_bound() || target->equals(cha_monomorphic_target), ""); assert(!cha_monomorphic_target->is_abstract(), ""); if (!cha_monomorphic_target->can_be_statically_bound(actual_recv)) { // If we inlined because CHA revealed only a single target method, diff --git a/src/hotspot/share/cds/archiveHeapWriter.hpp b/src/hotspot/share/cds/archiveHeapWriter.hpp index b337b75402fd6..352aeb9a08f7c 100644 --- a/src/hotspot/share/cds/archiveHeapWriter.hpp +++ b/src/hotspot/share/cds/archiveHeapWriter.hpp @@ -112,10 +112,11 @@ class ArchiveHeapWriter : AllStatic { public: static const intptr_t NOCOOPS_REQUESTED_BASE = 0x10000000; - // The minimum region size of all collectors that are supported by CDS. - // G1 heap region size can never be smaller than 1M. - // Shenandoah heap region size can never be smaller than 256K. - static constexpr int MIN_GC_REGION_ALIGNMENT = 256 * K; + // The minimum region size of all collectors that are supported by CDS in + // ArchiveHeapLoader::can_map() mode. Currently only G1 is supported. G1's region size + // depends on -Xmx, but can never be smaller than 1 * M. + // (TODO: Perhaps change to 256K to be compatible with Shenandoah) + static constexpr int MIN_GC_REGION_ALIGNMENT = 1 * M; private: class EmbeddedOopRelocator; diff --git a/src/hotspot/share/ci/ciMethod.cpp b/src/hotspot/share/ci/ciMethod.cpp index b2ac3a8b2175c..94b405cdbfacd 100644 --- a/src/hotspot/share/ci/ciMethod.cpp +++ b/src/hotspot/share/ci/ciMethod.cpp @@ -781,6 +781,22 @@ bool ciMethod::can_omit_stack_trace() const { return _can_omit_stack_trace; } +// ------------------------------------------------------------------ +// ciMethod::equals +// +// Returns true if the methods are the same, taking redefined methods +// into account. +bool ciMethod::equals(const ciMethod* m) const { + if (this == m) return true; + VM_ENTRY_MARK; + Method* m1 = this->get_Method(); + Method* m2 = m->get_Method(); + if (m1->is_old()) m1 = m1->get_new_method(); + if (m2->is_old()) m2 = m2->get_new_method(); + return m1 == m2; +} + + // ------------------------------------------------------------------ // ciMethod::resolve_invoke // diff --git a/src/hotspot/share/ci/ciMethod.hpp b/src/hotspot/share/ci/ciMethod.hpp index 5a4a1dd1c7fc3..5cb63204d0b72 100644 --- a/src/hotspot/share/ci/ciMethod.hpp +++ b/src/hotspot/share/ci/ciMethod.hpp @@ -366,6 +366,8 @@ class ciMethod : public ciMetadata { bool can_omit_stack_trace() const; + bool equals(const ciMethod* m) const; + // Replay data methods static void dump_name_as_ascii(outputStream* st, Method* method); void dump_name_as_ascii(outputStream* st); diff --git a/src/hotspot/share/classfile/systemDictionary.cpp b/src/hotspot/share/classfile/systemDictionary.cpp index 7f9e6430cc651..e32d124013d8b 100644 --- a/src/hotspot/share/classfile/systemDictionary.cpp +++ b/src/hotspot/share/classfile/systemDictionary.cpp @@ -261,17 +261,32 @@ Symbol* SystemDictionary::class_name_symbol(const char* name, Symbol* exception, if (name == nullptr) { THROW_MSG_NULL(exception, "No class name given"); } - if ((int)strlen(name) > Symbol::max_length()) { + size_t name_len = strlen(name); + if (name_len > static_cast(Symbol::max_length())) { // It's impossible to create this class; the name cannot fit - // into the constant pool. - Exceptions::fthrow(THREAD_AND_LOCATION, exception, - "Class name exceeds maximum length of %d: %s", - Symbol::max_length(), - name); + // into the constant pool. If necessary report an abridged name + // in the exception message. + if (name_len > static_cast(MaxStringPrintSize)) { + Exceptions::fthrow(THREAD_AND_LOCATION, exception, + "Class name exceeds maximum length of %d: %.*s ... (%zu characters omitted) ... %.*s", + Symbol::max_length(), + MaxStringPrintSize / 2, + name, + name_len - 2 * (MaxStringPrintSize / 2), // allows for odd value + MaxStringPrintSize / 2, + name + name_len - MaxStringPrintSize / 2); + } + else { + Exceptions::fthrow(THREAD_AND_LOCATION, exception, + "Class name exceeds maximum length of %d: %s", + Symbol::max_length(), + name); + } return nullptr; } // Callers should ensure that the name is never an illegal UTF8 string. - assert(UTF8::is_legal_utf8((const unsigned char*)name, (int)strlen(name), false), + assert(UTF8::is_legal_utf8((const unsigned char*)name, + static_cast(name_len), false), "Class name is not a valid utf8 string."); // Make a new symbol for the class name. diff --git a/src/hotspot/share/classfile/vmClassMacros.hpp b/src/hotspot/share/classfile/vmClassMacros.hpp index 503b595074d80..10fa89007957c 100644 --- a/src/hotspot/share/classfile/vmClassMacros.hpp +++ b/src/hotspot/share/classfile/vmClassMacros.hpp @@ -77,6 +77,7 @@ do_klass(StackOverflowError_klass, java_lang_StackOverflowError ) \ do_klass(IllegalMonitorStateException_klass, java_lang_IllegalMonitorStateException ) \ do_klass(Reference_klass, java_lang_ref_Reference ) \ + do_klass(IllegalCallerException_klass, java_lang_IllegalCallerException ) \ \ /* ref klasses and set reference types */ \ do_klass(SoftReference_klass, java_lang_ref_SoftReference ) \ diff --git a/src/hotspot/share/classfile/vmIntrinsics.cpp b/src/hotspot/share/classfile/vmIntrinsics.cpp index e60495d1f47fd..b470eb9b8380d 100644 --- a/src/hotspot/share/classfile/vmIntrinsics.cpp +++ b/src/hotspot/share/classfile/vmIntrinsics.cpp @@ -242,6 +242,8 @@ bool vmIntrinsics::disabled_by_jvm_flags(vmIntrinsics::ID id) { case vmIntrinsics::_Reference_get: case vmIntrinsics::_Continuation_doYield: case vmIntrinsics::_Continuation_enterSpecial: + case vmIntrinsics::_Continuation_pin: + case vmIntrinsics::_Continuation_unpin: break; default: return true; diff --git a/src/hotspot/share/classfile/vmIntrinsics.hpp b/src/hotspot/share/classfile/vmIntrinsics.hpp index 7a5c2ee47bb52..4b772c171d5a6 100644 --- a/src/hotspot/share/classfile/vmIntrinsics.hpp +++ b/src/hotspot/share/classfile/vmIntrinsics.hpp @@ -600,6 +600,8 @@ class methodHandle; do_alias(continuationOnPinned_signature, int_void_signature) \ do_intrinsic(_Continuation_doYield, jdk_internal_vm_Continuation, doYield_name, continuationDoYield_signature, F_SN) \ do_alias( continuationDoYield_signature, void_int_signature) \ + do_intrinsic(_Continuation_pin, jdk_internal_vm_Continuation, pin_name, void_method_signature, F_SN) \ + do_intrinsic(_Continuation_unpin, jdk_internal_vm_Continuation, unpin_name, void_method_signature, F_SN) \ \ /* java/lang/VirtualThread */ \ do_intrinsic(_notifyJvmtiVThreadStart, java_lang_VirtualThread, notifyJvmtiStart_name, void_method_signature, F_RN) \ diff --git a/src/hotspot/share/classfile/vmSymbols.hpp b/src/hotspot/share/classfile/vmSymbols.hpp index 8d1ae20eac07c..a65ab86fa0a8d 100644 --- a/src/hotspot/share/classfile/vmSymbols.hpp +++ b/src/hotspot/share/classfile/vmSymbols.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 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 @@ -203,6 +203,7 @@ class SerializeClosure; template(java_lang_CloneNotSupportedException, "java/lang/CloneNotSupportedException") \ template(java_lang_IllegalAccessException, "java/lang/IllegalAccessException") \ template(java_lang_IllegalArgumentException, "java/lang/IllegalArgumentException") \ + template(java_lang_IllegalCallerException, "java/lang/IllegalCallerException") \ template(java_lang_IllegalStateException, "java/lang/IllegalStateException") \ template(java_lang_IllegalMonitorStateException, "java/lang/IllegalMonitorStateException") \ template(java_lang_IllegalThreadStateException, "java/lang/IllegalThreadStateException") \ @@ -406,6 +407,8 @@ class SerializeClosure; template(onContinue_name, "onContinue0") \ template(scope_name, "scope") \ template(yieldInfo_name, "yieldInfo") \ + template(pin_name, "pin") \ + template(unpin_name, "unpin") \ template(tail_name, "tail") \ template(size_name, "size") \ template(bottom_name, "bottom") \ @@ -586,7 +589,7 @@ class SerializeClosure; template(string_boolean_class_signature, "(Ljava/lang/String;Z)Ljava/lang/Class;") \ template(object_object_object_signature, "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;") \ template(string_string_signature, "(Ljava/lang/String;)Ljava/lang/String;") \ - template(classloader_string_long_signature, "(Ljava/lang/ClassLoader;Ljava/lang/String;)J") \ + template(classloader_class_string_string_long_signature, "(Ljava/lang/ClassLoader;Ljava/lang/Class;Ljava/lang/String;Ljava/lang/String;)J") \ template(byte_array_void_signature, "([B)V") \ template(long_long_void_signature, "(JJ)V") \ template(void_byte_array_signature, "()[B") \ diff --git a/src/hotspot/share/gc/shared/gcLocker.cpp b/src/hotspot/share/gc/shared/gcLocker.cpp index 6f1961758222f..42b40309d9869 100644 --- a/src/hotspot/share/gc/shared/gcLocker.cpp +++ b/src/hotspot/share/gc/shared/gcLocker.cpp @@ -33,11 +33,33 @@ #include "runtime/javaThread.inline.hpp" #include "runtime/safepoint.hpp" #include "runtime/threadSMR.hpp" +#include "utilities/ticks.hpp" volatile jint GCLocker::_jni_lock_count = 0; volatile bool GCLocker::_needs_gc = false; unsigned int GCLocker::_total_collections = 0; +// GCLockerTimingDebugLogger tracks specific timing information for GC lock waits. +class GCLockerTimingDebugLogger : public StackObj { + const char* _log_message; + Ticks _start; + +public: + GCLockerTimingDebugLogger(const char* log_message) : _log_message(log_message) { + assert(_log_message != nullptr, "GC locker debug message must be set."); + _start = Ticks::now(); + } + + ~GCLockerTimingDebugLogger() { + Log(gc, jni) log; + if (log.is_debug()) { + ResourceMark rm; // JavaThread::name() allocates to convert to UTF8 + const Tickspan elapsed_time = Ticks::now() - _start; + log.debug("%s Resumed after " UINT64_FORMAT "ms. Thread \"%s\".", _log_message, elapsed_time.milliseconds(), Thread::current()->name()); + } + } +}; + #ifdef ASSERT volatile jint GCLocker::_debug_jni_lock_count = 0; #endif @@ -110,11 +132,11 @@ void GCLocker::stall_until_clear() { if (needs_gc()) { GCLockerTracer::inc_stall_count(); log_debug_jni("Allocation failed. Thread stalled by JNI critical section."); - } - - // Wait for _needs_gc to be cleared - while (needs_gc()) { - ml.wait(); + GCLockerTimingDebugLogger logger("Thread stalled by JNI critical section."); + // Wait for _needs_gc to be cleared + while (needs_gc()) { + ml.wait(); + } } } @@ -127,16 +149,20 @@ void GCLocker::jni_lock(JavaThread* thread) { assert(!thread->in_critical(), "shouldn't currently be in a critical region"); MonitorLocker ml(JNICritical_lock); // Block entering threads if there's a pending GC request. - while (needs_gc()) { - // There's at least one thread that has not left the critical region (CR) - // completely. When that last thread (no new threads can enter CR due to the - // blocking) exits CR, it calls `jni_unlock`, which sets `_needs_gc` - // to false and wakes up all blocked threads. - // We would like to assert #threads in CR to be > 0, `_jni_lock_count > 0` - // in the code, but it's too strong; it's possible that the last thread - // has called `jni_unlock`, but not yet finished the call, e.g. initiating - // a GCCause::_gc_locker GC. - ml.wait(); + if (needs_gc()) { + log_debug_jni("Blocking thread as there is a pending GC request"); + GCLockerTimingDebugLogger logger("Thread blocked to enter critical region."); + while (needs_gc()) { + // There's at least one thread that has not left the critical region (CR) + // completely. When that last thread (no new threads can enter CR due to the + // blocking) exits CR, it calls `jni_unlock`, which sets `_needs_gc` + // to false and wakes up all blocked threads. + // We would like to assert #threads in CR to be > 0, `_jni_lock_count > 0` + // in the code, but it's too strong; it's possible that the last thread + // has called `jni_unlock`, but not yet finished the call, e.g. initiating + // a GCCause::_gc_locker GC. + ml.wait(); + } } thread->enter_critical(); _jni_lock_count++; @@ -148,6 +174,7 @@ void GCLocker::jni_unlock(JavaThread* thread) { MutexLocker mu(JNICritical_lock); _jni_lock_count--; decrement_debug_jni_lock_count(); + log_debug_jni("Thread exiting critical region."); thread->exit_critical(); if (needs_gc() && !is_active_internal()) { // We're the last thread out. Request a GC. @@ -161,7 +188,7 @@ void GCLocker::jni_unlock(JavaThread* thread) { { // Must give up the lock while at a safepoint MutexUnlocker munlock(JNICritical_lock); - log_debug_jni("Performing GC after exiting critical section."); + log_debug_jni("Last thread exiting. Performing GC after exiting critical section."); Universe::heap()->collect(GCCause::_gc_locker); } _needs_gc = false; diff --git a/src/hotspot/share/gc/shenandoah/shenandoahConcurrentGC.cpp b/src/hotspot/share/gc/shenandoah/shenandoahConcurrentGC.cpp index 0e18b59103746..ed40fecfc1db8 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahConcurrentGC.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahConcurrentGC.cpp @@ -613,12 +613,6 @@ void ShenandoahConcurrentGC::op_final_mark() { // From here on, we need to update references. heap->set_has_forwarded_objects(true); - // Verify before arming for concurrent processing. - // Otherwise, verification can trigger stack processing. - if (ShenandoahVerify) { - heap->verifier()->verify_during_evacuation(); - } - // Arm nmethods/stack for concurrent processing ShenandoahCodeRoots::arm_nmethods_for_evac(); ShenandoahStackWatermark::change_epoch_id(); diff --git a/src/hotspot/share/gc/shenandoah/shenandoahDegeneratedGC.cpp b/src/hotspot/share/gc/shenandoah/shenandoahDegeneratedGC.cpp index 6b597d9b2d7b3..81d07a414cd95 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahDegeneratedGC.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahDegeneratedGC.cpp @@ -276,12 +276,12 @@ void ShenandoahDegenGC::op_prepare_evacuation() { } if (!heap->collection_set()->is_empty()) { + if (ShenandoahVerify) { + heap->verifier()->verify_before_evacuation(); + } + heap->set_evacuation_in_progress(true); heap->set_has_forwarded_objects(true); - - if(ShenandoahVerify) { - heap->verifier()->verify_during_evacuation(); - } } else { if (ShenandoahVerify) { heap->verifier()->verify_after_concmark(); diff --git a/src/hotspot/share/gc/shenandoah/shenandoahVerifier.cpp b/src/hotspot/share/gc/shenandoah/shenandoahVerifier.cpp index e5db7a9b392e9..518787728895b 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahVerifier.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahVerifier.cpp @@ -661,14 +661,6 @@ void ShenandoahVerifier::verify_at_safepoint(const char *label, enabled = true; expected = ShenandoahHeap::HAS_FORWARDED; break; - case _verify_gcstate_evacuation: - enabled = true; - expected = ShenandoahHeap::HAS_FORWARDED | ShenandoahHeap::EVACUATION; - if (!_heap->is_stw_gc_in_progress()) { - // Only concurrent GC sets this. - expected |= ShenandoahHeap::WEAK_ROOTS; - } - break; case _verify_gcstate_stable: enabled = true; expected = ShenandoahHeap::STABLE; @@ -851,18 +843,6 @@ void ShenandoahVerifier::verify_before_evacuation() { ); } -void ShenandoahVerifier::verify_during_evacuation() { - verify_at_safepoint( - "During Evacuation", - _verify_forwarded_allow, // some forwarded references are allowed - _verify_marked_disable, // walk only roots - _verify_cset_disable, // some cset references are not forwarded yet - _verify_liveness_disable, // liveness data might be already stale after pre-evacs - _verify_regions_disable, // trash regions not yet recycled - _verify_gcstate_evacuation // evacuation is in progress - ); -} - void ShenandoahVerifier::verify_before_updaterefs() { verify_at_safepoint( "Before Updating References", diff --git a/src/hotspot/share/gc/shenandoah/shenandoahVerifier.hpp b/src/hotspot/share/gc/shenandoah/shenandoahVerifier.hpp index dd4eb901a3348..1617678d92826 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahVerifier.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahVerifier.hpp @@ -133,10 +133,7 @@ class ShenandoahVerifier : public CHeapObj { _verify_gcstate_stable_weakroots, // Nothing is in progress, some objects are forwarded - _verify_gcstate_forwarded, - - // Evacuation is in progress, some objects are forwarded - _verify_gcstate_evacuation + _verify_gcstate_forwarded } VerifyGCState; struct VerifyOptions { @@ -175,7 +172,6 @@ class ShenandoahVerifier : public CHeapObj { void verify_before_concmark(); void verify_after_concmark(); void verify_before_evacuation(); - void verify_during_evacuation(); void verify_before_updaterefs(); void verify_after_updaterefs(); void verify_before_fullgc(); diff --git a/src/hotspot/share/gc/z/zDriver.cpp b/src/hotspot/share/gc/z/zDriver.cpp index 3836f330142f1..107be979c2584 100644 --- a/src/hotspot/share/gc/z/zDriver.cpp +++ b/src/hotspot/share/gc/z/zDriver.cpp @@ -230,8 +230,8 @@ void ZDriverMinor::terminate() { _port.send_async(request); } -static bool should_clear_soft_references(GCCause::Cause cause) { - // Clear soft references if implied by the GC cause +static bool should_clear_all_soft_references(GCCause::Cause cause) { + // Clear all soft references if implied by the GC cause switch (cause) { case GCCause::_wb_full_gc: case GCCause::_metadata_GC_clear_soft_refs: @@ -259,12 +259,12 @@ static bool should_clear_soft_references(GCCause::Cause cause) { break; } - // Clear soft references if threads are stalled waiting for an old collection + // Clear all soft references if threads are stalled waiting for an old collection if (ZHeap::heap()->is_alloc_stalling_for_old()) { return true; } - // Don't clear + // Don't clear all soft references return false; } @@ -302,13 +302,17 @@ static bool should_preclean_young(GCCause::Cause cause) { return true; } - // It is important that when soft references are cleared, we also pre-clean the young - // generation, as we might otherwise throw premature OOM. Therefore, all causes that - // trigger soft ref cleaning must also trigger pre-cleaning of young gen. If allocations - // stalled when checking for soft ref cleaning, then since we hold the driver locker all - // the way until we check for young gen pre-cleaning, we can be certain that we should + // We clear all soft references as a last-ditch effort to collect memory + // before throwing an OOM. Therefore it is important that when the GC policy + // is to clear all soft references, that we also pre-clean the young + // generation, as we might otherwise throw premature OOM. + // + // Therefore, all causes that trigger all soft ref clearing must also trigger + // pre-cleaning of young gen. If allocations stalled when checking for all + // soft ref clearing, then since we hold the driver locker all the way until + // we check for young gen pre-cleaning, we can be certain that we should // catch that above and perform young gen pre-cleaning. - assert(!should_clear_soft_references(cause), "Clearing soft references without pre-cleaning young gen"); + assert(!should_clear_all_soft_references(cause), "Clearing all soft references without pre-cleaning young gen"); return false; } @@ -395,6 +399,10 @@ class ZDriverScopeMajor : public StackObj { // Select number of worker threads to use ZGeneration::young()->set_active_workers(request.young_nworkers()); ZGeneration::old()->set_active_workers(request.old_nworkers()); + + // Set up soft reference policy + const bool clear_all = should_clear_all_soft_references(request.cause()); + ZGeneration::old()->set_soft_reference_policy(clear_all); } ~ZDriverScopeMajor() { @@ -444,12 +452,13 @@ void ZDriverMajor::gc(const ZDriverRequest& request) { collect_old(); } -static void handle_alloc_stalling_for_old(bool cleared_soft_refs) { - ZHeap::heap()->handle_alloc_stalling_for_old(cleared_soft_refs); +static void handle_alloc_stalling_for_old() { + const bool cleared_all = ZGeneration::old()->uses_clear_all_soft_reference_policy(); + ZHeap::heap()->handle_alloc_stalling_for_old(cleared_all); } -void ZDriverMajor::handle_alloc_stalls(bool cleared_soft_refs) const { - handle_alloc_stalling_for_old(cleared_soft_refs); +void ZDriverMajor::handle_alloc_stalls() const { + handle_alloc_stalling_for_old(); } void ZDriverMajor::run_thread() { @@ -464,10 +473,6 @@ void ZDriverMajor::run_thread() { abortpoint(); - // Set up soft reference policy - const bool clear_soft_refs = should_clear_soft_references(request.cause()); - ZGeneration::old()->set_soft_reference_policy(clear_soft_refs); - // Run GC gc(request); @@ -477,7 +482,7 @@ void ZDriverMajor::run_thread() { _port.ack(); // Handle allocation stalls - handle_alloc_stalls(clear_soft_refs); + handle_alloc_stalls(); ZBreakpoint::at_after_gc(); } diff --git a/src/hotspot/share/gc/z/zDriver.hpp b/src/hotspot/share/gc/z/zDriver.hpp index 6291a8f359ce2..5f1fe08a0b6ae 100644 --- a/src/hotspot/share/gc/z/zDriver.hpp +++ b/src/hotspot/share/gc/z/zDriver.hpp @@ -112,7 +112,7 @@ class ZDriverMajor : public ZDriver { void collect_old(); void gc(const ZDriverRequest& request); - void handle_alloc_stalls(bool cleared_soft_refs) const; + void handle_alloc_stalls() const; protected: virtual void run_thread(); diff --git a/src/hotspot/share/gc/z/zGeneration.cpp b/src/hotspot/share/gc/z/zGeneration.cpp index 8a7d38e299166..655f47ba49cd8 100644 --- a/src/hotspot/share/gc/z/zGeneration.cpp +++ b/src/hotspot/share/gc/z/zGeneration.cpp @@ -1286,6 +1286,10 @@ void ZGenerationOld::set_soft_reference_policy(bool clear) { _reference_processor.set_soft_reference_policy(clear); } +bool ZGenerationOld::uses_clear_all_soft_reference_policy() const { + return _reference_processor.uses_clear_all_soft_reference_policy(); +} + class ZRendezvousHandshakeClosure : public HandshakeClosure { public: ZRendezvousHandshakeClosure() diff --git a/src/hotspot/share/gc/z/zGeneration.hpp b/src/hotspot/share/gc/z/zGeneration.hpp index aec48a0a07236..3e18919eee43a 100644 --- a/src/hotspot/share/gc/z/zGeneration.hpp +++ b/src/hotspot/share/gc/z/zGeneration.hpp @@ -309,6 +309,7 @@ class ZGenerationOld : public ZGeneration { // Reference processing ReferenceDiscoverer* reference_discoverer(); void set_soft_reference_policy(bool clear); + bool uses_clear_all_soft_reference_policy() const; uint total_collections_at_start() const; diff --git a/src/hotspot/share/gc/z/zHeap.inline.hpp b/src/hotspot/share/gc/z/zHeap.inline.hpp index d983c002afaa8..127212aef0b3a 100644 --- a/src/hotspot/share/gc/z/zHeap.inline.hpp +++ b/src/hotspot/share/gc/z/zHeap.inline.hpp @@ -86,8 +86,8 @@ inline void ZHeap::handle_alloc_stalling_for_young() { _page_allocator.handle_alloc_stalling_for_young(); } -inline void ZHeap::handle_alloc_stalling_for_old(bool cleared_soft_refs) { - _page_allocator.handle_alloc_stalling_for_old(cleared_soft_refs); +inline void ZHeap::handle_alloc_stalling_for_old(bool cleared_all_soft_refs) { + _page_allocator.handle_alloc_stalling_for_old(cleared_all_soft_refs); } inline bool ZHeap::is_oop(uintptr_t addr) const { diff --git a/src/hotspot/share/gc/z/zPageAllocator.cpp b/src/hotspot/share/gc/z/zPageAllocator.cpp index 519c36e556d8f..b1fb1e4837391 100644 --- a/src/hotspot/share/gc/z/zPageAllocator.cpp +++ b/src/hotspot/share/gc/z/zPageAllocator.cpp @@ -985,9 +985,9 @@ void ZPageAllocator::handle_alloc_stalling_for_young() { restart_gc(); } -void ZPageAllocator::handle_alloc_stalling_for_old(bool cleared_soft_refs) { +void ZPageAllocator::handle_alloc_stalling_for_old(bool cleared_all_soft_refs) { ZLocker locker(&_lock); - if (cleared_soft_refs) { + if (cleared_all_soft_refs) { notify_out_of_memory(); } restart_gc(); diff --git a/src/hotspot/share/gc/z/zReferenceProcessor.cpp b/src/hotspot/share/gc/z/zReferenceProcessor.cpp index 1252de2ac2723..797bd96353687 100644 --- a/src/hotspot/share/gc/z/zReferenceProcessor.cpp +++ b/src/hotspot/share/gc/z/zReferenceProcessor.cpp @@ -113,7 +113,7 @@ static void list_append(zaddress& head, zaddress& tail, zaddress reference) { ZReferenceProcessor::ZReferenceProcessor(ZWorkers* workers) : _workers(workers), _soft_reference_policy(nullptr), - _clear_all_soft_refs(false), + _uses_clear_all_soft_reference_policy(false), _encountered_count(), _discovered_count(), _enqueued_count(), @@ -121,13 +121,13 @@ ZReferenceProcessor::ZReferenceProcessor(ZWorkers* workers) _pending_list(zaddress::null), _pending_list_tail(zaddress::null) {} -void ZReferenceProcessor::set_soft_reference_policy(bool clear) { +void ZReferenceProcessor::set_soft_reference_policy(bool clear_all_soft_references) { static AlwaysClearPolicy always_clear_policy; static LRUMaxHeapPolicy lru_max_heap_policy; - _clear_all_soft_refs = clear; + _uses_clear_all_soft_reference_policy = clear_all_soft_references; - if (clear) { + if (clear_all_soft_references) { _soft_reference_policy = &always_clear_policy; } else { _soft_reference_policy = &lru_max_heap_policy; @@ -136,6 +136,10 @@ void ZReferenceProcessor::set_soft_reference_policy(bool clear) { _soft_reference_policy->setup(); } +bool ZReferenceProcessor::uses_clear_all_soft_reference_policy() const { + return _uses_clear_all_soft_reference_policy; +} + bool ZReferenceProcessor::is_inactive(zaddress reference, oop referent, ReferenceType type) const { if (type == REF_FINAL) { // A FinalReference is inactive if its next field is non-null. An application can't @@ -440,7 +444,7 @@ class ZReferenceProcessorTask : public ZTask { void ZReferenceProcessor::process_references() { ZStatTimerOld timer(ZSubPhaseConcurrentReferencesProcess); - if (_clear_all_soft_refs) { + if (_uses_clear_all_soft_reference_policy) { log_info(gc, ref)("Clearing All SoftReferences"); } diff --git a/src/hotspot/share/gc/z/zReferenceProcessor.hpp b/src/hotspot/share/gc/z/zReferenceProcessor.hpp index 7a8900827da83..f8e924ed99fc1 100644 --- a/src/hotspot/share/gc/z/zReferenceProcessor.hpp +++ b/src/hotspot/share/gc/z/zReferenceProcessor.hpp @@ -41,7 +41,7 @@ class ZReferenceProcessor : public ReferenceDiscoverer { ZWorkers* const _workers; ReferencePolicy* _soft_reference_policy; - bool _clear_all_soft_refs; + bool _uses_clear_all_soft_reference_policy; ZPerWorker _encountered_count; ZPerWorker _discovered_count; ZPerWorker _enqueued_count; @@ -69,7 +69,9 @@ class ZReferenceProcessor : public ReferenceDiscoverer { public: ZReferenceProcessor(ZWorkers* workers); - void set_soft_reference_policy(bool clear); + void set_soft_reference_policy(bool clear_all_soft_references); + bool uses_clear_all_soft_reference_policy() const; + void reset_statistics(); virtual bool discover_reference(oop reference, ReferenceType type); diff --git a/src/hotspot/share/jfr/jni/jfrJniMethod.hpp b/src/hotspot/share/jfr/jni/jfrJniMethod.hpp index ca119c1f8c35a..680e6bee1ee68 100644 --- a/src/hotspot/share/jfr/jni/jfrJniMethod.hpp +++ b/src/hotspot/share/jfr/jni/jfrJniMethod.hpp @@ -113,7 +113,7 @@ jobject JNICALL jfr_get_event_writer(JNIEnv* env, jclass jvm); jobject JNICALL jfr_new_event_writer(JNIEnv* env, jclass jvm); -jboolean JNICALL jfr_event_writer_flush(JNIEnv* env, jclass jvm, jobject writer, jint used_size, jint requested_size); +void JNICALL jfr_event_writer_flush(JNIEnv* env, jclass jvm, jobject writer, jint used_size, jint requested_size); jlong JNICALL jfr_commit(JNIEnv* env, jclass cls, jlong next_position); void JNICALL jfr_flush(JNIEnv* env, jclass jvm); diff --git a/src/hotspot/share/jfr/jni/jfrUpcalls.cpp b/src/hotspot/share/jfr/jni/jfrUpcalls.cpp index bb316700ac011..2f1cb7e2d540d 100644 --- a/src/hotspot/share/jfr/jni/jfrUpcalls.cpp +++ b/src/hotspot/share/jfr/jni/jfrUpcalls.cpp @@ -191,6 +191,10 @@ void JfrUpcalls::new_bytes_eager_instrumentation(jlong trace_id, bool JfrUpcalls::unhide_internal_types(TRAPS) { DEBUG_ONLY(JfrJavaSupport::check_java_thread_in_vm(THREAD)); + if (!initialize(THREAD)) { + log_error(jfr, system)("JfrUpcall could not be initialized."); + return false; + } JavaValue result(T_VOID); const Klass* klass = SystemDictionary::resolve_or_fail(jvm_upcalls_class_sym, true, CHECK_false); assert(klass != nullptr, "invariant"); diff --git a/src/hotspot/share/jfr/support/jfrSymbolTable.cpp b/src/hotspot/share/jfr/support/jfrSymbolTable.cpp index ffb54f4d0caee..e3c34e46a1a4a 100644 --- a/src/hotspot/share/jfr/support/jfrSymbolTable.cpp +++ b/src/hotspot/share/jfr/support/jfrSymbolTable.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 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 @@ -23,11 +23,10 @@ */ #include "precompiled.hpp" -#include "classfile/javaClasses.inline.hpp" #include "classfile/classLoaderData.hpp" +#include "classfile/javaClasses.hpp" #include "jfr/support/jfrSymbolTable.hpp" -#include "oops/instanceKlass.hpp" -#include "oops/oop.inline.hpp" +#include "oops/klass.hpp" #include "oops/symbol.hpp" #include "runtime/mutexLocker.hpp" @@ -200,7 +199,7 @@ traceid JfrSymbolTable::bootstrap_name(bool leakp) { traceid JfrSymbolTable::mark(const Symbol* sym, bool leakp /* false */) { assert(sym != nullptr, "invariant"); - return mark((uintptr_t)sym->identity_hash(), sym, leakp); + return mark(sym->identity_hash(), sym, leakp); } traceid JfrSymbolTable::mark(uintptr_t hash, const Symbol* sym, bool leakp) { @@ -236,59 +235,25 @@ traceid JfrSymbolTable::mark(uintptr_t hash, const char* str, bool leakp) { } /* -* hidden classes symbol is the external name + -* the address of its InstanceKlass slash appended: -* java.lang.invoke.LambdaForm$BMH/22626602 -* -* caller needs ResourceMark -*/ - -uintptr_t JfrSymbolTable::hidden_klass_name_hash(const InstanceKlass* ik) { - assert(ik != nullptr, "invariant"); - assert(ik->is_hidden(), "invariant"); - const oop mirror = ik->java_mirror_no_keepalive(); - assert(mirror != nullptr, "invariant"); - return (uintptr_t)mirror->identity_hash(); -} - -static const char* create_hidden_klass_symbol(const InstanceKlass* ik, uintptr_t hash) { - assert(ik != nullptr, "invariant"); - assert(ik->is_hidden(), "invariant"); - assert(hash != 0, "invariant"); - char* hidden_symbol = nullptr; - const oop mirror = ik->java_mirror_no_keepalive(); - assert(mirror != nullptr, "invariant"); - char hash_buf[40]; - os::snprintf_checked(hash_buf, sizeof(hash_buf), "/" UINTX_FORMAT, hash); - const size_t hash_len = strlen(hash_buf); - const size_t result_len = ik->name()->utf8_length(); - hidden_symbol = NEW_RESOURCE_ARRAY(char, result_len + hash_len + 1); - ik->name()->as_klass_external_name(hidden_symbol, (int)result_len + 1); - assert(strlen(hidden_symbol) == result_len, "invariant"); - strcpy(hidden_symbol + result_len, hash_buf); - assert(strlen(hidden_symbol) == result_len + hash_len, "invariant"); - return hidden_symbol; -} - -bool JfrSymbolTable::is_hidden_klass(const Klass* k) { + * The hidden class symbol is the external name with the + * address of its Klass slash appended. + * + * "java.lang.invoke.LambdaForm$DMH/0x0000000037144c00" + * + * Caller needs ResourceMark. + */ +traceid JfrSymbolTable::mark_hidden_klass_name(const Klass* k, bool leakp) { assert(k != nullptr, "invariant"); - return k->is_instance_klass() && ((const InstanceKlass*)k)->is_hidden(); -} - -traceid JfrSymbolTable::mark_hidden_klass_name(const InstanceKlass* ik, bool leakp) { - assert(ik != nullptr, "invariant"); - assert(ik->is_hidden(), "invariant"); - const uintptr_t hash = hidden_klass_name_hash(ik); - const char* const hidden_symbol = create_hidden_klass_symbol(ik, hash); - return mark(hash, hidden_symbol, leakp); + assert(k->is_hidden(), "invariant"); + const uintptr_t hash = k->name()->identity_hash(); + return mark(hash, k->external_name(), leakp); } traceid JfrSymbolTable::mark(const Klass* k, bool leakp) { assert(k != nullptr, "invariant"); traceid symbol_id = 0; - if (is_hidden_klass(k)) { - assert(k->is_instance_klass(), "invariant"); - symbol_id = mark_hidden_klass_name((const InstanceKlass*)k, leakp); + if (k->is_hidden()) { + symbol_id = mark_hidden_klass_name(k, leakp); } else { Symbol* const sym = k->name(); if (sym != nullptr) { diff --git a/src/hotspot/share/jfr/support/jfrSymbolTable.hpp b/src/hotspot/share/jfr/support/jfrSymbolTable.hpp index a1951e52cc376..8cefa287c8ade 100644 --- a/src/hotspot/share/jfr/support/jfrSymbolTable.hpp +++ b/src/hotspot/share/jfr/support/jfrSymbolTable.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 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 @@ -100,16 +100,13 @@ class JfrSymbolTable : public JfrCHeapObj { traceid mark(const Symbol* sym, bool leakp = false); traceid mark(const char* str, bool leakp = false); traceid mark(uintptr_t hash, const char* str, bool leakp); + traceid mark_hidden_klass_name(const Klass* k, bool leakp); traceid bootstrap_name(bool leakp); bool has_entries() const { return has_symbol_entries() || has_string_entries(); } bool has_symbol_entries() const { return _symbol_list != nullptr; } bool has_string_entries() const { return _string_list != nullptr; } - traceid mark_hidden_klass_name(const InstanceKlass* k, bool leakp); - bool is_hidden_klass(const Klass* k); - uintptr_t hidden_klass_name_hash(const InstanceKlass* ik); - // hashtable(s) callbacks void on_link(const SymbolEntry* entry); bool on_equals(uintptr_t hash, const SymbolEntry* entry); diff --git a/src/hotspot/share/jfr/writers/jfrJavaEventWriter.cpp b/src/hotspot/share/jfr/writers/jfrJavaEventWriter.cpp index 2bd66ce7c1cc4..d9610bcc97005 100644 --- a/src/hotspot/share/jfr/writers/jfrJavaEventWriter.cpp +++ b/src/hotspot/share/jfr/writers/jfrJavaEventWriter.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 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 @@ -36,6 +36,7 @@ #include "oops/instanceKlass.hpp" #include "oops/oop.inline.hpp" #include "runtime/fieldDescriptor.inline.hpp" +#include "runtime/globals.hpp" #include "runtime/handles.inline.hpp" #include "runtime/interfaceSupport.inline.hpp" #include "runtime/jniHandles.inline.hpp" @@ -49,6 +50,7 @@ static int max_pos_offset = invalid_offset; static int excluded_offset = invalid_offset; static int thread_id_offset = invalid_offset; static int valid_offset = invalid_offset; +static int pin_offset = invalid_offset; static bool setup_event_writer_offsets(TRAPS) { const char class_name[] = "jdk/jfr/internal/event/EventWriter"; @@ -98,6 +100,13 @@ static bool setup_event_writer_offsets(TRAPS) { assert(invalid_offset == valid_offset, "invariant"); JfrJavaSupport::compute_field_offset(valid_offset, klass, valid_sym, vmSymbols::bool_signature()); assert(valid_offset != invalid_offset, "invariant"); + + const char pin_name[] = "pinVirtualThread"; + Symbol* const pin_sym = SymbolTable::new_symbol(valid_name); + assert(pin_sym != nullptr, "invariant"); + assert(invalid_offset == pin_offset, "invariant"); + JfrJavaSupport::compute_field_offset(pin_offset, klass, pin_sym, vmSymbols::bool_signature()); + assert(pin_offset != invalid_offset, "invariant"); return true; } @@ -219,13 +228,18 @@ void JfrJavaEventWriter::notify(JavaThread* jt) { } } +static inline bool pin_virtual(const JavaThread* jt) { + assert(jt != nullptr, "invariant"); + return JfrThreadLocal::is_vthread(jt) && VMContinuations; +} + static jobject create_new_event_writer(JfrBuffer* buffer, JfrThreadLocal* tl, TRAPS) { assert(buffer != nullptr, "invariant"); DEBUG_ONLY(JfrJavaSupport::check_java_thread_in_vm(THREAD)); HandleMark hm(THREAD); static const char klass[] = "jdk/jfr/internal/event/EventWriter"; static const char method[] = ""; - static const char signature[] = "(JJJZZ)V"; + static const char signature[] = "(JJJZZZ)V"; JavaValue result(T_OBJECT); JfrJavaArguments args(&result, klass, method, signature, CHECK_NULL); @@ -234,6 +248,7 @@ static jobject create_new_event_writer(JfrBuffer* buffer, JfrThreadLocal* tl, TR args.push_long((jlong)buffer->end()); args.push_long((jlong)JfrThreadLocal::thread_id(THREAD)); args.push_int((jint)JNI_TRUE); // valid + args.push_int(pin_virtual(THREAD) ? (jint)JNI_TRUE : (jint)JNI_FALSE); args.push_int(tl->is_excluded() ? (jint)JNI_TRUE : (jint)JNI_FALSE); // excluded JfrJavaSupport::new_object_global_ref(&args, CHECK_NULL); return result.get_jobject(); @@ -249,9 +264,12 @@ jobject JfrJavaEventWriter::event_writer(JavaThread* jt) { const jlong event_writer_tid = writer->long_field(thread_id_offset); const jlong current_tid = static_cast(JfrThreadLocal::thread_id(jt)); if (event_writer_tid != current_tid) { + writer->long_field_put(thread_id_offset, current_tid); const bool excluded = tl->is_excluded(); writer->bool_field_put(excluded_offset, excluded); - writer->long_field_put(thread_id_offset, current_tid); + if (!excluded) { + writer->bool_field_put(pin_offset, pin_virtual(jt)); + } } } return h_writer; diff --git a/src/hotspot/share/jvmci/jvmciCompilerToVM.cpp b/src/hotspot/share/jvmci/jvmciCompilerToVM.cpp index af72322ff4bf2..d231fbe8a6a0e 100644 --- a/src/hotspot/share/jvmci/jvmciCompilerToVM.cpp +++ b/src/hotspot/share/jvmci/jvmciCompilerToVM.cpp @@ -710,8 +710,10 @@ C2V_END C2V_VMENTRY_0(jlong, getJObjectValue, (JNIEnv* env, jobject, jobject constant_jobject)) requireNotInHotSpot("getJObjectValue", JVMCI_CHECK_0); - if (!THREAD->has_last_Java_frame()) { - JVMCI_THROW_MSG_0(IllegalStateException, err_msg("Cannot call getJObjectValue without Java frame anchor")); + // Ensure that current JNI handle scope is not the top-most JNIHandleBlock as handles + // in that scope are only released when the thread exits. + if (!THREAD->has_last_Java_frame() && THREAD->active_handles()->pop_frame_link() == nullptr) { + JVMCI_THROW_MSG_0(IllegalStateException, err_msg("Cannot call getJObjectValue without Java frame anchor or a pushed JNI handle block")); } JVMCIObject constant = JVMCIENV->wrap(constant_jobject); Handle constant_value = JVMCIENV->asConstant(constant, JVMCI_CHECK_0); diff --git a/src/hotspot/share/jvmci/vmStructs_jvmci.cpp b/src/hotspot/share/jvmci/vmStructs_jvmci.cpp index be9c0893b3a62..6f71816019541 100644 --- a/src/hotspot/share/jvmci/vmStructs_jvmci.cpp +++ b/src/hotspot/share/jvmci/vmStructs_jvmci.cpp @@ -41,6 +41,7 @@ #include "oops/methodCounters.hpp" #include "oops/objArrayKlass.hpp" #include "prims/jvmtiThreadState.hpp" +#include "runtime/continuationEntry.hpp" #include "runtime/deoptimization.hpp" #include "runtime/flags/jvmFlag.hpp" #include "runtime/osThread.hpp" @@ -250,10 +251,12 @@ nonstatic_field(JavaThread, _held_monitor_count, intx) \ nonstatic_field(JavaThread, _lock_stack, LockStack) \ nonstatic_field(JavaThread, _om_cache, OMCache) \ + nonstatic_field(JavaThread, _cont_entry, ContinuationEntry*) \ JVMTI_ONLY(nonstatic_field(JavaThread, _is_in_VTMS_transition, bool)) \ JVMTI_ONLY(nonstatic_field(JavaThread, _is_in_tmp_VTMS_transition, bool)) \ JVMTI_ONLY(nonstatic_field(JavaThread, _is_disable_suspend, bool)) \ \ + nonstatic_field(ContinuationEntry, _pin_count, uint32_t) \ nonstatic_field(LockStack, _top, uint32_t) \ \ JVMTI_ONLY(static_field(JvmtiVTMSTransitionDisabler, _VTMS_notify_jvmti_events, bool)) \ diff --git a/src/hotspot/share/memory/classLoaderMetaspace.cpp b/src/hotspot/share/memory/classLoaderMetaspace.cpp index 3315c15e67749..08bf42da8e3d9 100644 --- a/src/hotspot/share/memory/classLoaderMetaspace.cpp +++ b/src/hotspot/share/memory/classLoaderMetaspace.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2024, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2020 SAP SE. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -130,9 +130,10 @@ MetaWord* ClassLoaderMetaspace::expand_and_allocate(size_t word_size, Metaspace: // Prematurely returns a metaspace allocation to the _block_freelists // because it is not needed anymore. -void ClassLoaderMetaspace::deallocate(MetaWord* ptr, size_t word_size, bool is_class) { +void ClassLoaderMetaspace::deallocate(MetaWord* ptr, size_t word_size) { MutexLocker fcl(lock(), Mutex::_no_safepoint_check_flag); - if (Metaspace::using_class_space() && is_class) { + const bool is_class = Metaspace::using_class_space() && Metaspace::is_in_class_space(ptr); + if (is_class) { class_space_arena()->deallocate(ptr, word_size); } else { non_class_space_arena()->deallocate(ptr, word_size); diff --git a/src/hotspot/share/memory/classLoaderMetaspace.hpp b/src/hotspot/share/memory/classLoaderMetaspace.hpp index 525c63dde3e4b..176b8c5082acf 100644 --- a/src/hotspot/share/memory/classLoaderMetaspace.hpp +++ b/src/hotspot/share/memory/classLoaderMetaspace.hpp @@ -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 @@ -92,7 +92,7 @@ class ClassLoaderMetaspace : public CHeapObj { // Prematurely returns a metaspace allocation to the _block_freelists // because it is not needed anymore. - void deallocate(MetaWord* ptr, size_t word_size, bool is_class); + void deallocate(MetaWord* ptr, size_t word_size); // Update statistics. This walks all in-use chunks. void add_to_statistics(metaspace::ClmsStats* out) const; diff --git a/src/hotspot/share/memory/metadataFactory.hpp b/src/hotspot/share/memory/metadataFactory.hpp index 14cac8dc191a7..f5935c588d79b 100644 --- a/src/hotspot/share/memory/metadataFactory.hpp +++ b/src/hotspot/share/memory/metadataFactory.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2010, 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 @@ -54,7 +54,7 @@ class MetadataFactory : AllStatic { assert(loader_data != nullptr, "shouldn't pass null"); assert(!data->is_shared(), "cannot deallocate array in shared spaces"); int size = data->size(); - loader_data->metaspace_non_null()->deallocate((MetaWord*)data, size, false); + loader_data->metaspace_non_null()->deallocate((MetaWord*)data, size); } } @@ -68,7 +68,6 @@ class MetadataFactory : AllStatic { assert(!md->on_stack(), "can't deallocate things on stack"); assert(!md->is_shared(), "cannot deallocate if in shared spaces"); md->deallocate_contents(loader_data); - bool is_klass = md->is_klass(); // Call the destructor. This is currently used for MethodData which has a member // that needs to be destructed to release resources. Most Metadata derived classes have noop // destructors and/or cleanup using deallocate_contents. @@ -76,7 +75,7 @@ class MetadataFactory : AllStatic { // or volatile so we can call the destructor of the type T points to. using U = std::remove_cv_t; md->~U(); - loader_data->metaspace_non_null()->deallocate((MetaWord*)md, size, is_klass); + loader_data->metaspace_non_null()->deallocate((MetaWord*)md, size); } } }; diff --git a/src/hotspot/share/memory/metaspace.cpp b/src/hotspot/share/memory/metaspace.cpp index ad51f5ab7b6db..9b3b36f8be02e 100644 --- a/src/hotspot/share/memory/metaspace.cpp +++ b/src/hotspot/share/memory/metaspace.cpp @@ -538,6 +538,8 @@ void MetaspaceGC::compute_new_size() { ////// Metaspace methods ///// const MetaspaceTracer* Metaspace::_tracer = nullptr; +const void* Metaspace::_class_space_start = nullptr; +const void* Metaspace::_class_space_end = nullptr; bool Metaspace::initialized() { return metaspace::MetaspaceContext::context_nonclass() != nullptr @@ -570,6 +572,8 @@ void Metaspace::initialize_class_space(ReservedSpace rs) { "wrong alignment"); MetaspaceContext::initialize_class_space_context(rs); + _class_space_start = rs.base(); + _class_space_end = rs.end(); } // Returns true if class space has been setup (initialize_class_space). @@ -979,17 +983,15 @@ void Metaspace::purge(bool classes_unloaded) { MetaspaceCriticalAllocation::process(); } -bool Metaspace::contains(const void* ptr) { - if (MetaspaceShared::is_in_shared_metaspace(ptr)) { - return true; - } - return contains_non_shared(ptr); -} -bool Metaspace::contains_non_shared(const void* ptr) { - if (using_class_space() && VirtualSpaceList::vslist_class()->contains((MetaWord*)ptr)) { - return true; - } +// Returns true if pointer points into one of the metaspace regions, or +// into the class space. +bool Metaspace::is_in_shared_metaspace(const void* ptr) { + return MetaspaceShared::is_in_shared_metaspace(ptr); +} +// Returns true if pointer points into one of the non-class-space metaspace regions. +bool Metaspace::is_in_nonclass_metaspace(const void* ptr) { return VirtualSpaceList::vslist_nonclass()->contains((MetaWord*)ptr); } + diff --git a/src/hotspot/share/memory/metaspace.hpp b/src/hotspot/share/memory/metaspace.hpp index a90ff77564763..6de901b25d12b 100644 --- a/src/hotspot/share/memory/metaspace.hpp +++ b/src/hotspot/share/memory/metaspace.hpp @@ -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. * Copyright (c) 2017, 2021 SAP SE. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -64,6 +64,10 @@ class Metaspace : public AllStatic { static const MetaspaceTracer* _tracer; + // For quick pointer testing: extent of class space; nullptr if no class space. + static const void* _class_space_start; + static const void* _class_space_end; + static bool _initialized; public: @@ -113,8 +117,32 @@ class Metaspace : public AllStatic { static MetaWord* allocate(ClassLoaderData* loader_data, size_t word_size, MetaspaceObj::Type type); - static bool contains(const void* ptr); - static bool contains_non_shared(const void* ptr); + // Returns true if the pointer points into class space, non-class metaspace, or the + // metadata portion of the CDS archive. + static bool contains(const void* ptr) { + return is_in_shared_metaspace(ptr) || // in cds + is_in_class_space(ptr) || // in class space + is_in_nonclass_metaspace(ptr); // in one of the non-class regions? + } + + // Returns true if the pointer points into class space or into non-class metaspace + static bool contains_non_shared(const void* ptr) { + return is_in_class_space(ptr) || // in class space + is_in_nonclass_metaspace(ptr); // in one of the non-class regions? + } + + // Returns true if pointer points into the CDS klass region. + static bool is_in_shared_metaspace(const void* ptr); + + // Returns true if pointer points into one of the non-class-space metaspace regions. + static bool is_in_nonclass_metaspace(const void* ptr); + + // Returns true if pointer points into class space, false if it doesn't or if + // there is no class space. Class space is a contiguous region, which is why + // two address comparisons are enough. + static inline bool is_in_class_space(const void* ptr) { + return ptr < _class_space_end && ptr >= _class_space_start; + } // Free empty virtualspaces static void purge(bool classes_unloaded); diff --git a/src/hotspot/share/oops/generateOopMap.cpp b/src/hotspot/share/oops/generateOopMap.cpp index eb078daee6bb4..918e6969713c9 100644 --- a/src/hotspot/share/oops/generateOopMap.cpp +++ b/src/hotspot/share/oops/generateOopMap.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 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 @@ -436,12 +436,12 @@ void GenerateOopMap::mark_bbheaders_and_count_gc_points() { /* We will also mark successors of jsr's as basic block headers. */ switch (bytecode) { case Bytecodes::_jsr: - assert(!fellThrough, "should not happen"); - bb_mark_fct(this, bci + Bytecodes::length_for(bytecode), nullptr); - break; case Bytecodes::_jsr_w: assert(!fellThrough, "should not happen"); - bb_mark_fct(this, bci + Bytecodes::length_for(bytecode), nullptr); + // If this is the last bytecode, there is no successor to mark + if (bci + Bytecodes::length_for(bytecode) < method()->code_size()) { + bb_mark_fct(this, bci + Bytecodes::length_for(bytecode), nullptr); + } break; default: break; @@ -502,7 +502,10 @@ void GenerateOopMap::mark_reachable_code() { case Bytecodes::_jsr: case Bytecodes::_jsr_w: assert(!fell_through, "should not happen"); - reachable_basicblock(this, bci + Bytecodes::length_for(bytecode), &change); + // If this is the last bytecode, there is no successor to mark + if (bci + Bytecodes::length_for(bytecode) < method()->code_size()) { + reachable_basicblock(this, bci + Bytecodes::length_for(bytecode), &change); + } break; default: break; @@ -586,9 +589,6 @@ bool GenerateOopMap::jump_targets_do(BytecodeStream *bcs, jmpFct_t jmpFct, int * case Bytecodes::_jsr: assert(bcs->is_wide()==false, "sanity check"); (*jmpFct)(this, bcs->dest(), data); - - - break; case Bytecodes::_jsr_w: (*jmpFct)(this, bcs->dest_w(), data); diff --git a/src/hotspot/share/oops/instanceStackChunkKlass.cpp b/src/hotspot/share/oops/instanceStackChunkKlass.cpp index bf215e1c13e5a..a2227b0a76a5e 100644 --- a/src/hotspot/share/oops/instanceStackChunkKlass.cpp +++ b/src/hotspot/share/oops/instanceStackChunkKlass.cpp @@ -226,7 +226,7 @@ class PrintStackChunkClosure { p2i(fs.sp()), fs.is_interpreted(), f.frame_size(), fs.is_interpreted() ? 0 : f.compiled_frame_stack_argsize()); #ifdef ASSERT - f.print_value_on(_st, nullptr); + f.print_value_on(_st); #else f.print_on(_st); #endif diff --git a/src/hotspot/share/oops/markWord.hpp b/src/hotspot/share/oops/markWord.hpp index 92577a8b40b01..bbd80d02cbda8 100644 --- a/src/hotspot/share/oops/markWord.hpp +++ b/src/hotspot/share/oops/markWord.hpp @@ -53,7 +53,8 @@ // [ptr | 00] locked ptr points to real header on stack (stack-locking in use) // [header | 00] locked locked regular object header (fast-locking in use) // [header | 01] unlocked regular object header -// [ptr | 10] monitor inflated lock (header is swapped out) +// [ptr | 10] monitor inflated lock (header is swapped out, UseObjectMonitorTable == false) +// [header | 10] monitor inflated lock (UseObjectMonitorTable == true) // [ptr | 11] marked used to mark an object // [0 ............ 0| 00] inflating inflation in progress (stack-locking in use) // diff --git a/src/hotspot/share/opto/c2compiler.cpp b/src/hotspot/share/opto/c2compiler.cpp index c5e174784773f..2f087858efd48 100644 --- a/src/hotspot/share/opto/c2compiler.cpp +++ b/src/hotspot/share/opto/c2compiler.cpp @@ -731,6 +731,8 @@ bool C2Compiler::is_intrinsic_supported(vmIntrinsics::ID id) { case vmIntrinsics::_setCurrentThread: case vmIntrinsics::_scopedValueCache: case vmIntrinsics::_setScopedValueCache: + case vmIntrinsics::_Continuation_pin: + case vmIntrinsics::_Continuation_unpin: #ifdef JFR_HAVE_INTRINSICS case vmIntrinsics::_counterTime: case vmIntrinsics::_getEventWriter: diff --git a/src/hotspot/share/opto/library_call.cpp b/src/hotspot/share/opto/library_call.cpp index eced285f8cbdf..24901855b91a1 100644 --- a/src/hotspot/share/opto/library_call.cpp +++ b/src/hotspot/share/opto/library_call.cpp @@ -482,6 +482,9 @@ bool LibraryCallKit::try_to_inline(int predicate) { case vmIntrinsics::_scopedValueCache: return inline_native_scopedValueCache(); case vmIntrinsics::_setScopedValueCache: return inline_native_setScopedValueCache(); + case vmIntrinsics::_Continuation_pin: return inline_native_Continuation_pinning(false); + case vmIntrinsics::_Continuation_unpin: return inline_native_Continuation_pinning(true); + #if INCLUDE_JVMTI case vmIntrinsics::_notifyJvmtiVThreadStart: return inline_native_notify_jvmti_funcs(CAST_FROM_FN_PTR(address, OptoRuntime::notify_jvmti_vthread_start()), "notifyJvmtiStart", true, false); @@ -3230,10 +3233,12 @@ bool LibraryCallKit::inline_native_jvm_commit() { * oop threadObj = Thread::threadObj(); * oop vthread = java_lang_Thread::vthread(threadObj); * traceid tid; + * bool pinVirtualThread; * bool excluded; * if (vthread != threadObj) { // i.e. current thread is virtual * tid = java_lang_Thread::tid(vthread); * u2 vthread_epoch_raw = java_lang_Thread::jfr_epoch(vthread); + * pinVirtualThread = VMContinuations; * excluded = vthread_epoch_raw & excluded_mask; * if (!excluded) { * traceid current_epoch = JfrTraceIdEpoch::current_generation(); @@ -3245,13 +3250,15 @@ bool LibraryCallKit::inline_native_jvm_commit() { * } else { * tid = java_lang_Thread::tid(threadObj); * u2 thread_epoch_raw = java_lang_Thread::jfr_epoch(threadObj); + * pinVirtualThread = false; * excluded = thread_epoch_raw & excluded_mask; * } * oop event_writer = JNIHandles::resolve_non_null(h_event_writer); * traceid tid_in_event_writer = getField(event_writer, "threadID"); * if (tid_in_event_writer != tid) { - * setField(event_writer, "threadID", tid); + * setField(event_writer, "pinVirtualThread", pinVirtualThread); * setField(event_writer, "excluded", excluded); + * setField(event_writer, "threadID", tid); * } * return event_writer */ @@ -3322,6 +3329,10 @@ bool LibraryCallKit::inline_native_getEventWriter() { // Load the tid field from the vthread object. Node* vthread_tid = load_field_from_object(vthread, "tid", "J"); + // Continuation support determines if a virtual thread should be pinned. + Node* global_addr = makecon(TypeRawPtr::make((address)&VMContinuations)); + Node* continuation_support = make_load(control(), global_addr, TypeInt::BOOL, T_BOOLEAN, MemNode::unordered); + // Load the raw epoch value from the vthread. Node* vthread_epoch_offset = basic_plus_adr(vthread, java_lang_Thread::jfr_epoch_offset()); Node* vthread_epoch_raw = access_load_at(vthread, vthread_epoch_offset, TypeRawPtr::BOTTOM, TypeInt::CHAR, T_CHAR, @@ -3412,6 +3423,8 @@ bool LibraryCallKit::inline_native_getEventWriter() { record_for_igvn(tid); PhiNode* exclusion = new PhiNode(vthread_compare_rgn, TypeInt::BOOL); record_for_igvn(exclusion); + PhiNode* pinVirtualThread = new PhiNode(vthread_compare_rgn, TypeInt::BOOL); + record_for_igvn(pinVirtualThread); // Update control and phi nodes. vthread_compare_rgn->init_req(_true_path, _gvn.transform(exclude_compare_rgn)); @@ -3424,6 +3437,8 @@ bool LibraryCallKit::inline_native_getEventWriter() { tid->init_req(_false_path, _gvn.transform(thread_obj_tid)); exclusion->init_req(_true_path, _gvn.transform(vthread_is_excluded)); exclusion->init_req(_false_path, _gvn.transform(threadObj_is_excluded)); + pinVirtualThread->init_req(_true_path, _gvn.transform(continuation_support)); + pinVirtualThread->init_req(_false_path, _gvn.intcon(0)); // Update branch state. set_control(_gvn.transform(vthread_compare_rgn)); @@ -3447,6 +3462,9 @@ bool LibraryCallKit::inline_native_getEventWriter() { // Get the field offset to, conditionally, store an updated exclusion value later. Node* const event_writer_excluded_field = field_address_from_object(event_writer, "excluded", "Z", false); const TypePtr* event_writer_excluded_field_type = _gvn.type(event_writer_excluded_field)->isa_ptr(); + // Get the field offset to, conditionally, store an updated pinVirtualThread value later. + Node* const event_writer_pin_field = field_address_from_object(event_writer, "pinVirtualThread", "Z", false); + const TypePtr* event_writer_pin_field_type = _gvn.type(event_writer_pin_field)->isa_ptr(); RegionNode* event_writer_tid_compare_rgn = new RegionNode(PATH_LIMIT); record_for_igvn(event_writer_tid_compare_rgn); @@ -3467,6 +3485,9 @@ bool LibraryCallKit::inline_native_getEventWriter() { Node* tid_is_not_equal = _gvn.transform(new IfTrueNode(iff_tid_not_equal)); record_for_igvn(tid_is_not_equal); + // Store the pin state to the event writer. + store_to_memory(tid_is_not_equal, event_writer_pin_field, _gvn.transform(pinVirtualThread), T_BOOLEAN, event_writer_pin_field_type, MemNode::unordered); + // Store the exclusion state to the event writer. store_to_memory(tid_is_not_equal, event_writer_excluded_field, _gvn.transform(exclusion), T_BOOLEAN, event_writer_excluded_field_type, MemNode::unordered); @@ -3715,6 +3736,93 @@ bool LibraryCallKit::inline_native_setScopedValueCache() { return true; } +//------------------------inline_native_Continuation_pin and unpin----------- + +// Shared implementation routine for both pin and unpin. +bool LibraryCallKit::inline_native_Continuation_pinning(bool unpin) { + enum { _true_path = 1, _false_path = 2, PATH_LIMIT }; + + // Save input memory. + Node* input_memory_state = reset_memory(); + set_all_memory(input_memory_state); + + // TLS + Node* tls_ptr = _gvn.transform(new ThreadLocalNode()); + Node* last_continuation_offset = basic_plus_adr(top(), tls_ptr, in_bytes(JavaThread::cont_entry_offset())); + Node* last_continuation = make_load(control(), last_continuation_offset, last_continuation_offset->get_ptr_type(), T_ADDRESS, MemNode::unordered); + + // Null check the last continuation object. + Node* continuation_cmp_null = _gvn.transform(new CmpPNode(last_continuation, null())); + Node* test_continuation_not_equal_null = _gvn.transform(new BoolNode(continuation_cmp_null, BoolTest::ne)); + IfNode* iff_continuation_not_equal_null = create_and_map_if(control(), test_continuation_not_equal_null, PROB_MAX, COUNT_UNKNOWN); + + // False path, last continuation is null. + Node* continuation_is_null = _gvn.transform(new IfFalseNode(iff_continuation_not_equal_null)); + + // True path, last continuation is not null. + Node* continuation_is_not_null = _gvn.transform(new IfTrueNode(iff_continuation_not_equal_null)); + + set_control(continuation_is_not_null); + + // Load the pin count from the last continuation. + Node* pin_count_offset = basic_plus_adr(top(), last_continuation, in_bytes(ContinuationEntry::pin_count_offset())); + Node* pin_count = make_load(control(), pin_count_offset, TypeInt::INT, T_INT, MemNode::unordered); + + // The loaded pin count is compared against a context specific rhs for over/underflow detection. + Node* pin_count_rhs; + if (unpin) { + pin_count_rhs = _gvn.intcon(0); + } else { + pin_count_rhs = _gvn.intcon(UINT32_MAX); + } + Node* pin_count_cmp = _gvn.transform(new CmpUNode(_gvn.transform(pin_count), pin_count_rhs)); + Node* test_pin_count_over_underflow = _gvn.transform(new BoolNode(pin_count_cmp, BoolTest::eq)); + IfNode* iff_pin_count_over_underflow = create_and_map_if(control(), test_pin_count_over_underflow, PROB_MIN, COUNT_UNKNOWN); + + // False branch, no pin count over/underflow. Increment or decrement pin count and store back. + Node* valid_pin_count = _gvn.transform(new IfFalseNode(iff_pin_count_over_underflow)); + set_control(valid_pin_count); + + Node* next_pin_count; + if (unpin) { + next_pin_count = _gvn.transform(new SubINode(pin_count, _gvn.intcon(1))); + } else { + next_pin_count = _gvn.transform(new AddINode(pin_count, _gvn.intcon(1))); + } + + Node* updated_pin_count_memory = store_to_memory(control(), pin_count_offset, next_pin_count, T_INT, Compile::AliasIdxRaw, MemNode::unordered); + + // True branch, pin count over/underflow. + Node* pin_count_over_underflow = _gvn.transform(new IfTrueNode(iff_pin_count_over_underflow)); + { + // Trap (but not deoptimize (Action_none)) and continue in the interpreter + // which will throw IllegalStateException for pin count over/underflow. + PreserveJVMState pjvms(this); + set_control(pin_count_over_underflow); + set_all_memory(input_memory_state); + uncommon_trap_exact(Deoptimization::Reason_intrinsic, + Deoptimization::Action_none); + assert(stopped(), "invariant"); + } + + // Result of top level CFG and Memory. + RegionNode* result_rgn = new RegionNode(PATH_LIMIT); + record_for_igvn(result_rgn); + PhiNode* result_mem = new PhiNode(result_rgn, Type::MEMORY, TypePtr::BOTTOM); + record_for_igvn(result_mem); + + result_rgn->init_req(_true_path, _gvn.transform(valid_pin_count)); + result_rgn->init_req(_false_path, _gvn.transform(continuation_is_null)); + result_mem->init_req(_true_path, _gvn.transform(updated_pin_count_memory)); + result_mem->init_req(_false_path, _gvn.transform(input_memory_state)); + + // Set output state. + set_control(_gvn.transform(result_rgn)); + set_all_memory(_gvn.transform(result_mem)); + + return true; +} + //---------------------------load_mirror_from_klass---------------------------- // Given a klass oop, load its java mirror (a java.lang.Class oop). Node* LibraryCallKit::load_mirror_from_klass(Node* klass) { diff --git a/src/hotspot/share/opto/library_call.hpp b/src/hotspot/share/opto/library_call.hpp index 313e8c39544c6..4ae9d0216e9fd 100644 --- a/src/hotspot/share/opto/library_call.hpp +++ b/src/hotspot/share/opto/library_call.hpp @@ -241,6 +241,7 @@ class LibraryCallKit : public GraphKit { const Type* scopedValueCache_type(); Node* scopedValueCache_helper(); bool inline_native_setScopedValueCache(); + bool inline_native_Continuation_pinning(bool unpin); bool inline_native_time_funcs(address method, const char* funcName); #if INCLUDE_JVMTI diff --git a/src/hotspot/share/opto/loopopts.cpp b/src/hotspot/share/opto/loopopts.cpp index fc6c1a34823e5..b838b15032f70 100644 --- a/src/hotspot/share/opto/loopopts.cpp +++ b/src/hotspot/share/opto/loopopts.cpp @@ -1069,7 +1069,7 @@ void PhaseIdealLoop::try_move_store_after_loop(Node* n) { #endif lca = place_outside_loop(lca, n_loop); assert(!n_loop->is_member(get_loop(lca)), "control must not be back in the loop"); - assert(get_loop(lca)->_nest < n_loop->_nest || lca->in(0)->is_NeverBranch(), "must not be moved into inner loop"); + assert(get_loop(lca)->_nest < n_loop->_nest || get_loop(lca)->_head->as_Loop()->is_in_infinite_subgraph(), "must not be moved into inner loop"); // Move store out of the loop _igvn.replace_node(hook, n->in(MemNode::Memory)); @@ -1272,9 +1272,7 @@ Node* PhaseIdealLoop::place_outside_loop(Node* useblock, IdealLoopTree* loop) co // Pick control right outside the loop for (;;) { Node* dom = idom(useblock); - if (loop->is_member(get_loop(dom)) || - // NeverBranch nodes are not assigned to the loop when constructed - (dom->is_NeverBranch() && loop->is_member(get_loop(dom->in(0))))) { + if (loop->is_member(get_loop(dom))) { break; } useblock = dom; diff --git a/src/hotspot/share/opto/memnode.cpp b/src/hotspot/share/opto/memnode.cpp index 83a15319555b2..623b1d2bf8542 100644 --- a/src/hotspot/share/opto/memnode.cpp +++ b/src/hotspot/share/opto/memnode.cpp @@ -1,5 +1,6 @@ /* * Copyright (c) 1997, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2024, Alibaba Group Holding Limited. 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 @@ -433,23 +434,31 @@ Node *MemNode::Ideal_common(PhaseGVN *phase, bool can_reshape) { // Used by MemNode::find_previous_store to prove that the // control input of a memory operation predates (dominates) // an allocation it wants to look past. -bool MemNode::all_controls_dominate(Node* dom, Node* sub) { - if (dom == nullptr || dom->is_top() || sub == nullptr || sub->is_top()) - return false; // Conservative answer for dead code +// Returns 'DomResult::Dominate' if all control inputs of 'dom' +// dominate 'sub', 'DomResult::NotDominate' if not, +// and 'DomResult::EncounteredDeadCode' if we can't decide due to +// dead code, but at the end of IGVN, we know the definite result +// once the dead code is cleaned up. +Node::DomResult MemNode::maybe_all_controls_dominate(Node* dom, Node* sub) { + if (dom == nullptr || dom->is_top() || sub == nullptr || sub->is_top()) { + return DomResult::EncounteredDeadCode; // Conservative answer for dead code + } // Check 'dom'. Skip Proj and CatchProj nodes. dom = dom->find_exact_control(dom); - if (dom == nullptr || dom->is_top()) - return false; // Conservative answer for dead code + if (dom == nullptr || dom->is_top()) { + return DomResult::EncounteredDeadCode; // Conservative answer for dead code + } if (dom == sub) { // For the case when, for example, 'sub' is Initialize and the original // 'dom' is Proj node of the 'sub'. - return false; + return DomResult::NotDominate; } - if (dom->is_Con() || dom->is_Start() || dom->is_Root() || dom == sub) - return true; + if (dom->is_Con() || dom->is_Start() || dom->is_Root() || dom == sub) { + return DomResult::Dominate; + } // 'dom' dominates 'sub' if its control edge and control edges // of all its inputs dominate or equal to sub's control edge. @@ -463,16 +472,19 @@ bool MemNode::all_controls_dominate(Node* dom, Node* sub) { // Get control edge of 'sub'. Node* orig_sub = sub; sub = sub->find_exact_control(sub->in(0)); - if (sub == nullptr || sub->is_top()) - return false; // Conservative answer for dead code + if (sub == nullptr || sub->is_top()) { + return DomResult::EncounteredDeadCode; // Conservative answer for dead code + } assert(sub->is_CFG(), "expecting control"); - if (sub == dom) - return true; + if (sub == dom) { + return DomResult::Dominate; + } - if (sub->is_Start() || sub->is_Root()) - return false; + if (sub->is_Start() || sub->is_Root()) { + return DomResult::NotDominate; + } { // Check all control edges of 'dom'. @@ -486,41 +498,47 @@ bool MemNode::all_controls_dominate(Node* dom, Node* sub) { for (uint next = 0; next < dom_list.size(); next++) { Node* n = dom_list.at(next); - if (n == orig_sub) - return false; // One of dom's inputs dominated by sub. + if (n == orig_sub) { + return DomResult::NotDominate; // One of dom's inputs dominated by sub. + } if (!n->is_CFG() && n->pinned()) { // Check only own control edge for pinned non-control nodes. n = n->find_exact_control(n->in(0)); - if (n == nullptr || n->is_top()) - return false; // Conservative answer for dead code + if (n == nullptr || n->is_top()) { + return DomResult::EncounteredDeadCode; // Conservative answer for dead code + } assert(n->is_CFG(), "expecting control"); dom_list.push(n); } else if (n->is_Con() || n->is_Start() || n->is_Root()) { only_dominating_controls = true; } else if (n->is_CFG()) { - if (n->dominates(sub, nlist)) + DomResult dom_result = n->dominates(sub, nlist); + if (dom_result == DomResult::Dominate) { only_dominating_controls = true; - else - return false; + } else { + return dom_result; + } } else { // First, own control edge. Node* m = n->find_exact_control(n->in(0)); if (m != nullptr) { - if (m->is_top()) - return false; // Conservative answer for dead code + if (m->is_top()) { + return DomResult::EncounteredDeadCode; // Conservative answer for dead code + } dom_list.push(m); } // Now, the rest of edges. uint cnt = n->req(); for (uint i = 1; i < cnt; i++) { m = n->find_exact_control(n->in(i)); - if (m == nullptr || m->is_top()) + if (m == nullptr || m->is_top()) { continue; + } dom_list.push(m); } } } - return only_dominating_controls; + return only_dominating_controls ? DomResult::Dominate : DomResult::NotDominate; } } @@ -732,16 +750,18 @@ Node* MemNode::find_previous_store(PhaseValues* phase) { } else if (mem->is_Proj() && mem->in(0)->is_Initialize()) { InitializeNode* st_init = mem->in(0)->as_Initialize(); AllocateNode* st_alloc = st_init->allocation(); - if (st_alloc == nullptr) + if (st_alloc == nullptr) { break; // something degenerated + } bool known_identical = false; bool known_independent = false; - if (alloc == st_alloc) + if (alloc == st_alloc) { known_identical = true; - else if (alloc != nullptr) + } else if (alloc != nullptr) { known_independent = true; - else if (all_controls_dominate(this, st_alloc)) + } else if (all_controls_dominate(this, st_alloc)) { known_independent = true; + } if (known_independent) { // The bases are provably independent: Either they are @@ -1572,8 +1592,9 @@ bool LoadNode::can_split_through_phi_base(PhaseGVN* phase) { } if (!mem->is_Phi()) { - if (!MemNode::all_controls_dominate(mem, base->in(0))) + if (!MemNode::all_controls_dominate(mem, base->in(0))) { return false; + } } else if (base->in(0) != mem->in(0)) { if (!MemNode::all_controls_dominate(mem, base->in(0))) { return false; @@ -1664,35 +1685,49 @@ Node* LoadNode::split_through_phi(PhaseGVN* phase, bool ignore_missing_instance_ // Select Region to split through. Node* region; + DomResult dom_result = DomResult::Dominate; if (!base_is_phi) { assert(mem->is_Phi(), "sanity"); region = mem->in(0); // Skip if the region dominates some control edge of the address. - if (!MemNode::all_controls_dominate(address, region)) - return nullptr; + // We will check `dom_result` later. + dom_result = MemNode::maybe_all_controls_dominate(address, region); } else if (!mem->is_Phi()) { assert(base_is_phi, "sanity"); region = base->in(0); // Skip if the region dominates some control edge of the memory. - if (!MemNode::all_controls_dominate(mem, region)) - return nullptr; + // We will check `dom_result` later. + dom_result = MemNode::maybe_all_controls_dominate(mem, region); } else if (base->in(0) != mem->in(0)) { assert(base_is_phi && mem->is_Phi(), "sanity"); - if (MemNode::all_controls_dominate(mem, base->in(0))) { + dom_result = MemNode::maybe_all_controls_dominate(mem, base->in(0)); + if (dom_result == DomResult::Dominate) { region = base->in(0); - } else if (MemNode::all_controls_dominate(address, mem->in(0))) { - region = mem->in(0); } else { - return nullptr; // complex graph + dom_result = MemNode::maybe_all_controls_dominate(address, mem->in(0)); + if (dom_result == DomResult::Dominate) { + region = mem->in(0); + } + // Otherwise we encountered a complex graph. } } else { assert(base->in(0) == mem->in(0), "sanity"); region = mem->in(0); } + PhaseIterGVN* igvn = phase->is_IterGVN(); + if (dom_result != DomResult::Dominate) { + if (dom_result == DomResult::EncounteredDeadCode) { + // There is some dead code which eventually will be removed in IGVN. + // Once this is the case, we get an unambiguous dominance result. + // Push the node to the worklist again until the dead code is removed. + igvn->_worklist.push(this); + } + return nullptr; + } + Node* phi = nullptr; const Type* this_type = this->bottom_type(); - PhaseIterGVN* igvn = phase->is_IterGVN(); if (t_oop != nullptr && (t_oop->is_known_instance_field() || load_boxed_values)) { int this_index = C->get_alias_index(t_oop); int this_offset = t_oop->offset(); @@ -4578,8 +4613,9 @@ bool InitializeNode::detect_init_independence(Node* value, PhaseGVN* phase) { // must have preceded the init, or else be equal to the init. // Even after loop optimizations (which might change control edges) // a store is never pinned *before* the availability of its inputs. - if (!MemNode::all_controls_dominate(n, this)) + if (!MemNode::all_controls_dominate(n, this)) { return false; // failed to prove a good control + } } // Check data edges for possible dependencies on 'this'. diff --git a/src/hotspot/share/opto/memnode.hpp b/src/hotspot/share/opto/memnode.hpp index 1a8f01b4069cb..4bfa90977135d 100644 --- a/src/hotspot/share/opto/memnode.hpp +++ b/src/hotspot/share/opto/memnode.hpp @@ -1,5 +1,6 @@ /* * Copyright (c) 1997, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2024, Alibaba Group Holding Limited. 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 @@ -111,8 +112,12 @@ class MemNode : public Node { static Node *optimize_simple_memory_chain(Node *mchain, const TypeOopPtr *t_oop, Node *load, PhaseGVN *phase); static Node *optimize_memory_chain(Node *mchain, const TypePtr *t_adr, Node *load, PhaseGVN *phase); - // This one should probably be a phase-specific function: - static bool all_controls_dominate(Node* dom, Node* sub); + // The following two should probably be phase-specific functions: + static DomResult maybe_all_controls_dominate(Node* dom, Node* sub); + static bool all_controls_dominate(Node* dom, Node* sub) { + DomResult dom_result = maybe_all_controls_dominate(dom, sub); + return dom_result == DomResult::Dominate; + } virtual const class TypePtr *adr_type() const; // returns bottom_type of address diff --git a/src/hotspot/share/opto/node.cpp b/src/hotspot/share/opto/node.cpp index f36770e67ea6c..2e586de33a3d8 100644 --- a/src/hotspot/share/opto/node.cpp +++ b/src/hotspot/share/opto/node.cpp @@ -1,5 +1,6 @@ /* * Copyright (c) 1997, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2024, Alibaba Group Holding Limited. 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 @@ -1249,7 +1250,7 @@ Node* Node::find_exact_control(Node* ctrl) { // We already know that if any path back to Root or Start reaches 'this', // then all paths so, so this is a simple search for one example, // not an exhaustive search for a counterexample. -bool Node::dominates(Node* sub, Node_List &nlist) { +Node::DomResult Node::dominates(Node* sub, Node_List &nlist) { assert(this->is_CFG(), "expecting control"); assert(sub != nullptr && sub->is_CFG(), "expecting control"); @@ -1269,12 +1270,15 @@ bool Node::dominates(Node* sub, Node_List &nlist) { // will either exit through the loop head, or give up. // (If we get confused, break out and return a conservative 'false'.) while (sub != nullptr) { - if (sub->is_top()) break; // Conservative answer for dead code. + if (sub->is_top()) { + // Conservative answer for dead code. + return DomResult::EncounteredDeadCode; + } if (sub == dom) { if (nlist.size() == 0) { // No Region nodes except loops were visited before and the EntryControl // path was taken for loops: it did not walk in a cycle. - return true; + return DomResult::Dominate; } else if (met_dom) { break; // already met before: walk in a cycle } else { @@ -1288,7 +1292,7 @@ bool Node::dominates(Node* sub, Node_List &nlist) { // Success if we met 'dom' along a path to Start or Root. // We assume there are no alternative paths that avoid 'dom'. // (This assumption is up to the caller to ensure!) - return met_dom; + return met_dom ? DomResult::Dominate : DomResult::NotDominate; } Node* up = sub->in(0); // Normalize simple pass-through regions and projections: @@ -1319,7 +1323,7 @@ bool Node::dominates(Node* sub, Node_List &nlist) { if (visited == sub) { if (visited_twice_already) { // Visited 2 paths, but still stuck in loop body. Give up. - return false; + return DomResult::NotDominate; } // The Region node was visited before only once. // (We will repush with the low bit set, below.) @@ -1362,8 +1366,7 @@ bool Node::dominates(Node* sub, Node_List &nlist) { } // Did not meet Root or Start node in pred. chain. - // Conservative answer for dead code. - return false; + return DomResult::NotDominate; } //------------------------------remove_dead_region----------------------------- diff --git a/src/hotspot/share/opto/node.hpp b/src/hotspot/share/opto/node.hpp index 3e39e1ed2fbfb..bc5842866a186 100644 --- a/src/hotspot/share/opto/node.hpp +++ b/src/hotspot/share/opto/node.hpp @@ -1,5 +1,6 @@ /* * Copyright (c) 1997, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2024, Alibaba Group Holding Limited. 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 @@ -1107,8 +1108,14 @@ class Node { // Skip Proj and CatchProj nodes chains. Check for Null and Top. Node* find_exact_control(Node* ctrl); + // Results of the dominance analysis. + enum class DomResult { + NotDominate, // 'this' node does not dominate 'sub'. + Dominate, // 'this' node dominates or is equal to 'sub'. + EncounteredDeadCode // Result is undefined due to encountering dead code. + }; // Check if 'this' node dominates or equal to 'sub'. - bool dominates(Node* sub, Node_List &nlist); + DomResult dominates(Node* sub, Node_List &nlist); protected: bool remove_dead_region(PhaseGVN *phase, bool can_reshape); diff --git a/src/hotspot/share/opto/subnode.cpp b/src/hotspot/share/opto/subnode.cpp index 7eb7922c5fbd8..445eb16821443 100644 --- a/src/hotspot/share/opto/subnode.cpp +++ b/src/hotspot/share/opto/subnode.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 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 @@ -1623,25 +1623,8 @@ Node *BoolNode::Ideal(PhaseGVN *phase, bool can_reshape) { return new BoolNode( ncmp, _test.negate() ); } - // Change ((x & m) u<= m) or ((m & x) u<= m) to always true - // Same with ((x & m) u< m+1) and ((m & x) u< m+1) - if (cop == Op_CmpU && - cmp1_op == Op_AndI) { - Node* bound = nullptr; - if (_test._test == BoolTest::le) { - bound = cmp2; - } else if (_test._test == BoolTest::lt && - cmp2->Opcode() == Op_AddI && - cmp2->in(2)->find_int_con(0) == 1) { - bound = cmp2->in(1); - } - if (cmp1->in(2) == bound || cmp1->in(1) == bound) { - return ConINode::make(1); - } - } - // Change ((x & (m - 1)) u< m) into (m > 0) - // This is the off-by-one variant of the above + // This is the off-by-one variant of ((x & m) u<= m) if (cop == Op_CmpU && _test._test == BoolTest::lt && cmp1_op == Op_AndI) { @@ -1827,9 +1810,39 @@ Node *BoolNode::Ideal(PhaseGVN *phase, bool can_reshape) { } //------------------------------Value------------------------------------------ +// Change ((x & m) u<= m) or ((m & x) u<= m) to always true +// Same with ((x & m) u< m+1) and ((m & x) u< m+1) +const Type* BoolNode::Value_cmpu_and_mask(PhaseValues* phase) const { + Node* cmp = in(1); + if (cmp != nullptr && cmp->Opcode() == Op_CmpU) { + Node* cmp1 = cmp->in(1); + Node* cmp2 = cmp->in(2); + + if (cmp1->Opcode() == Op_AndI) { + Node* bound = nullptr; + if (_test._test == BoolTest::le) { + bound = cmp2; + } else if (_test._test == BoolTest::lt && cmp2->Opcode() == Op_AddI && cmp2->in(2)->find_int_con(0) == 1) { + bound = cmp2->in(1); + } + + if (cmp1->in(2) == bound || cmp1->in(1) == bound) { + return TypeInt::ONE; + } + } + } + + return nullptr; +} + // Simplify a Bool (convert condition codes to boolean (1 or 0)) node, // based on local information. If the input is constant, do it. const Type* BoolNode::Value(PhaseGVN* phase) const { + const Type* t = Value_cmpu_and_mask(phase); + if (t != nullptr) { + return t; + } + return _test.cc2logical( phase->type( in(1) ) ); } diff --git a/src/hotspot/share/opto/subnode.hpp b/src/hotspot/share/opto/subnode.hpp index a0c052645c69c..6ceaa851739d8 100644 --- a/src/hotspot/share/opto/subnode.hpp +++ b/src/hotspot/share/opto/subnode.hpp @@ -347,6 +347,7 @@ class BoolNode : public Node { BoolNode* negate(PhaseGVN* phase); virtual int Opcode() const; virtual Node *Ideal(PhaseGVN *phase, bool can_reshape); + const Type* Value_cmpu_and_mask(PhaseValues* phase) const; virtual const Type* Value(PhaseGVN* phase) const; virtual const Type *bottom_type() const { return TypeInt::BOOL; } uint match_edge(uint idx) const { return 0; } diff --git a/src/hotspot/share/prims/nativeLookup.cpp b/src/hotspot/share/prims/nativeLookup.cpp index 78cf7481abfd0..368d5eb264e1c 100644 --- a/src/hotspot/share/prims/nativeLookup.cpp +++ b/src/hotspot/share/prims/nativeLookup.cpp @@ -273,16 +273,22 @@ address NativeLookup::lookup_style(const methodHandle& method, char* pure_name, // Otherwise call static method findNative in ClassLoader Klass* klass = vmClasses::ClassLoader_klass(); - Handle name_arg = java_lang_String::create_from_str(jni_name, CHECK_NULL); + Handle jni_class(THREAD, method->method_holder()->java_mirror()); + Handle jni_name_arg = java_lang_String::create_from_str(jni_name, CHECK_NULL); + Handle java_name_arg = java_lang_String::create_from_str(method->name()->as_C_string(), CHECK_NULL); + + JavaCallArguments args; + args.push_oop(loader); + args.push_oop(jni_class); + args.push_oop(jni_name_arg); + args.push_oop(java_name_arg); JavaValue result(T_LONG); JavaCalls::call_static(&result, klass, vmSymbols::findNative_name(), - vmSymbols::classloader_string_long_signature(), - // Arguments - loader, - name_arg, + vmSymbols::classloader_class_string_string_long_signature(), + &args, CHECK_NULL); entry = (address) (intptr_t) result.get_jlong(); @@ -409,6 +415,14 @@ address NativeLookup::lookup_base(const methodHandle& method, TRAPS) { entry = lookup_entry_prefixed(method, CHECK_NULL); if (entry != nullptr) return entry; + if (THREAD->has_pending_exception()) { + oop exception = THREAD->pending_exception(); + if (exception->is_a(vmClasses::IllegalCallerException_klass())) { + // we already have a pending exception from the restricted method check, just return + return nullptr; + } + } + // Native function not found, throw UnsatisfiedLinkError stringStream ss; ss.print("'"); diff --git a/src/hotspot/share/prims/whitebox.cpp b/src/hotspot/share/prims/whitebox.cpp index 544eeabb5c212..8a08a12a0b0e2 100644 --- a/src/hotspot/share/prims/whitebox.cpp +++ b/src/hotspot/share/prims/whitebox.cpp @@ -2582,7 +2582,7 @@ WB_ENTRY(void, WB_VerifyFrames(JNIEnv* env, jobject wb, jboolean log, jboolean u for (StackFrameStream fst(JavaThread::current(), update_map, true); !fst.is_done(); fst.next()) { frame* current_frame = fst.current(); if (log) { - current_frame->print_value_on(&st, nullptr); + current_frame->print_value_on(&st); } current_frame->verify(fst.register_map()); } diff --git a/src/hotspot/share/runtime/arguments.cpp b/src/hotspot/share/runtime/arguments.cpp index 66513e297c392..ed3c7645db646 100644 --- a/src/hotspot/share/runtime/arguments.cpp +++ b/src/hotspot/share/runtime/arguments.cpp @@ -311,6 +311,8 @@ bool needs_module_property_warning = false; #define UPGRADE_PATH_LEN 12 #define ENABLE_NATIVE_ACCESS "enable.native.access" #define ENABLE_NATIVE_ACCESS_LEN 20 +#define ILLEGAL_NATIVE_ACCESS "illegal.native.access" +#define ILLEGAL_NATIVE_ACCESS_LEN 21 // Return TRUE if option matches 'property', or 'property=', or 'property.'. static bool matches_property_suffix(const char* option, const char* property, size_t len) { @@ -332,6 +334,7 @@ bool Arguments::is_internal_module_property(const char* property) { matches_property_suffix(property_suffix, LIMITMODS, LIMITMODS_LEN) || matches_property_suffix(property_suffix, PATH, PATH_LEN) || matches_property_suffix(property_suffix, UPGRADE_PATH, UPGRADE_PATH_LEN) || + matches_property_suffix(property_suffix, ILLEGAL_NATIVE_ACCESS, ILLEGAL_NATIVE_ACCESS_LEN) || matches_property_suffix(property_suffix, ENABLE_NATIVE_ACCESS, ENABLE_NATIVE_ACCESS_LEN)) { return true; } @@ -509,6 +512,9 @@ static SpecialFlag const special_jvm_flags[] = { { "RequireSharedSpaces", JDK_Version::jdk(18), JDK_Version::jdk(19), JDK_Version::undefined() }, { "UseSharedSpaces", JDK_Version::jdk(18), JDK_Version::jdk(19), JDK_Version::undefined() }, { "DontYieldALot", JDK_Version::jdk(23), JDK_Version::jdk(24), JDK_Version::jdk(25) }, +#ifdef LINUX + { "UseLinuxPosixThreadCPUClocks", JDK_Version::jdk(24), JDK_Version::jdk(25), JDK_Version::jdk(26) }, +#endif { "LockingMode", JDK_Version::jdk(24), JDK_Version::jdk(26), JDK_Version::jdk(27) }, // --- Deprecated alias flags (see also aliased_jvm_flags) - sorted by obsolete_in then expired_in: { "CreateMinidumpOnCrash", JDK_Version::jdk(9), JDK_Version::undefined(), JDK_Version::undefined() }, @@ -2249,6 +2255,10 @@ jint Arguments::parse_each_vm_init_arg(const JavaVMInitArgs* args, bool* patch_m if (!create_numbered_module_property("jdk.module.enable.native.access", tail, enable_native_access_count++)) { return JNI_ENOMEM; } + } else if (match_option(option, "--illegal-native-access=", &tail)) { + if (!create_module_property("jdk.module.illegal.native.access", tail, InternalProperty)) { + return JNI_ENOMEM; + } } else if (match_option(option, "--limit-modules=", &tail)) { if (!create_module_property("jdk.module.limitmods", tail, InternalProperty)) { return JNI_ENOMEM; diff --git a/src/hotspot/share/runtime/continuationEntry.hpp b/src/hotspot/share/runtime/continuationEntry.hpp index 5930b008d2771..ac76cd6f0882d 100644 --- a/src/hotspot/share/runtime/continuationEntry.hpp +++ b/src/hotspot/share/runtime/continuationEntry.hpp @@ -39,6 +39,7 @@ class RegisterMap; // Metadata stored in the continuation entry frame class ContinuationEntry { + friend class JVMCIVMStructs; ContinuationEntryPD _pd; #ifdef ASSERT private: @@ -78,7 +79,7 @@ class ContinuationEntry { #else int32_t _parent_held_monitor_count; #endif - uint _pin_count; + uint32_t _pin_count; public: static ByteSize parent_offset() { return byte_offset_of(ContinuationEntry, _parent); } @@ -108,7 +109,7 @@ class ContinuationEntry { bool is_pinned() { return _pin_count > 0; } bool pin() { - if (_pin_count == UINT_MAX) return false; + if (_pin_count == UINT32_MAX) return false; _pin_count++; return true; } diff --git a/src/hotspot/share/runtime/continuationFreezeThaw.cpp b/src/hotspot/share/runtime/continuationFreezeThaw.cpp index 23540e475d4eb..6a0ab7344c40c 100644 --- a/src/hotspot/share/runtime/continuationFreezeThaw.cpp +++ b/src/hotspot/share/runtime/continuationFreezeThaw.cpp @@ -883,7 +883,7 @@ inline void FreezeBase::before_freeze_java_frame(const frame& f, const frame& ca LogStream ls(lt); ls.print_cr("======== FREEZING FRAME interpreted: %d bottom: %d", f.is_interpreted_frame(), is_bottom_frame); ls.print_cr("fsize: %d argsize: %d", fsize, argsize); - f.print_value_on(&ls, nullptr); + f.print_value_on(&ls); } assert(caller.is_interpreted_frame() == Interpreter::contains(caller.pc()), ""); } @@ -892,7 +892,7 @@ inline void FreezeBase::after_freeze_java_frame(const frame& hf, bool is_bottom_ LogTarget(Trace, continuations) lt; if (lt.develop_is_enabled()) { LogStream ls(lt); - DEBUG_ONLY(hf.print_value_on(&ls, nullptr);) + DEBUG_ONLY(hf.print_value_on(&ls);) assert(hf.is_heap_frame(), "should be"); DEBUG_ONLY(print_frame_layout(hf, false, &ls);) if (is_bottom_frame) { @@ -2033,7 +2033,7 @@ NOINLINE intptr_t* ThawBase::thaw_slow(stackChunkOop chunk, bool return_barrier) LogStream ls(lt); ls.print_cr("top hframe before (thaw):"); assert(heap_frame.is_heap_frame(), "should have created a relative frame"); - heap_frame.print_value_on(&ls, nullptr); + heap_frame.print_value_on(&ls); } #if INCLUDE_ZGC || INCLUDE_SHENANDOAHGC @@ -2130,7 +2130,7 @@ inline void ThawBase::before_thaw_java_frame(const frame& hf, const frame& calle LogStream ls(lt); ls.print_cr("======== THAWING FRAME: %d", num_frame); assert(hf.is_heap_frame(), "should be"); - hf.print_value_on(&ls, nullptr); + hf.print_value_on(&ls); } assert(bottom == _cont.is_entry_frame(caller), "bottom: %d is_entry_frame: %d", bottom, _cont.is_entry_frame(hf)); } @@ -2400,7 +2400,7 @@ void ThawBase::finish_thaw(frame& f) { if (lt.develop_is_enabled()) { LogStream ls(lt); ls.print_cr("top hframe after (thaw):"); - _cont.last_frame().print_value_on(&ls, nullptr); + _cont.last_frame().print_value_on(&ls); } } @@ -2412,7 +2412,7 @@ void ThawBase::push_return_frame(frame& f) { // see generate_cont_thaw if (lt.develop_is_enabled()) { LogStream ls(lt); ls.print_cr("push_return_frame"); - f.print_value_on(&ls, nullptr); + f.print_value_on(&ls); } assert(f.sp() - frame::metadata_words_at_bottom >= _top_stack_address, "overwrote past thawing space" @@ -2473,7 +2473,7 @@ static inline intptr_t* thaw_internal(JavaThread* thread, const Continuation::th if (lt.develop_is_enabled()) { LogStream ls(lt); ls.print_cr("Jumping to frame (thaw):"); - frame(sp).print_value_on(&ls, nullptr); + frame(sp).print_value_on(&ls); } #endif diff --git a/src/hotspot/share/runtime/frame.cpp b/src/hotspot/share/runtime/frame.cpp index 1aed46d58804f..e193271eff658 100644 --- a/src/hotspot/share/runtime/frame.cpp +++ b/src/hotspot/share/runtime/frame.cpp @@ -511,7 +511,7 @@ const char* frame::print_name() const { return "C"; } -void frame::print_value_on(outputStream* st, JavaThread *thread) const { +void frame::print_value_on(outputStream* st) const { NOT_PRODUCT(address begin = pc()-40;) NOT_PRODUCT(address end = nullptr;) @@ -550,7 +550,7 @@ void frame::print_value_on(outputStream* st, JavaThread *thread) const { } void frame::print_on(outputStream* st) const { - print_value_on(st,nullptr); + print_value_on(st); if (is_interpreted_frame()) { interpreter_frame_print_on(st); } diff --git a/src/hotspot/share/runtime/frame.hpp b/src/hotspot/share/runtime/frame.hpp index 468437a648464..1c57e3de4daa6 100644 --- a/src/hotspot/share/runtime/frame.hpp +++ b/src/hotspot/share/runtime/frame.hpp @@ -433,8 +433,8 @@ class frame { void describe_pd(FrameValues& values, int frame_no); public: - void print_value() const { print_value_on(tty,nullptr); } - void print_value_on(outputStream* st, JavaThread *thread) const; + void print_value() const { print_value_on(tty); } + void print_value_on(outputStream* st) const; void print_on(outputStream* st) const; void interpreter_frame_print_on(outputStream* st) const; void print_on_error(outputStream* st, char* buf, int buflen, bool verbose = false) const; diff --git a/src/hotspot/share/runtime/javaThread.cpp b/src/hotspot/share/runtime/javaThread.cpp index 0c00ef75c9216..416e79d584477 100644 --- a/src/hotspot/share/runtime/javaThread.cpp +++ b/src/hotspot/share/runtime/javaThread.cpp @@ -1906,7 +1906,7 @@ void JavaThread::trace_frames() { int frame_no = 1; for (StackFrameStream fst(this, true /* update */, true /* process_frames */); !fst.is_done(); fst.next()) { tty->print(" %d. ", frame_no++); - fst.current()->print_value_on(tty, this); + fst.current()->print_value_on(tty); tty->cr(); } } diff --git a/src/hotspot/share/runtime/vframe.cpp b/src/hotspot/share/runtime/vframe.cpp index 58eead692c6fb..d93b380ce92db 100644 --- a/src/hotspot/share/runtime/vframe.cpp +++ b/src/hotspot/share/runtime/vframe.cpp @@ -622,7 +622,7 @@ javaVFrame* vframeStreamCommon::asJavaVFrame() { #ifndef PRODUCT void vframe::print(outputStream* output) { - if (WizardMode) _fr.print_value_on(output, nullptr); + if (WizardMode) _fr.print_value_on(output); } void vframe::print_value(outputStream* output) const { @@ -737,7 +737,7 @@ void javaVFrame::print_activation(int index, outputStream* output) const { // ------------- externalVFrame -------------- void externalVFrame::print(outputStream* output) { - _fr.print_value_on(output, nullptr); + _fr.print_value_on(output); } void externalVFrame::print_value(outputStream* output) const { diff --git a/src/hotspot/share/utilities/events.cpp b/src/hotspot/share/utilities/events.cpp index b4d46d79ffa69..1185e349b53a5 100644 --- a/src/hotspot/share/utilities/events.cpp +++ b/src/hotspot/share/utilities/events.cpp @@ -151,7 +151,9 @@ void UnloadingEventLog::log(Thread* thread, InstanceKlass* ik) { ik->name()->print_value_on(&st); } -void ExceptionsEventLog::log(Thread* thread, Handle h_exception, const char* message, const char* file, int line) { +void ExceptionsEventLog::log(Thread* thread, Handle h_exception, + const char* message, const char* file, int line, + int message_length_limit) { if (!should_log()) return; double timestamp = fetch_timestamp(); @@ -163,8 +165,11 @@ void ExceptionsEventLog::log(Thread* thread, Handle h_exception, const char* mes _records[index].data.size()); st.print("Exception <"); h_exception->print_value_on(&st); - st.print("%s%s> (" PTR_FORMAT ") \n" + if (message != nullptr) { + int len = message_length_limit > 0 ? message_length_limit : (int)strlen(message); + st.print(": %.*s", len, message); + } + st.print("> (" PTR_FORMAT ") \n" "thrown [%s, line %d]", - message ? ": " : "", message ? message : "", p2i(h_exception()), file, line); } diff --git a/src/hotspot/share/utilities/events.hpp b/src/hotspot/share/utilities/events.hpp index 4470002a1e367..cbbed7232fb1e 100644 --- a/src/hotspot/share/utilities/events.hpp +++ b/src/hotspot/share/utilities/events.hpp @@ -207,7 +207,9 @@ class ExceptionsEventLog : public ExtendedStringEventLog { ExceptionsEventLog(const char* name, const char* short_name, int count = LogEventsBufferEntries) : ExtendedStringEventLog(name, short_name, count) {} - void log(Thread* thread, Handle h_exception, const char* message, const char* file, int line); + // Message length limit of zero means no limit. + void log(Thread* thread, Handle h_exception, const char* message, + const char* file, int line, int message_length_limit = 0); }; @@ -275,7 +277,7 @@ class Events : AllStatic { // Log exception related message static void log_exception(Thread* thread, const char* format, ...) ATTRIBUTE_PRINTF(2, 3); - static void log_exception(Thread* thread, Handle h_exception, const char* message, const char* file, int line); + static void log_exception(Thread* thread, Handle h_exception, const char* message, const char* file, int line, int message_length_limit = 0); static void log_redefinition(Thread* thread, const char* format, ...) ATTRIBUTE_PRINTF(2, 3); @@ -345,9 +347,11 @@ inline void Events::log_exception(Thread* thread, const char* format, ...) { } } -inline void Events::log_exception(Thread* thread, Handle h_exception, const char* message, const char* file, int line) { +inline void Events::log_exception(Thread* thread, Handle h_exception, + const char* message, const char* file, + int line, int message_length_limit) { if (LogEvents && _exceptions != nullptr) { - _exceptions->log(thread, h_exception, message, file, line); + _exceptions->log(thread, h_exception, message, file, line, message_length_limit); } } diff --git a/src/hotspot/share/utilities/exceptions.cpp b/src/hotspot/share/utilities/exceptions.cpp index 034444839ab50..f730b37b8fffa 100644 --- a/src/hotspot/share/utilities/exceptions.cpp +++ b/src/hotspot/share/utilities/exceptions.cpp @@ -183,7 +183,7 @@ void Exceptions::_throw(JavaThread* thread, const char* file, int line, Handle h thread->set_pending_exception(h_exception(), file, line); // vm log - Events::log_exception(thread, h_exception, message, file, line); + Events::log_exception(thread, h_exception, message, file, line, MAX_LEN); } diff --git a/src/java.base/share/classes/java/lang/ClassLoader.java b/src/java.base/share/classes/java/lang/ClassLoader.java index 665c7a2567027..5817c37d6f62b 100644 --- a/src/java.base/share/classes/java/lang/ClassLoader.java +++ b/src/java.base/share/classes/java/lang/ClassLoader.java @@ -2442,10 +2442,27 @@ static NativeLibrary loadLibrary(Class fromClass, String name) { " in java.library.path: " + StaticProperty.javaLibraryPath()); } - /* + /** * Invoked in the VM class linking code. + * @param loader the class loader used to look up the native library symbol + * @param clazz the class in which the native method is declared + * @param entryName the native method's mangled name (this is the name used for the native lookup) + * @param javaName the native method's declared name + */ + static long findNative(ClassLoader loader, Class clazz, String entryName, String javaName) { + long addr = findNativeInternal(loader, entryName); + if (addr != 0 && loader != null) { + Reflection.ensureNativeAccess(clazz, clazz, javaName, true); + } + return addr; + } + + /* + * This is also called by SymbolLookup::loaderLookup. In that case, we need + * to avoid a restricted check, as that check has already been performed when + * obtaining the lookup. */ - static long findNative(ClassLoader loader, String entryName) { + static long findNativeInternal(ClassLoader loader, String entryName) { if (loader == null) { return BootLoader.getNativeLibraries().find(entryName); } else { diff --git a/src/java.base/share/classes/java/lang/Module.java b/src/java.base/share/classes/java/lang/Module.java index d7a7081861834..e4cf4a3a6c370 100644 --- a/src/java.base/share/classes/java/lang/Module.java +++ b/src/java.base/share/classes/java/lang/Module.java @@ -62,7 +62,9 @@ import jdk.internal.loader.ClassLoaders; import jdk.internal.misc.CDS; import jdk.internal.misc.Unsafe; +import jdk.internal.misc.VM; import jdk.internal.module.ModuleBootstrap; +import jdk.internal.module.ModuleBootstrap.IllegalNativeAccess; import jdk.internal.module.ModuleLoaderMap; import jdk.internal.module.ServicesCatalog; import jdk.internal.module.Resources; @@ -300,26 +302,43 @@ private Module moduleForNativeAccess() { } // This is invoked from Reflection.ensureNativeAccess - void ensureNativeAccess(Class owner, String methodName, Class currentClass) { + void ensureNativeAccess(Class owner, String methodName, Class currentClass, boolean jni) { // The target module whose enableNativeAccess flag is ensured Module target = moduleForNativeAccess(); - if (!EnableNativeAccess.isNativeAccessEnabled(target)) { - if (ModuleBootstrap.hasEnableNativeAccessFlag()) { - throw new IllegalCallerException("Illegal native access from: " + this); + ModuleBootstrap.IllegalNativeAccess illegalNativeAccess = ModuleBootstrap.illegalNativeAccess(); + if (illegalNativeAccess != ModuleBootstrap.IllegalNativeAccess.ALLOW && + !EnableNativeAccess.isNativeAccessEnabled(target)) { + String mod = isNamed() ? "module " + getName() : "an unnamed module"; + if (currentClass != null) { + // try to extract location of the current class (e.g. jar or folder) + URL url = System.codeSource(currentClass); + if (url != null) { + mod += " (" + url + ")"; + } } - if (EnableNativeAccess.trySetEnableNativeAccess(target)) { + if (illegalNativeAccess == ModuleBootstrap.IllegalNativeAccess.DENY) { + throw new IllegalCallerException("Illegal native access from " + mod); + } else if (EnableNativeAccess.trySetEnableNativeAccess(target)) { // warn and set flag, so that only one warning is reported per module String cls = owner.getName(); String mtd = cls + "::" + methodName; - String mod = isNamed() ? "module " + getName() : "an unnamed module"; String modflag = isNamed() ? getName() : "ALL-UNNAMED"; String caller = currentClass != null ? currentClass.getName() : "code"; - System.err.printf(""" - WARNING: A restricted method in %s has been called - WARNING: %s has been called by %s in %s - WARNING: Use --enable-native-access=%s to avoid a warning for callers in this module - WARNING: Restricted methods will be blocked in a future release unless native access is enabled - %n""", cls, mtd, caller, mod, modflag); + if (jni) { + VM.initialErr().printf(""" + WARNING: A native method in %s has been bound + WARNING: %s is declared in %s + WARNING: Use --enable-native-access=%s to avoid a warning for native methods declared in this module + WARNING: Restricted methods will be blocked in a future release unless native access is enabled + %n""", cls, mtd, mod, modflag); + } else { + VM.initialErr().printf(""" + WARNING: A restricted method in %s has been called + WARNING: %s has been called by %s in %s + WARNING: Use --enable-native-access=%s to avoid a warning for callers in this module + WARNING: Restricted methods will be blocked in a future release unless native access is enabled + %n""", cls, mtd, caller, mod, modflag); + } } } } diff --git a/src/java.base/share/classes/java/lang/ModuleLayer.java b/src/java.base/share/classes/java/lang/ModuleLayer.java index 3a13982c9b93c..80d392470cb33 100644 --- a/src/java.base/share/classes/java/lang/ModuleLayer.java +++ b/src/java.base/share/classes/java/lang/ModuleLayer.java @@ -323,7 +323,7 @@ public Controller addOpens(Module source, String pn, Module target) { public Controller enableNativeAccess(Module target) { ensureInLayer(target); Reflection.ensureNativeAccess(Reflection.getCallerClass(), Module.class, - "enableNativeAccess"); + "enableNativeAccess", false); target.implAddEnableNativeAccess(); return this; } diff --git a/src/java.base/share/classes/java/lang/Runtime.java b/src/java.base/share/classes/java/lang/Runtime.java index e77bf4c41e36c..19cbfa42e0035 100644 --- a/src/java.base/share/classes/java/lang/Runtime.java +++ b/src/java.base/share/classes/java/lang/Runtime.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1995, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1995, 2024, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2019, Azul Systems, Inc. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -36,6 +36,7 @@ import java.util.StringTokenizer; import jdk.internal.access.SharedSecrets; +import jdk.internal.javac.Restricted; import jdk.internal.reflect.CallerSensitive; import jdk.internal.reflect.Reflection; @@ -828,14 +829,19 @@ public void runFinalization() { * a native library image by the host system. * @throws NullPointerException if {@code filename} is * {@code null} + * @throws IllegalCallerException if the caller is in a module that + * does not have native access enabled. * @spec jni/index.html Java Native Interface Specification * @see java.lang.Runtime#getRuntime() * @see java.lang.SecurityException * @see java.lang.SecurityManager#checkLink(java.lang.String) */ @CallerSensitive + @Restricted public void load(String filename) { - load0(Reflection.getCallerClass(), filename); + Class caller = Reflection.getCallerClass(); + Reflection.ensureNativeAccess(caller, Runtime.class, "load", false); + load0(caller, filename); } void load0(Class fromClass, String filename) { @@ -894,13 +900,18 @@ void load0(Class fromClass, String filename) { * native library image by the host system. * @throws NullPointerException if {@code libname} is * {@code null} + * @throws IllegalCallerException if the caller is in a module that + * does not have native access enabled. * @spec jni/index.html Java Native Interface Specification * @see java.lang.SecurityException * @see java.lang.SecurityManager#checkLink(java.lang.String) */ @CallerSensitive + @Restricted public void loadLibrary(String libname) { - loadLibrary0(Reflection.getCallerClass(), libname); + Class caller = Reflection.getCallerClass(); + Reflection.ensureNativeAccess(caller, Runtime.class, "loadLibrary", false); + loadLibrary0(caller, libname); } void loadLibrary0(Class fromClass, String libname) { diff --git a/src/java.base/share/classes/java/lang/System.java b/src/java.base/share/classes/java/lang/System.java index 5ff4796505b58..503167bc2dd0d 100644 --- a/src/java.base/share/classes/java/lang/System.java +++ b/src/java.base/share/classes/java/lang/System.java @@ -69,6 +69,7 @@ import java.util.concurrent.ConcurrentHashMap; import java.util.stream.Stream; +import jdk.internal.javac.Restricted; import jdk.internal.logger.LoggerFinderLoader.TemporaryLoggerFinder; import jdk.internal.misc.Blocker; import jdk.internal.misc.CarrierThreadLocal; @@ -355,7 +356,7 @@ private static class CallersHolder { = Collections.synchronizedMap(new WeakHashMap<>()); } - private static URL codeSource(Class clazz) { + static URL codeSource(Class clazz) { PrivilegedAction pa = clazz::getProtectionDomain; @SuppressWarnings("removal") CodeSource cs = AccessController.doPrivileged(pa).getCodeSource(); @@ -2017,14 +2018,19 @@ public static void runFinalization() { * linked with the VM, or the library cannot be mapped to * a native library image by the host system. * @throws NullPointerException if {@code filename} is {@code null} + * @throws IllegalCallerException if the caller is in a module that + * does not have native access enabled. * * @spec jni/index.html Java Native Interface Specification * @see java.lang.Runtime#load(java.lang.String) * @see java.lang.SecurityManager#checkLink(java.lang.String) */ @CallerSensitive + @Restricted public static void load(String filename) { - Runtime.getRuntime().load0(Reflection.getCallerClass(), filename); + Class caller = Reflection.getCallerClass(); + Reflection.ensureNativeAccess(caller, System.class, "load", false); + Runtime.getRuntime().load0(caller, filename); } /** @@ -2055,14 +2061,19 @@ public static void load(String filename) { * linked with the VM, or the library cannot be mapped to a * native library image by the host system. * @throws NullPointerException if {@code libname} is {@code null} + * @throws IllegalCallerException if the caller is in a module that + * does not have native access enabled. * * @spec jni/index.html Java Native Interface Specification * @see java.lang.Runtime#loadLibrary(java.lang.String) * @see java.lang.SecurityManager#checkLink(java.lang.String) */ @CallerSensitive + @Restricted public static void loadLibrary(String libname) { - Runtime.getRuntime().loadLibrary0(Reflection.getCallerClass(), libname); + Class caller = Reflection.getCallerClass(); + Reflection.ensureNativeAccess(caller, System.class, "loadLibrary", false); + Runtime.getRuntime().loadLibrary0(caller, libname); } /** @@ -2539,8 +2550,8 @@ public boolean addEnableNativeAccess(ModuleLayer layer, String name) { public void addEnableNativeAccessToAllUnnamed() { Module.implAddEnableNativeAccessToAllUnnamed(); } - public void ensureNativeAccess(Module m, Class owner, String methodName, Class currentClass) { - m.ensureNativeAccess(owner, methodName, currentClass); + public void ensureNativeAccess(Module m, Class owner, String methodName, Class currentClass, boolean jni) { + m.ensureNativeAccess(owner, methodName, currentClass, jni); } public ServicesCatalog getServicesCatalog(ModuleLayer layer) { return layer.getServicesCatalog(); @@ -2645,7 +2656,7 @@ public Object classData(Class c) { @Override public long findNative(ClassLoader loader, String entry) { - return ClassLoader.findNative(loader, entry); + return ClassLoader.findNativeInternal(loader, entry); } @Override diff --git a/src/java.base/share/classes/java/lang/classfile/AttributeMapper.java b/src/java.base/share/classes/java/lang/classfile/AttributeMapper.java index 0e7d625290e5c..0b46055423ae3 100644 --- a/src/java.base/share/classes/java/lang/classfile/AttributeMapper.java +++ b/src/java.base/share/classes/java/lang/classfile/AttributeMapper.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 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 @@ -40,7 +40,7 @@ * @since 22 */ @PreviewFeature(feature = PreviewFeature.Feature.CLASSFILE_API) -public interface AttributeMapper { +public interface AttributeMapper> { /** * Attribute stability indicator diff --git a/src/java.base/share/classes/java/lang/classfile/package-info.java b/src/java.base/share/classes/java/lang/classfile/package-info.java index 921cf9e1a3443..6e9ecfe4819e6 100644 --- a/src/java.base/share/classes/java/lang/classfile/package-info.java +++ b/src/java.base/share/classes/java/lang/classfile/package-info.java @@ -147,7 +147,7 @@ * ClassReader, int)} method for mapping from the classfile format * to an attribute instance, and the * {@link java.lang.classfile.AttributeMapper#writeAttribute(java.lang.classfile.BufWriter, - * java.lang.Object)} method for mapping back to the classfile format. It also + * java.lang.classfile.Attribute)} method for mapping back to the classfile format. It also * contains metadata including the attribute name, the set of classfile entities * where the attribute is applicable, and whether multiple attributes of the * same kind are allowed on a single entity. diff --git a/src/java.base/share/classes/java/lang/foreign/AddressLayout.java b/src/java.base/share/classes/java/lang/foreign/AddressLayout.java index 49cab25a75fb5..6e188c5a3171e 100644 --- a/src/java.base/share/classes/java/lang/foreign/AddressLayout.java +++ b/src/java.base/share/classes/java/lang/foreign/AddressLayout.java @@ -108,7 +108,7 @@ public sealed interface AddressLayout extends ValueLayout permits ValueLayouts.O * @param layout the target layout * @return an address layout with same characteristics as this layout, but with the * provided target layout - * @throws IllegalCallerException If the caller is in a module that does not have + * @throws IllegalCallerException if the caller is in a module that does not have * native access enabled * @see #targetLayout() */ diff --git a/src/java.base/share/classes/java/lang/foreign/Linker.java b/src/java.base/share/classes/java/lang/foreign/Linker.java index fd6e820d01662..5474fef66da13 100644 --- a/src/java.base/share/classes/java/lang/foreign/Linker.java +++ b/src/java.base/share/classes/java/lang/foreign/Linker.java @@ -613,7 +613,7 @@ static Linker nativeLinker() { * {@code address.equals(MemorySegment.NULL)} * @throws IllegalArgumentException if an invalid combination of linker options * is given - * @throws IllegalCallerException If the caller is in a module that does not have + * @throws IllegalCallerException if the caller is in a module that does not have * native access enabled * * @see SymbolLookup @@ -684,7 +684,7 @@ MethodHandle downcallHandle(MemorySegment address, * supported by this linker * @throws IllegalArgumentException if an invalid combination of linker options * is given - * @throws IllegalCallerException If the caller is in a module that does not have + * @throws IllegalCallerException if the caller is in a module that does not have * native access enabled */ @CallerSensitive @@ -733,7 +733,7 @@ MethodHandle downcallHandle(MemorySegment address, * @throws IllegalStateException if {@code arena.scope().isAlive() == false} * @throws WrongThreadException if {@code arena} is a confined arena, and this method * is called from a thread {@code T}, other than the arena's owner thread - * @throws IllegalCallerException If the caller is in a module that does not have + * @throws IllegalCallerException if the caller is in a module that does not have * native access enabled */ @CallerSensitive diff --git a/src/java.base/share/classes/java/lang/foreign/MemoryLayout.java b/src/java.base/share/classes/java/lang/foreign/MemoryLayout.java index 989fc134a2628..2cf0a5e4443cb 100644 --- a/src/java.base/share/classes/java/lang/foreign/MemoryLayout.java +++ b/src/java.base/share/classes/java/lang/foreign/MemoryLayout.java @@ -574,7 +574,9 @@ public sealed interface MemoryLayout *

* For any given dynamic argument {@code x_i}, it must be that {@code 0 <= x_i < size_i}, * where {@code size_i} is the size of the open path element associated with {@code x_i}. - * Otherwise, the returned method handle throws {@link IndexOutOfBoundsException}. + * Otherwise, the returned method handle throws {@link IndexOutOfBoundsException}. Moreover, + * the value of {@code b} must be such that the computation for {@code offset} does not overflow, + * or the returned method handle throws {@link ArithmeticException}. * * @apiNote The returned method handle can be used to compute a layout offset, * similarly to {@link #byteOffset(PathElement...)}, but more flexibly, as @@ -664,14 +666,15 @@ public sealed interface MemoryLayout *

* If the provided layout path has size {@code m} and contains a dereference path * element in position {@code k} (where {@code k <= m}) then two layout paths - * {@code P} and {@code P'} are derived, where P contains all the path elements from - * 0 to {@code k - 1} and {@code P'} contains all the path elements from {@code k + 1} - * to {@code m} (if any). Then, the returned var handle is computed as follows: + * {@code P} and {@code Q} are derived, where P contains all the path elements from + * 0 to {@code k - 1} and {@code Q} contains all the path elements from {@code k + 1} + * to {@code m} ({@code Q} could be an empty layout path if {@code k == m}). + * Then, the returned var handle is computed as follows: * * {@snippet lang = "java": * VarHandle baseHandle = this.varHandle(P); * MemoryLayout target = ((AddressLayout)this.select(P)).targetLayout().get(); - * VarHandle targetHandle = target.varHandle(P); + * VarHandle targetHandle = target.varHandle(Q); * targetHandle = MethodHandles.insertCoordinates(targetHandle, 1, 0L); // always access nested targets at offset 0 * targetHandle = MethodHandles.collectCoordinates(targetHandle, 0, * baseHandle.toMethodHandle(VarHandle.AccessMode.GET)); @@ -944,7 +947,7 @@ static PathElement sequenceElement(long index) { * is computed as follows: *

    *
  • if {@code F > 0}, then {@code B = ceilDiv(C - S, F)}
  • - *
  • if {@code F < 0}, then {@code B = ceilDiv(-(S + 1), -F)}
  • + *
  • if {@code F < 0}, then {@code B = ceilDiv(S + 1, -F)}
  • *
* That is, the size of the returned open path element is {@code B}. * @@ -972,8 +975,8 @@ static PathElement sequenceElement() { } /** - * {@return a path element that dereferences an address layout as its - * {@linkplain AddressLayout#targetLayout() target layout} (where set)} + * {@return a path element that selects the {@linkplain AddressLayout#targetLayout() target layout} of + * an address layout (where set)} */ static PathElement dereferenceElement() { return LayoutPath.DereferenceElement.instance(); diff --git a/src/java.base/share/classes/java/lang/foreign/MemorySegment.java b/src/java.base/share/classes/java/lang/foreign/MemorySegment.java index 82f6b358a0752..8f171fd8bfbc9 100644 --- a/src/java.base/share/classes/java/lang/foreign/MemorySegment.java +++ b/src/java.base/share/classes/java/lang/foreign/MemorySegment.java @@ -475,7 +475,7 @@ * MemorySegment ptr = null; * try (Arena arena = Arena.ofConfined()) { * MemorySegment z = segment.get(ValueLayout.ADDRESS, ...); // size = 0, scope = always alive - * ptr = z.reinterpret(16, arena, null); // size = 4, scope = arena.scope() + * ptr = z.reinterpret(16, arena, null); // size = 16, scope = arena.scope() * int x = ptr.getAtIndex(ValueLayout.JAVA_INT, 3); // ok * } * int x = ptr.getAtIndex(ValueLayout.JAVA_INT, 3); // throws IllegalStateException diff --git a/src/java.base/share/classes/java/lang/foreign/SymbolLookup.java b/src/java.base/share/classes/java/lang/foreign/SymbolLookup.java index a8838ea715c92..c6e4443b57007 100644 --- a/src/java.base/share/classes/java/lang/foreign/SymbolLookup.java +++ b/src/java.base/share/classes/java/lang/foreign/SymbolLookup.java @@ -285,14 +285,14 @@ static SymbolLookup loaderLookup() { * @throws WrongThreadException if {@code arena} is a confined arena, and this method * is called from a thread {@code T}, other than the arena's owner thread * @throws IllegalArgumentException if {@code name} does not identify a valid library - * @throws IllegalCallerException If the caller is in a module that does not have + * @throws IllegalCallerException if the caller is in a module that does not have * native access enabled */ @CallerSensitive @Restricted static SymbolLookup libraryLookup(String name, Arena arena) { Reflection.ensureNativeAccess(Reflection.getCallerClass(), - SymbolLookup.class, "libraryLookup"); + SymbolLookup.class, "libraryLookup", false); if (Utils.containsNullChars(name)) { throw new IllegalArgumentException("Cannot open library: " + name); } @@ -319,14 +319,14 @@ static SymbolLookup libraryLookup(String name, Arena arena) { * is called from a thread {@code T}, other than the arena's owner thread * @throws IllegalArgumentException if {@code path} does not point to a valid library * in the default file system - * @throws IllegalCallerException If the caller is in a module that does not have + * @throws IllegalCallerException if the caller is in a module that does not have * native access enabled */ @CallerSensitive @Restricted static SymbolLookup libraryLookup(Path path, Arena arena) { Reflection.ensureNativeAccess(Reflection.getCallerClass(), - SymbolLookup.class, "libraryLookup"); + SymbolLookup.class, "libraryLookup", false); if (path.getFileSystem() != FileSystems.getDefault()) { throw new IllegalArgumentException("Path not in default file system: " + path); } diff --git a/src/java.base/share/classes/java/lang/foreign/package-info.java b/src/java.base/share/classes/java/lang/foreign/package-info.java index 6594826e40524..1f31301638e05 100644 --- a/src/java.base/share/classes/java/lang/foreign/package-info.java +++ b/src/java.base/share/classes/java/lang/foreign/package-info.java @@ -165,10 +165,11 @@ * In the reference implementation, access to restricted methods can be granted to * specific modules using the command line option {@code --enable-native-access=M1,M2, ... Mn}, * where {@code M1}, {@code M2}, {@code ... Mn} are module names (for the unnamed module, - * the special value {@code ALL-UNNAMED} can be used). If this option is specified, - * access to restricted methods are only granted to the modules listed by that option. - * If this option is not specified, access to restricted methods is enabled for all - * modules, but access to restricted methods will result in runtime warnings. + * the special value {@code ALL-UNNAMED} can be used). Access to restricted methods + * from modules not listed by that option is deemed illegal. Clients can + * control how access to restricted methods is handled, using the command line + * option {@code --illegal-native-access}. If this option is not specified, + * illegal access to restricted methods will result in runtime warnings. * * @spec jni/index.html Java Native Interface Specification * diff --git a/src/java.base/share/classes/java/lang/invoke/StringConcatFactory.java b/src/java.base/share/classes/java/lang/invoke/StringConcatFactory.java index dd2621935749f..870d4c063ec2e 100644 --- a/src/java.base/share/classes/java/lang/invoke/StringConcatFactory.java +++ b/src/java.base/share/classes/java/lang/invoke/StringConcatFactory.java @@ -29,6 +29,8 @@ import jdk.internal.access.JavaLangAccess; import jdk.internal.access.SharedSecrets; import jdk.internal.constant.ConstantUtils; +import jdk.internal.constant.MethodTypeDescImpl; +import jdk.internal.constant.ReferenceClassDescImpl; import jdk.internal.misc.VM; import jdk.internal.util.ClassFileDumper; import jdk.internal.util.ReferenceKey; @@ -1085,32 +1087,32 @@ private static final class InlineHiddenClassStrategy { static final MethodHandles.Lookup STR_LOOKUP = new MethodHandles.Lookup(String.class); static final ClassDesc CD_CONCAT = ConstantUtils.binaryNameToDesc(CLASS_NAME); - static final ClassDesc CD_StringConcatHelper = ClassDesc.ofDescriptor("Ljava/lang/StringConcatHelper;"); - static final ClassDesc CD_StringConcatBase = ClassDesc.ofDescriptor("Ljava/lang/StringConcatHelper$StringConcatBase;"); - static final ClassDesc CD_Array_byte = ClassDesc.ofDescriptor("[B"); - static final ClassDesc CD_Array_String = ClassDesc.ofDescriptor("[Ljava/lang/String;"); - - static final MethodTypeDesc MTD_byte_char = MethodTypeDesc.of(CD_byte, CD_char); - static final MethodTypeDesc MTD_byte = MethodTypeDesc.of(CD_byte); - static final MethodTypeDesc MTD_int = MethodTypeDesc.of(CD_int); - static final MethodTypeDesc MTD_int_int_boolean = MethodTypeDesc.of(CD_int, CD_int, CD_boolean); - static final MethodTypeDesc MTD_int_int_char = MethodTypeDesc.of(CD_int, CD_int, CD_char); - static final MethodTypeDesc MTD_int_int_int = MethodTypeDesc.of(CD_int, CD_int, CD_int); - static final MethodTypeDesc MTD_int_int_long = MethodTypeDesc.of(CD_int, CD_int, CD_long); - static final MethodTypeDesc MTD_int_int_String = MethodTypeDesc.of(CD_int, CD_int, CD_String); - static final MethodTypeDesc MTD_String_float = MethodTypeDesc.of(CD_String, CD_float); - static final MethodTypeDesc MTD_String_double = MethodTypeDesc.of(CD_String, CD_double); - static final MethodTypeDesc MTD_String_Object = MethodTypeDesc.of(CD_String, CD_Object); - - static final MethodTypeDesc MTD_INIT = MethodTypeDesc.of(CD_void, CD_Array_String); - static final MethodTypeDesc MTD_NEW_ARRAY_SUFFIX = MethodTypeDesc.of(CD_Array_byte, CD_String, CD_int, CD_byte); - static final MethodTypeDesc MTD_STRING_INIT = MethodTypeDesc.of(CD_void, CD_Array_byte, CD_byte); - - static final MethodTypeDesc PREPEND_int = MethodTypeDesc.of(CD_int, CD_int, CD_byte, CD_Array_byte, CD_int, CD_String); - static final MethodTypeDesc PREPEND_long = MethodTypeDesc.of(CD_int, CD_int, CD_byte, CD_Array_byte, CD_long, CD_String); - static final MethodTypeDesc PREPEND_boolean = MethodTypeDesc.of(CD_int, CD_int, CD_byte, CD_Array_byte, CD_boolean, CD_String); - static final MethodTypeDesc PREPEND_char = MethodTypeDesc.of(CD_int, CD_int, CD_byte, CD_Array_byte, CD_char, CD_String); - static final MethodTypeDesc PREPEND_String = MethodTypeDesc.of(CD_int, CD_int, CD_byte, CD_Array_byte, CD_String, CD_String); + static final ClassDesc CD_StringConcatHelper = ReferenceClassDescImpl.ofValidated("Ljava/lang/StringConcatHelper;"); + static final ClassDesc CD_StringConcatBase = ReferenceClassDescImpl.ofValidated("Ljava/lang/StringConcatHelper$StringConcatBase;"); + static final ClassDesc CD_Array_byte = ReferenceClassDescImpl.ofValidated("[B"); + static final ClassDesc CD_Array_String = ReferenceClassDescImpl.ofValidated("[Ljava/lang/String;"); + + static final MethodTypeDesc MTD_byte_char = MethodTypeDescImpl.ofValidated(CD_byte, CD_char); + static final MethodTypeDesc MTD_byte = MethodTypeDescImpl.ofValidated(CD_byte); + static final MethodTypeDesc MTD_int = MethodTypeDescImpl.ofValidated(CD_int); + static final MethodTypeDesc MTD_int_int_boolean = MethodTypeDescImpl.ofValidated(CD_int, CD_int, CD_boolean); + static final MethodTypeDesc MTD_int_int_char = MethodTypeDescImpl.ofValidated(CD_int, CD_int, CD_char); + static final MethodTypeDesc MTD_int_int_int = MethodTypeDescImpl.ofValidated(CD_int, CD_int, CD_int); + static final MethodTypeDesc MTD_int_int_long = MethodTypeDescImpl.ofValidated(CD_int, CD_int, CD_long); + static final MethodTypeDesc MTD_int_int_String = MethodTypeDescImpl.ofValidated(CD_int, CD_int, CD_String); + static final MethodTypeDesc MTD_String_float = MethodTypeDescImpl.ofValidated(CD_String, CD_float); + static final MethodTypeDesc MTD_String_double = MethodTypeDescImpl.ofValidated(CD_String, CD_double); + static final MethodTypeDesc MTD_String_Object = MethodTypeDescImpl.ofValidated(CD_String, CD_Object); + + static final MethodTypeDesc MTD_INIT = MethodTypeDescImpl.ofValidated(CD_void, CD_Array_String); + static final MethodTypeDesc MTD_NEW_ARRAY_SUFFIX = MethodTypeDescImpl.ofValidated(CD_Array_byte, CD_String, CD_int, CD_byte); + static final MethodTypeDesc MTD_STRING_INIT = MethodTypeDescImpl.ofValidated(CD_void, CD_Array_byte, CD_byte); + + static final MethodTypeDesc PREPEND_int = MethodTypeDescImpl.ofValidated(CD_int, CD_int, CD_byte, CD_Array_byte, CD_int, CD_String); + static final MethodTypeDesc PREPEND_long = MethodTypeDescImpl.ofValidated(CD_int, CD_int, CD_byte, CD_Array_byte, CD_long, CD_String); + static final MethodTypeDesc PREPEND_boolean = MethodTypeDescImpl.ofValidated(CD_int, CD_int, CD_byte, CD_Array_byte, CD_boolean, CD_String); + static final MethodTypeDesc PREPEND_char = MethodTypeDescImpl.ofValidated(CD_int, CD_int, CD_byte, CD_Array_byte, CD_char, CD_String); + static final MethodTypeDesc PREPEND_String = MethodTypeDescImpl.ofValidated(CD_int, CD_int, CD_byte, CD_Array_byte, CD_String, CD_String); static final RuntimeVisibleAnnotationsAttribute FORCE_INLINE = RuntimeVisibleAnnotationsAttribute.of(Annotation.of(ClassDesc.ofDescriptor("Ljdk/internal/vm/annotation/ForceInline;"))); @@ -1166,7 +1168,7 @@ private static MethodType erasedArgs(MethodType args) { } paramTypes[i] = cl; } - return changed ? MethodType.methodType(args.returnType(), paramTypes) : args; + return changed ? MethodType.methodType(args.returnType(), paramTypes, true) : args; } /** @@ -1191,24 +1193,36 @@ private static MethodTypeDesc prependArgs(MethodType concatArgs) { var cl = concatArgs.parameterType(i); paramTypes[i + 4] = needStringOf(cl) ? CD_String : ConstantUtils.classDesc(cl); } - return MethodTypeDesc.of(CD_int, paramTypes); + return MethodTypeDescImpl.ofValidated(CD_int, paramTypes); } /** - * Construct the MethodType of the coder method, - * The first parameter is the initialized coder, Only parameter types that can be UTF16 are added. + * Construct the MethodType of the coder method. The first parameter is the initialized coder. + * Only parameter types which can be UTF16 are added. Returns null if no such parameter exists. */ - private static MethodTypeDesc coderArgs(MethodType concatArgs) { + private static MethodTypeDesc coderArgsIfMaybeUTF16(MethodType concatArgs) { int parameterCount = concatArgs.parameterCount(); - List paramTypes = new ArrayList<>(); - paramTypes.add(CD_int); // init coder + + int maybeUTF16Count = 0; for (int i = 0; i < parameterCount; i++) { + if (maybeUTF16(concatArgs.parameterType(i))) { + maybeUTF16Count++; + } + } + + if (maybeUTF16Count == 0) { + return null; + } + + var paramTypes = new ClassDesc[maybeUTF16Count + 1]; + paramTypes[0] = CD_int; // init coder + for (int i = 0, paramIndex = 1; i < parameterCount; i++) { var cl = concatArgs.parameterType(i); if (maybeUTF16(cl)) { - paramTypes.add(cl == char.class ? CD_char : CD_String); + paramTypes[paramIndex++] = cl == char.class ? CD_char : CD_String; } } - return MethodTypeDesc.of(CD_int, paramTypes); + return MethodTypeDescImpl.ofValidated(CD_int, paramTypes); } /** @@ -1223,7 +1237,7 @@ private static MethodTypeDesc lengthArgs(MethodType concatArgs) { var cl = concatArgs.parameterType(i); paramTypes[i + 1] = needStringOf(cl) ? CD_String : ConstantUtils.classDesc(cl); } - return MethodTypeDesc.of(CD_int, paramTypes); + return MethodTypeDescImpl.ofValidated(CD_int, paramTypes); } private static MethodHandle generate(Lookup lookup, MethodType args, String[] constants) throws Exception { @@ -1250,7 +1264,7 @@ private static MethodHandle generate(Lookup lookup, MethodType args, String[] co } } MethodTypeDesc lengthArgs = lengthArgs(concatArgs), - coderArgs = parameterMaybeUTF16(concatArgs) ? coderArgs(concatArgs) : null, + coderArgs = coderArgsIfMaybeUTF16(concatArgs), prependArgs = prependArgs(concatArgs); byte[] classBytes = ClassFile.of().build(CD_CONCAT, @@ -1478,7 +1492,7 @@ public void accept(CodeBuilder cb) { /* * String[] constants = this.constants; - * suffix = constants[paranCount]; + * suffix = constants[paramCount]; * length -= suffix.length(); */ cb.aload(thisSlot) @@ -1692,14 +1706,5 @@ static boolean needStringOf(Class cl) { static boolean maybeUTF16(Class cl) { return cl == char.class || !cl.isPrimitive(); } - - static boolean parameterMaybeUTF16(MethodType args) { - for (int i = 0; i < args.parameterCount(); i++) { - if (maybeUTF16(args.parameterType(i))) { - return true; - } - } - return false; - } } } diff --git a/src/java.base/share/classes/java/lang/runtime/SwitchBootstraps.java b/src/java.base/share/classes/java/lang/runtime/SwitchBootstraps.java index 43f7339c75a96..bfdb76e2ef1b6 100644 --- a/src/java.base/share/classes/java/lang/runtime/SwitchBootstraps.java +++ b/src/java.base/share/classes/java/lang/runtime/SwitchBootstraps.java @@ -43,13 +43,14 @@ import java.util.Optional; import java.util.function.BiPredicate; import java.util.function.Consumer; -import java.util.stream.Stream; + import jdk.internal.access.SharedSecrets; import java.lang.classfile.ClassFile; import java.lang.classfile.Label; import java.lang.classfile.instruction.SwitchCase; import jdk.internal.constant.ConstantUtils; +import jdk.internal.constant.MethodTypeDescImpl; import jdk.internal.constant.ReferenceClassDescImpl; import jdk.internal.misc.PreviewFeatures; import jdk.internal.vm.annotation.Stable; @@ -81,19 +82,27 @@ private SwitchBootstraps() {} private static final MethodHandles.Lookup LOOKUP = MethodHandles.lookup(); private static final boolean previewEnabled = PreviewFeatures.isEnabled(); + private static final ClassDesc CD_BiPredicate = ReferenceClassDescImpl.ofValidated("Ljava/util/function/BiPredicate;"); + private static final ClassDesc CD_Objects = ReferenceClassDescImpl.ofValidated("Ljava/util/Objects;"); - private static final MethodType TYPES_SWITCH_TYPE = MethodType.methodType(int.class, + private static final MethodTypeDesc CHECK_INDEX_DESCRIPTOR = + MethodTypeDescImpl.ofValidated(ConstantDescs.CD_int, ConstantDescs.CD_int, ConstantDescs.CD_int); + private static final MethodTypeDesc MTD_TYPE_SWITCH = MethodTypeDescImpl.ofValidated(ConstantDescs.CD_int, + ConstantDescs.CD_Object, + ConstantDescs.CD_int); + private static final MethodTypeDesc MTD_TYPE_SWITCH_EXTRA = MethodTypeDescImpl.ofValidated(ConstantDescs.CD_int, + ConstantDescs.CD_Object, + ConstantDescs.CD_int, + CD_BiPredicate, + ConstantDescs.CD_List); + private static final MethodType MT_TYPE_SWITCH_EXTRA = MethodType.methodType(int.class, Object.class, int.class, BiPredicate.class, List.class); - - private static final MethodTypeDesc TYPES_SWITCH_DESCRIPTOR = - MethodTypeDesc.ofDescriptor("(Ljava/lang/Object;ILjava/util/function/BiPredicate;Ljava/util/List;)I"); - private static final MethodTypeDesc CHECK_INDEX_DESCRIPTOR = - MethodTypeDesc.ofDescriptor("(II)I"); - - private static final ClassDesc CD_Objects = ReferenceClassDescImpl.ofValidated("Ljava/util/Objects;"); + private static final MethodType MT_TYPE_SWITCH = MethodType.methodType(int.class, + Object.class, + int.class); private static class StaticHolders { private static final MethodHandle MAPPED_ENUM_SWITCH; @@ -180,7 +189,7 @@ public static CallSite typeSwitch(MethodHandles.Lookup lookup, } MethodHandle target = generateTypeSwitch(lookup, selectorType, labels); - + target = target.asType(invocationType); return new ConstantCallSite(target); } @@ -272,9 +281,8 @@ public static CallSite enumSwitch(MethodHandles.Lookup lookup, || !invocationType.parameterType(0).isEnum() || !invocationType.parameterType(1).equals(int.class)) throw new IllegalArgumentException("Illegal invocation type " + invocationType); - requireNonNull(labels); - labels = labels.clone(); + labels = labels.clone(); // implicit null check Class enumClass = invocationType.parameterType(0); boolean constantsOnly = true; @@ -301,7 +309,6 @@ public static CallSite enumSwitch(MethodHandles.Lookup lookup, } else { target = generateTypeSwitch(lookup, invocationType.parameterType(0), labels); } - target = target.asType(invocationType); return new ConstantCallSite(target); @@ -434,6 +441,33 @@ private static final class MappedEnumCache { public MethodHandle generatedSwitch; } + /** + * Check if the labelConstants can be converted statically to bytecode, or + * whether we'll need to compute and pass in extra information at the call site. + */ + private static boolean needsExtraInfo(Class selectorType, Object[] labelConstants) { + for (int idx = labelConstants.length - 1; idx >= 0; idx--) { + Object currentLabel = labelConstants[idx]; + if (currentLabel instanceof Class classLabel) { + // No extra info needed for exact matches or primitives + if (unconditionalExactnessCheck(selectorType, classLabel) || classLabel.isPrimitive()) { + continue; + } + // Hidden classes - or arrays thereof - can't be nominally + // represented. Passed in as arguments. + while (classLabel.isArray()) { + classLabel = classLabel.getComponentType(); + } + if (classLabel.isHidden()) { + return true; + } + } else if (currentLabel instanceof EnumDesc) { + // EnumDescs labels needs late binding + return true; + } + } + return false; + } /* * Construct test chains for labels inside switch, to handle switch repeats: * switch (idx) { @@ -467,9 +501,10 @@ private static Consumer generateTypeSwitchSkeleton(Class selecto } cb.iload(RESTART_IDX); Label dflt = cb.newLabel(); - record Element(Label target, Label next, Object caseLabel) { } - List cases = new ArrayList<>(); - List switchCases = new ArrayList<>(); + Label[] caseTargets = new Label[labelConstants.length]; + Label[] caseNext = new Label[labelConstants.length]; + Object[] caseLabels = new Object[labelConstants.length]; + SwitchCase[] switchCases = new SwitchCase[labelConstants.length]; Object lastLabel = null; for (int idx = labelConstants.length - 1; idx >= 0; idx--) { Object currentLabel = labelConstants[idx]; @@ -478,22 +513,22 @@ record Element(Label target, Label next, Object caseLabel) { } if (lastLabel == null) { next = dflt; } else if (lastLabel.equals(currentLabel)) { - next = cases.getLast().next(); + next = caseNext[idx + 1]; } else { - next = cases.getLast().target(); + next = caseTargets[idx + 1]; } lastLabel = currentLabel; - cases.add(new Element(target, next, currentLabel)); - switchCases.add(SwitchCase.of(idx, target)); + caseTargets[idx] = target; + caseNext[idx] = next; + caseLabels[idx] = currentLabel; + switchCases[idx] = SwitchCase.of(idx, target); } - cases = cases.reversed(); - switchCases = switchCases.reversed(); - cb.tableswitch(0, labelConstants.length - 1, dflt, switchCases); - for (int idx = 0; idx < cases.size(); idx++) { - Element element = cases.get(idx); - Label next = element.next(); - cb.labelBinding(element.target()); - if (element.caseLabel() instanceof Class classLabel) { + cb.tableswitch(0, labelConstants.length - 1, dflt, Arrays.asList(switchCases)); + for (int idx = 0; idx < labelConstants.length; idx++) { + Label next = caseNext[idx]; + Object caseLabel = caseLabels[idx]; + cb.labelBinding(caseTargets[idx]); + if (caseLabel instanceof Class classLabel) { if (unconditionalExactnessCheck(selectorType, classLabel)) { //nothing - unconditionally use this case } else if (classLabel.isPrimitive()) { @@ -577,7 +612,7 @@ record Element(Label target, Label next, Object caseLabel) { } extraClassLabels.add(classLabel); } } - } else if (element.caseLabel() instanceof EnumDesc enumLabel) { + } else if (caseLabel instanceof EnumDesc enumLabel) { int enumIdx = enumDescs.size(); enumDescs.add(enumLabel); cb.aload(ENUM_CACHE); @@ -587,13 +622,13 @@ record Element(Label target, Label next, Object caseLabel) { } MethodTypeDesc.of(ConstantDescs.CD_Integer, ConstantDescs.CD_int)); cb.aload(SELECTOR_OBJ); - cb.invokeinterface(referenceClassDesc(BiPredicate.class), + cb.invokeinterface(CD_BiPredicate, "test", MethodTypeDesc.of(ConstantDescs.CD_boolean, ConstantDescs.CD_Object, ConstantDescs.CD_Object)); cb.ifeq(next); - } else if (element.caseLabel() instanceof String stringLabel) { + } else if (caseLabel instanceof String stringLabel) { cb.ldc(stringLabel); cb.aload(SELECTOR_OBJ); cb.invokevirtual(ConstantDescs.CD_Object, @@ -601,7 +636,7 @@ record Element(Label target, Label next, Object caseLabel) { } MethodTypeDesc.of(ConstantDescs.CD_boolean, ConstantDescs.CD_Object)); cb.ifeq(next); - } else if (element.caseLabel() instanceof Integer integerLabel) { + } else if (caseLabel instanceof Integer integerLabel) { Label compare = cb.newLabel(); Label notNumber = cb.newLabel(); cb.aload(SELECTOR_OBJ); @@ -626,16 +661,16 @@ record Element(Label target, Label next, Object caseLabel) { } cb.ldc(integerLabel); cb.if_icmpne(next); - } else if ((element.caseLabel() instanceof Long || - element.caseLabel() instanceof Float || - element.caseLabel() instanceof Double || - element.caseLabel() instanceof Boolean)) { - if (element.caseLabel() instanceof Boolean c) { + } else if ((caseLabel instanceof Long || + caseLabel instanceof Float || + caseLabel instanceof Double || + caseLabel instanceof Boolean)) { + if (caseLabel instanceof Boolean c) { cb.loadConstant(c ? 1 : 0); } else { - cb.loadConstant((ConstantDesc) element.caseLabel()); + cb.loadConstant((ConstantDesc) caseLabel); } - var caseLabelWrapper = Wrapper.forWrapperType(element.caseLabel().getClass()); + var caseLabelWrapper = Wrapper.forWrapperType(caseLabel.getClass()); cb.invokestatic(caseLabelWrapper.wrapperClassDescriptor(), "valueOf", MethodTypeDesc.of(caseLabelWrapper.wrapperClassDescriptor(), @@ -648,13 +683,13 @@ record Element(Label target, Label next, Object caseLabel) { } cb.ifeq(next); } else { throw new InternalError("Unsupported label type: " + - element.caseLabel().getClass()); + caseLabel.getClass()); } cb.loadConstant(idx); cb.ireturn(); } cb.labelBinding(dflt); - cb.loadConstant(cases.size()); + cb.loadConstant(labelConstants.length); cb.ireturn(); }; } @@ -663,14 +698,15 @@ record Element(Label target, Label next, Object caseLabel) { } * Construct the method handle that represents the method int typeSwitch(Object, int, BiPredicate, List) */ private static MethodHandle generateTypeSwitch(MethodHandles.Lookup caller, Class selectorType, Object[] labelConstants) { - List> enumDescs = new ArrayList<>(); - List> extraClassLabels = new ArrayList<>(); + boolean addExtraInfo = needsExtraInfo(selectorType, labelConstants); + List> enumDescs = addExtraInfo ? new ArrayList<>() : null; + List> extraClassLabels = addExtraInfo ? new ArrayList<>() : null; byte[] classBytes = ClassFile.of().build(ConstantUtils.binaryNameToDesc(typeSwitchClassName(caller.lookupClass())), clb -> { clb.withFlags(AccessFlag.FINAL, AccessFlag.SUPER, AccessFlag.SYNTHETIC) .withMethodBody("typeSwitch", - TYPES_SWITCH_DESCRIPTOR, + addExtraInfo ? MTD_TYPE_SWITCH_EXTRA : MTD_TYPE_SWITCH, ClassFile.ACC_FINAL | ClassFile.ACC_PUBLIC | ClassFile.ACC_STATIC, generateTypeSwitchSkeleton(selectorType, labelConstants, enumDescs, extraClassLabels)); }); @@ -681,13 +717,11 @@ private static MethodHandle generateTypeSwitch(MethodHandles.Lookup caller, Clas lookup = caller.defineHiddenClass(classBytes, true, NESTMATE, STRONG); MethodHandle typeSwitch = lookup.findStatic(lookup.lookupClass(), "typeSwitch", - TYPES_SWITCH_TYPE); - typeSwitch = MethodHandles.insertArguments(typeSwitch, 2, new ResolvedEnumLabels(caller, enumDescs.toArray(new EnumDesc[0])), - List.copyOf(extraClassLabels)); - typeSwitch = MethodHandles.explicitCastArguments(typeSwitch, - MethodType.methodType(int.class, - selectorType, - int.class)); + addExtraInfo ? MT_TYPE_SWITCH_EXTRA : MT_TYPE_SWITCH); + if (addExtraInfo) { + typeSwitch = MethodHandles.insertArguments(typeSwitch, 2, new ResolvedEnumLabels(caller, enumDescs.toArray(new EnumDesc[0])), + List.copyOf(extraClassLabels)); + } return typeSwitch; } catch (Throwable t) { throw new IllegalArgumentException(t); diff --git a/src/java.base/share/classes/java/text/CompactNumberFormat.java b/src/java.base/share/classes/java/text/CompactNumberFormat.java index 0cb5eb88079e4..35464d6ec91d0 100644 --- a/src/java.base/share/classes/java/text/CompactNumberFormat.java +++ b/src/java.base/share/classes/java/text/CompactNumberFormat.java @@ -652,16 +652,16 @@ private StringBuf format(double number, StringBuf result, double val = getNumberValue(number, divisor); if (checkIncrement(val, compactDataIndex, divisor)) { divisor = (Long) divisors.get(++compactDataIndex); - val = getNumberValue(number, divisor); } + roundedNumber = roundedNumber / divisor; + decimalFormat.setDigitList(roundedNumber, isNegative, getMaximumFractionDigits()); + val = decimalFormat.getDigitList().getDouble(); String prefix = getAffix(false, true, isNegative, compactDataIndex, val); String suffix = getAffix(false, false, isNegative, compactDataIndex, val); if (!prefix.isEmpty() || !suffix.isEmpty()) { appendPrefix(result, prefix, delegate); if (!placeHolderPatterns.get(compactDataIndex).get(val).isEmpty()) { - roundedNumber = roundedNumber / divisor; - decimalFormat.setDigitList(roundedNumber, isNegative, getMaximumFractionDigits()); decimalFormat.subformatNumber(result, delegate, isNegative, false, getMaximumIntegerDigits(), getMinimumIntegerDigits(), getMaximumFractionDigits(), getMinimumFractionDigits()); @@ -734,31 +734,28 @@ private StringBuf format(long number, StringBuf result, FieldDelegate delegate) double val = getNumberValue(number, divisor); if (checkIncrement(val, compactDataIndex, divisor)) { divisor = (Long) divisors.get(++compactDataIndex); - val = getNumberValue(number, divisor); } + var noFraction = number % divisor == 0; + if (noFraction) { + number = number / divisor; + decimalFormat.setDigitList(number, isNegative, 0); + } else { + // To avoid truncation of fractional part store + // the value in double and follow double path instead of + // long path + double dNumber = (double) number / divisor; + decimalFormat.setDigitList(dNumber, isNegative, getMaximumFractionDigits()); + } + val = decimalFormat.getDigitList().getDouble(); String prefix = getAffix(false, true, isNegative, compactDataIndex, val); String suffix = getAffix(false, false, isNegative, compactDataIndex, val); if (!prefix.isEmpty() || !suffix.isEmpty()) { appendPrefix(result, prefix, delegate); if (!placeHolderPatterns.get(compactDataIndex).get(val).isEmpty()) { - if ((number % divisor == 0)) { - number = number / divisor; - decimalFormat.setDigitList(number, isNegative, 0); - decimalFormat.subformatNumber(result, delegate, - isNegative, true, getMaximumIntegerDigits(), - getMinimumIntegerDigits(), getMaximumFractionDigits(), - getMinimumFractionDigits()); - } else { - // To avoid truncation of fractional part store - // the value in double and follow double path instead of - // long path - double dNumber = (double) number / divisor; - decimalFormat.setDigitList(dNumber, isNegative, getMaximumFractionDigits()); - decimalFormat.subformatNumber(result, delegate, - isNegative, false, getMaximumIntegerDigits(), - getMinimumIntegerDigits(), getMaximumFractionDigits(), - getMinimumFractionDigits()); - } + decimalFormat.subformatNumber(result, delegate, + isNegative, noFraction, getMaximumIntegerDigits(), + getMinimumIntegerDigits(), getMaximumFractionDigits(), + getMinimumFractionDigits()); appendSuffix(result, suffix, delegate); } } else { @@ -833,15 +830,15 @@ private StringBuf format(BigDecimal number, StringBuf result, double val = getNumberValue(number.doubleValue(), divisor.doubleValue()); if (checkIncrement(val, compactDataIndex, divisor.doubleValue())) { divisor = divisors.get(++compactDataIndex); - val = getNumberValue(number.doubleValue(), divisor.doubleValue()); } + number = number.divide(new BigDecimal(divisor.toString()), getRoundingMode()); + decimalFormat.setDigitList(number, isNegative, getMaximumFractionDigits()); + val = decimalFormat.getDigitList().getDouble(); String prefix = getAffix(false, true, isNegative, compactDataIndex, val); String suffix = getAffix(false, false, isNegative, compactDataIndex, val); if (!prefix.isEmpty() || !suffix.isEmpty()) { appendPrefix(result, prefix, delegate); if (!placeHolderPatterns.get(compactDataIndex).get(val).isEmpty()) { - number = number.divide(new BigDecimal(divisor.toString()), getRoundingMode()); - decimalFormat.setDigitList(number, isNegative, getMaximumFractionDigits()); decimalFormat.subformatNumber(result, delegate, isNegative, false, getMaximumIntegerDigits(), getMinimumIntegerDigits(), getMaximumFractionDigits(), getMinimumFractionDigits()); @@ -904,34 +901,30 @@ private StringBuf format(BigInteger number, StringBuf result, double val = getNumberValue(number.doubleValue(), divisor.doubleValue()); if (checkIncrement(val, compactDataIndex, divisor.doubleValue())) { divisor = divisors.get(++compactDataIndex); - val = getNumberValue(number.doubleValue(), divisor.doubleValue()); } + var noFraction = number.mod(new BigInteger(divisor.toString())) + .compareTo(BigInteger.ZERO) == 0; + if (noFraction) { + number = number.divide(new BigInteger(divisor.toString())); + decimalFormat.setDigitList(number, isNegative, 0); + } else { + // To avoid truncation of fractional part store the value in + // BigDecimal and follow BigDecimal path instead of + // BigInteger path + BigDecimal nDecimal = new BigDecimal(number) + .divide(new BigDecimal(divisor.toString()), getRoundingMode()); + decimalFormat.setDigitList(nDecimal, isNegative, getMaximumFractionDigits()); + } + val = decimalFormat.getDigitList().getDouble(); String prefix = getAffix(false, true, isNegative, compactDataIndex, val); String suffix = getAffix(false, false, isNegative, compactDataIndex, val); if (!prefix.isEmpty() || !suffix.isEmpty()) { appendPrefix(result, prefix, delegate); if (!placeHolderPatterns.get(compactDataIndex).get(val).isEmpty()) { - if (number.mod(new BigInteger(divisor.toString())) - .compareTo(BigInteger.ZERO) == 0) { - number = number.divide(new BigInteger(divisor.toString())); - - decimalFormat.setDigitList(number, isNegative, 0); - decimalFormat.subformatNumber(result, delegate, - isNegative, true, getMaximumIntegerDigits(), - getMinimumIntegerDigits(), getMaximumFractionDigits(), - getMinimumFractionDigits()); - } else { - // To avoid truncation of fractional part store the value in - // BigDecimal and follow BigDecimal path instead of - // BigInteger path - BigDecimal nDecimal = new BigDecimal(number) - .divide(new BigDecimal(divisor.toString()), getRoundingMode()); - decimalFormat.setDigitList(nDecimal, isNegative, getMaximumFractionDigits()); - decimalFormat.subformatNumber(result, delegate, - isNegative, false, getMaximumIntegerDigits(), - getMinimumIntegerDigits(), getMaximumFractionDigits(), - getMinimumFractionDigits()); - } + decimalFormat.subformatNumber(result, delegate, + isNegative, noFraction, getMaximumIntegerDigits(), + getMinimumIntegerDigits(), getMaximumFractionDigits(), + getMinimumFractionDigits()); appendSuffix(result, suffix, delegate); } } else { diff --git a/src/java.base/share/classes/java/text/DecimalFormat.java b/src/java.base/share/classes/java/text/DecimalFormat.java index c04abbd042f57..b23c5f360bf05 100644 --- a/src/java.base/share/classes/java/text/DecimalFormat.java +++ b/src/java.base/share/classes/java/text/DecimalFormat.java @@ -1799,6 +1799,14 @@ void setDigitList(Number number, boolean isNegative, int maxDigits) { } } + /** + * {@return the {@code DigitList} used by this {@code DecimalFormat} instance} + * Declared as package-private, intended for {@code CompactNumberFormat}. + */ + DigitList getDigitList() { + return digitList; + } + // ======== End fast-path formatting logic for double ========================= /** diff --git a/src/java.base/share/classes/java/time/LocalDateTime.java b/src/java.base/share/classes/java/time/LocalDateTime.java index d14afb7d78f9a..cea9123258c6b 100644 --- a/src/java.base/share/classes/java/time/LocalDateTime.java +++ b/src/java.base/share/classes/java/time/LocalDateTime.java @@ -1966,10 +1966,17 @@ public int hashCode() { @Override public String toString() { var buf = new StringBuilder(29); + formatTo(buf); + return buf.toString(); + } + + /** + * Prints the toString result to the given buf, avoiding extra string allocations. + */ + void formatTo(StringBuilder buf) { date.formatTo(buf); buf.append('T'); time.formatTo(buf); - return buf.toString(); } //----------------------------------------------------------------------- diff --git a/src/java.base/share/classes/java/time/OffsetDateTime.java b/src/java.base/share/classes/java/time/OffsetDateTime.java index bd75fffb24e55..fd8355e36cda5 100644 --- a/src/java.base/share/classes/java/time/OffsetDateTime.java +++ b/src/java.base/share/classes/java/time/OffsetDateTime.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 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 @@ -1923,7 +1923,10 @@ public int hashCode() { */ @Override public String toString() { - return dateTime.toString() + offset.toString(); + var offsetStr = offset.toString(); + var buf = new StringBuilder(29 + offsetStr.length()); + dateTime.formatTo(buf); + return buf.append(offsetStr).toString(); } //----------------------------------------------------------------------- diff --git a/src/java.base/share/classes/java/time/OffsetTime.java b/src/java.base/share/classes/java/time/OffsetTime.java index b9fe5e533d80e..1f6feb4180fc5 100644 --- a/src/java.base/share/classes/java/time/OffsetTime.java +++ b/src/java.base/share/classes/java/time/OffsetTime.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 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 @@ -1398,7 +1398,10 @@ public int hashCode() { */ @Override public String toString() { - return time.toString() + offset.toString(); + var offsetStr = offset.toString(); + var buf = new StringBuilder(18 + offsetStr.length()); + time.formatTo(buf); + return buf.append(offsetStr).toString(); } //----------------------------------------------------------------------- diff --git a/src/java.base/share/classes/java/time/ZonedDateTime.java b/src/java.base/share/classes/java/time/ZonedDateTime.java index 555392cf513ce..b1426efc914a4 100644 --- a/src/java.base/share/classes/java/time/ZonedDateTime.java +++ b/src/java.base/share/classes/java/time/ZonedDateTime.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 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 @@ -2214,11 +2214,20 @@ public int hashCode() { */ @Override // override for Javadoc public String toString() { - String str = dateTime.toString() + offset.toString(); + var offsetStr = offset.toString(); + var zoneStr = (String) null; + int length = 29 + offsetStr.length(); if (offset != zone) { - str += '[' + zone.toString() + ']'; + zoneStr = zone.toString(); + length += zoneStr.length() + 2; } - return str; + var buf = new StringBuilder(length); + dateTime.formatTo(buf); + buf.append(offsetStr); + if (zoneStr != null) { + buf.append('[').append(zoneStr).append(']'); + } + return buf.toString(); } //----------------------------------------------------------------------- diff --git a/src/java.base/share/classes/java/util/Locale.java b/src/java.base/share/classes/java/util/Locale.java index ae6c4af5ec56c..73132b81c09a6 100644 --- a/src/java.base/share/classes/java/util/Locale.java +++ b/src/java.base/share/classes/java/util/Locale.java @@ -988,17 +988,23 @@ static Locale getInstance(BaseLocale baseloc, LocaleExtensions extensions) { if (locale != null) { return locale; } - return LOCALE_CACHE.computeIfAbsent(baseloc, LOCALE_CREATOR); + return LocaleCache.cache(baseloc); } else { LocaleKey key = new LocaleKey(baseloc, extensions); - return LOCALE_CACHE.computeIfAbsent(key, LOCALE_CREATOR); + return LocaleCache.cache(key); } } - private static final ReferencedKeyMap LOCALE_CACHE - = ReferencedKeyMap.create(true, ReferencedKeyMap.concurrentHashMapSupplier()); + private static final class LocaleCache implements Function { + private static final ReferencedKeyMap LOCALE_CACHE + = ReferencedKeyMap.create(true, ReferencedKeyMap.concurrentHashMapSupplier()); + + private static final Function LOCALE_CREATOR = new LocaleCache(); + + public static Locale cache(Object key) { + return LOCALE_CACHE.computeIfAbsent(key, LOCALE_CREATOR); + } - private static final Function LOCALE_CREATOR = new Function<>() { @Override public Locale apply(Object key) { if (key instanceof BaseLocale base) { @@ -1007,7 +1013,7 @@ public Locale apply(Object key) { LocaleKey lk = (LocaleKey)key; return new Locale(lk.base, lk.exts); } - }; + } private static final class LocaleKey { diff --git a/src/java.base/share/classes/java/util/concurrent/ScheduledThreadPoolExecutor.java b/src/java.base/share/classes/java/util/concurrent/ScheduledThreadPoolExecutor.java index 87e2ea4920599..d2bfa40c9b9d0 100644 --- a/src/java.base/share/classes/java/util/concurrent/ScheduledThreadPoolExecutor.java +++ b/src/java.base/share/classes/java/util/concurrent/ScheduledThreadPoolExecutor.java @@ -182,6 +182,11 @@ public class ScheduledThreadPoolExecutor */ private static final AtomicLong sequencer = new AtomicLong(); + /** + * Maximum delay is effectively 146 years + */ + private static final long MAX_NANOS = (Long.MAX_VALUE >>> 1) - 1; + private class ScheduledFutureTask extends FutureTask implements RunnableScheduledFuture { @@ -525,25 +530,7 @@ private long triggerTime(long delay, TimeUnit unit) { * Returns the nanoTime-based trigger time of a delayed action. */ long triggerTime(long delay) { - return System.nanoTime() + - ((delay < (Long.MAX_VALUE >> 1)) ? delay : overflowFree(delay)); - } - - /** - * Constrains the values of all delays in the queue to be within - * Long.MAX_VALUE of each other, to avoid overflow in compareTo. - * This may occur if a task is eligible to be dequeued, but has - * not yet been, while some other task is added with a delay of - * Long.MAX_VALUE. - */ - private long overflowFree(long delay) { - Delayed head = (Delayed) super.getQueue().peek(); - if (head != null) { - long headDelay = head.getDelay(NANOSECONDS); - if (headDelay < 0 && (delay - headDelay < 0)) - delay = Long.MAX_VALUE + headDelay; - } - return delay; + return System.nanoTime() + Math.min(delay, MAX_NANOS); } /** diff --git a/src/java.base/share/classes/jdk/internal/access/JavaLangAccess.java b/src/java.base/share/classes/jdk/internal/access/JavaLangAccess.java index e4d322a20d729..2a89386f742dc 100644 --- a/src/java.base/share/classes/jdk/internal/access/JavaLangAccess.java +++ b/src/java.base/share/classes/jdk/internal/access/JavaLangAccess.java @@ -281,10 +281,14 @@ public interface JavaLangAccess { void addEnableNativeAccessToAllUnnamed(); /** - * Ensure that the given module has native access. If not, warn or - * throw exception depending on the configuration. - */ - void ensureNativeAccess(Module m, Class owner, String methodName, Class currentClass); + * Ensure that the given module has native access. If not, warn or throw exception depending on the configuration. + * @param m the module in which native access occurred + * @param owner the owner of the restricted method being called (or the JNI method being bound) + * @param methodName the name of the restricted method being called (or the JNI method being bound) + * @param currentClass the class calling the restricted method (for JNI, this is the same as {@code owner}) + * @param jni {@code true}, if this event is related to a JNI method being bound + */ + void ensureNativeAccess(Module m, Class owner, String methodName, Class currentClass, boolean jni); /** * Returns the ServicesCatalog for the given Layer. diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/AbstractPoolEntry.java b/src/java.base/share/classes/jdk/internal/classfile/impl/AbstractPoolEntry.java index c27968eecab4f..bc885291b44cd 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/AbstractPoolEntry.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/AbstractPoolEntry.java @@ -1030,34 +1030,13 @@ public boolean equals(Object o) { } - abstract static sealed class PrimitiveEntry - extends AbstractPoolEntry { - protected final T val; - - public PrimitiveEntry(ConstantPool constantPool, int tag, int index, T val) { - super(constantPool, tag, index, hash1(tag, val.hashCode())); - this.val = val; - } + public static final class IntegerEntryImpl extends AbstractPoolEntry implements IntegerEntry { - public T value() { - return val; - } - - public ConstantDesc constantValue() { - return value(); - } - - @Override - public String toString() { - return "" + tag() + value(); - } - } - - public static final class IntegerEntryImpl extends PrimitiveEntry - implements IntegerEntry { + private final int val; IntegerEntryImpl(ConstantPool cpm, int index, int i) { - super(cpm, ClassFile.TAG_INTEGER, index, i); + super(cpm, ClassFile.TAG_INTEGER, index, hash1(ClassFile.TAG_INTEGER, Integer.hashCode(i))); + val = i; } @Override @@ -1073,7 +1052,12 @@ public IntegerEntry clone(ConstantPoolBuilder cp) { @Override public int intValue() { - return value(); + return val; + } + + @Override + public ConstantDesc constantValue() { + return val; } @Override @@ -1086,11 +1070,14 @@ public boolean equals(Object o) { } } - public static final class FloatEntryImpl extends PrimitiveEntry + public static final class FloatEntryImpl extends AbstractPoolEntry implements FloatEntry { + private final float val; + FloatEntryImpl(ConstantPool cpm, int index, float f) { - super(cpm, ClassFile.TAG_FLOAT, index, f); + super(cpm, ClassFile.TAG_FLOAT, index, hash1(ClassFile.TAG_FLOAT, Float.hashCode(f))); + val = f; } @Override @@ -1106,7 +1093,12 @@ public FloatEntry clone(ConstantPoolBuilder cp) { @Override public float floatValue() { - return value(); + return val; + } + + @Override + public ConstantDesc constantValue() { + return val; } @Override @@ -1119,10 +1111,13 @@ public boolean equals(Object o) { } } - public static final class LongEntryImpl extends PrimitiveEntry implements LongEntry { + public static final class LongEntryImpl extends AbstractPoolEntry implements LongEntry { + + private final long val; LongEntryImpl(ConstantPool cpm, int index, long l) { - super(cpm, ClassFile.TAG_LONG, index, l); + super(cpm, ClassFile.TAG_LONG, index, hash1(ClassFile.TAG_LONG, Long.hashCode(l))); + val = l; } @Override @@ -1138,7 +1133,12 @@ public LongEntry clone(ConstantPoolBuilder cp) { @Override public long longValue() { - return value(); + return val; + } + + @Override + public ConstantDesc constantValue() { + return val; } @Override @@ -1151,10 +1151,13 @@ public boolean equals(Object o) { } } - public static final class DoubleEntryImpl extends PrimitiveEntry implements DoubleEntry { + public static final class DoubleEntryImpl extends AbstractPoolEntry implements DoubleEntry { + + private final double val; DoubleEntryImpl(ConstantPool cpm, int index, double d) { - super(cpm, ClassFile.TAG_DOUBLE, index, d); + super(cpm, ClassFile.TAG_DOUBLE, index, hash1(ClassFile.TAG_DOUBLE, Double.hashCode(d))); + val = d; } @Override @@ -1170,7 +1173,12 @@ public DoubleEntry clone(ConstantPoolBuilder cp) { @Override public double doubleValue() { - return value(); + return val; + } + + @Override + public ConstantDesc constantValue() { + return val; } @Override diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/AttributeHolder.java b/src/java.base/share/classes/jdk/internal/classfile/impl/AttributeHolder.java index 31e1a7f2533fc..fb9ecc98902d7 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/AttributeHolder.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/AttributeHolder.java @@ -54,7 +54,7 @@ public void writeTo(BufWriterImpl buf) { } @SuppressWarnings("unchecked") -
A get(AttributeMapper am) { + > A get(AttributeMapper am) { for (Attribute a : attributes) if (a.attributeMapper() == am) return (A)a; diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/BoundAttribute.java b/src/java.base/share/classes/jdk/internal/classfile/impl/BoundAttribute.java index d5ed0c14bcef4..36ef2fa55ebef 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/BoundAttribute.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/BoundAttribute.java @@ -148,7 +148,7 @@ public static List> readAttributes(AttributedElement enclosing, Cla mapper = customAttributes.apply(name); } if (mapper != null) { - filled.add((Attribute) Objects.requireNonNull(mapper.readAttribute(enclosing, reader, p))); + filled.add(Objects.requireNonNull(mapper.readAttribute(enclosing, reader, p))); } else { AttributeMapper fakeMapper = new AttributeMapper<>() { @Override diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/ClassFileImpl.java b/src/java.base/share/classes/jdk/internal/classfile/impl/ClassFileImpl.java index 8de62e7a12ba6..1fd4c5cb1a0b0 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/ClassFileImpl.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/ClassFileImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 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 @@ -83,17 +83,28 @@ public ClassFileImpl withOptions(Option... options) { var chro = classHierarchyResolverOption; var amo = attributeMapperOption; for (var o : options) { - switch (o) { - case StackMapsOption oo -> smo = oo; - case DebugElementsOption oo -> deo = oo; - case LineNumbersOption oo -> lno = oo; - case AttributesProcessingOption oo -> apo = oo; - case ConstantPoolSharingOption oo -> cpso = oo; - case ShortJumpsOption oo -> sjo = oo; - case DeadCodeOption oo -> dco = oo; - case DeadLabelsOption oo -> dlo = oo; - case ClassHierarchyResolverOption oo -> chro = oo; - case AttributeMapperOption oo -> amo = oo; + if (o instanceof StackMapsOption oo) { + smo = oo; + } else if (o instanceof DebugElementsOption oo) { + deo = oo; + } else if (o instanceof LineNumbersOption oo) { + lno = oo; + } else if (o instanceof AttributesProcessingOption oo) { + apo = oo; + } else if (o instanceof ConstantPoolSharingOption oo) { + cpso = oo; + } else if (o instanceof ShortJumpsOption oo) { + sjo = oo; + } else if (o instanceof DeadCodeOption oo) { + dco = oo; + } else if (o instanceof DeadLabelsOption oo) { + dlo = oo; + } else if (o instanceof ClassHierarchyResolverOption oo) { + chro = oo; + } else if (o instanceof AttributeMapperOption oo) { + amo = oo; + } else { // null or unknown Option type + throw new IllegalArgumentException("Invalid option: " + o); } } return new ClassFileImpl(smo, deo, lno, apo, cpso, sjo, dco, dlo, chro, amo); diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/SplitConstantPool.java b/src/java.base/share/classes/jdk/internal/classfile/impl/SplitConstantPool.java index f7905712b18d6..777da61c49d9d 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/SplitConstantPool.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/SplitConstantPool.java @@ -266,19 +266,70 @@ private BootstrapMethodEntryImpl internalAdd(BootstrapMethodEntryImpl bsm, int h return bsm; } - private PoolEntry findPrimitiveEntry(int tag, T val) { - int hash = AbstractPoolEntry.hash1(tag, val.hashCode()); + private IntegerEntry findIntEntry(int val) { + int hash = AbstractPoolEntry.hash1(TAG_INTEGER, Integer.hashCode(val)); EntryMap map = map(); for (int token = map.firstToken(hash); token != -1; token = map.nextToken(hash, token)) { PoolEntry e = map.getElementByToken(token); - if (e.tag() == tag - && e instanceof AbstractPoolEntry.PrimitiveEntry ce - && ce.value().equals(val)) - return e; + if (e.tag() == TAG_INTEGER + && e instanceof AbstractPoolEntry.IntegerEntryImpl ce + && ce.intValue() == val) + return ce; + } + if (!doneFullScan) { + fullScan(); + return findIntEntry(val); + } + return null; + } + + private LongEntry findLongEntry(long val) { + int hash = AbstractPoolEntry.hash1(TAG_LONG, Long.hashCode(val)); + EntryMap map = map(); + for (int token = map.firstToken(hash); token != -1; token = map.nextToken(hash, token)) { + PoolEntry e = map.getElementByToken(token); + if (e.tag() == TAG_LONG + && e instanceof AbstractPoolEntry.LongEntryImpl ce + && ce.longValue() == val) + return ce; + } + if (!doneFullScan) { + fullScan(); + return findLongEntry(val); + } + return null; + } + + private FloatEntry findFloatEntry(float val) { + int hash = AbstractPoolEntry.hash1(TAG_FLOAT, Float.hashCode(val)); + EntryMap map = map(); + for (int token = map.firstToken(hash); token != -1; token = map.nextToken(hash, token)) { + PoolEntry e = map.getElementByToken(token); + if (e.tag() == TAG_FLOAT + && e instanceof AbstractPoolEntry.FloatEntryImpl ce + && ce.floatValue() == val) + return ce; + } + if (!doneFullScan) { + fullScan(); + return findFloatEntry(val); + } + return null; + } + + private DoubleEntry findDoubleEntry(double val) { + int hash = AbstractPoolEntry.hash1(TAG_DOUBLE, Double.hashCode(val)); + EntryMap map = map(); + for (int token = map.firstToken(hash); token != -1; token = map.nextToken(hash, token)) { + PoolEntry e = map.getElementByToken(token); + if (e.tag() == TAG_DOUBLE + && e instanceof AbstractPoolEntry.DoubleEntryImpl ce + && ce.doubleValue() == val) + return ce; } if (!doneFullScan) { fullScan(); - return findPrimitiveEntry(tag, val); + return findDoubleEntry(val); } return null; } @@ -542,25 +593,25 @@ public ConstantDynamicEntry constantDynamicEntry(BootstrapMethodEntry bootstrapM @Override public IntegerEntry intEntry(int value) { - var e = (IntegerEntry) findPrimitiveEntry(TAG_INTEGER, value); + var e = findIntEntry(value); return e == null ? internalAdd(new AbstractPoolEntry.IntegerEntryImpl(this, size, value)) : e; } @Override public FloatEntry floatEntry(float value) { - var e = (FloatEntry) findPrimitiveEntry(TAG_FLOAT, value); + var e = findFloatEntry(value); return e == null ? internalAdd(new AbstractPoolEntry.FloatEntryImpl(this, size, value)) : e; } @Override public LongEntry longEntry(long value) { - var e = (LongEntry) findPrimitiveEntry(TAG_LONG, value); + var e = findLongEntry(value); return e == null ? internalAdd(new AbstractPoolEntry.LongEntryImpl(this, size, value)) : e; } @Override public DoubleEntry doubleEntry(double value) { - var e = (DoubleEntry) findPrimitiveEntry(TAG_DOUBLE, value); + var e = findDoubleEntry(value); return e == null ? internalAdd(new AbstractPoolEntry.DoubleEntryImpl(this, size, value)) : e; } diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/StackMapDecoder.java b/src/java.base/share/classes/jdk/internal/classfile/impl/StackMapDecoder.java index d0bf91171acfe..609333048d0d3 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/StackMapDecoder.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/StackMapDecoder.java @@ -161,13 +161,14 @@ private static boolean equals(List l1, List + switch (vti.tag()) { + case VT_TOP, VT_INTEGER, VT_FLOAT, VT_DOUBLE, VT_LONG, VT_NULL, VT_UNINITIALIZED_THIS -> {} - case ObjectVerificationTypeInfo ovti -> - bw.writeIndex(ovti.className()); - case UninitializedVerificationTypeInfo uvti -> - bw.writeU2(bw.labelContext().labelToBci(uvti.newTarget())); + case VT_OBJECT -> + bw.writeIndex(((ObjectVerificationTypeInfo)vti).className()); + case VT_UNINITIALIZED -> + bw.writeU2(bw.labelContext().labelToBci(((UninitializedVerificationTypeInfo)vti).newTarget())); + default -> throw new IllegalArgumentException("Invalid verification type tag: " + vti.tag()); } } diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/Util.java b/src/java.base/share/classes/jdk/internal/classfile/impl/Util.java index 1ff80d766766e..a064c40be30a9 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/Util.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/Util.java @@ -224,7 +224,7 @@ public static MethodTypeDesc methodTypeSymbol(NameAndTypeEntry nat) { } @SuppressWarnings("unchecked") - private static void writeAttribute(BufWriterImpl writer, Attribute attr) { + private static > void writeAttribute(BufWriterImpl writer, Attribute attr) { if (attr instanceof CustomAttribute ca) { var mapper = (AttributeMapper) ca.attributeMapper(); mapper.writeAttribute(writer, (T) ca); diff --git a/src/java.base/share/classes/jdk/internal/foreign/AbstractMemorySegmentImpl.java b/src/java.base/share/classes/jdk/internal/foreign/AbstractMemorySegmentImpl.java index 42857decf63b1..75be22ac454fa 100644 --- a/src/java.base/share/classes/jdk/internal/foreign/AbstractMemorySegmentImpl.java +++ b/src/java.base/share/classes/jdk/internal/foreign/AbstractMemorySegmentImpl.java @@ -152,7 +152,7 @@ public final MemorySegment reinterpret(Arena arena, Consumer clea } public MemorySegment reinterpretInternal(Class callerClass, long newSize, Scope scope, Consumer cleanup) { - Reflection.ensureNativeAccess(callerClass, MemorySegment.class, "reinterpret"); + Reflection.ensureNativeAccess(callerClass, MemorySegment.class, "reinterpret", false); Utils.checkNonNegativeArgument(newSize, "newSize"); if (!isNative()) throw new UnsupportedOperationException("Not a native segment"); Runnable action = cleanup != null ? diff --git a/src/java.base/share/classes/jdk/internal/foreign/LayoutPath.java b/src/java.base/share/classes/jdk/internal/foreign/LayoutPath.java index 956a5c75875ab..dc995589472b1 100644 --- a/src/java.base/share/classes/jdk/internal/foreign/LayoutPath.java +++ b/src/java.base/share/classes/jdk/internal/foreign/LayoutPath.java @@ -66,7 +66,7 @@ public class LayoutPath { private static final MethodHandle MH_SLICE_LAYOUT; private static final MethodHandle MH_CHECK_ENCL_LAYOUT; private static final MethodHandle MH_SEGMENT_RESIZE; - private static final MethodHandle MH_ADD; + private static final MethodHandle MH_ADD_EXACT; static { try { @@ -81,7 +81,7 @@ public class LayoutPath { MethodType.methodType(void.class, MemorySegment.class, long.class, MemoryLayout.class)); MH_SEGMENT_RESIZE = lookup.findStatic(LayoutPath.class, "resizeSegment", MethodType.methodType(MemorySegment.class, MemorySegment.class)); - MH_ADD = lookup.findStatic(Long.class, "sum", + MH_ADD_EXACT = lookup.findStatic(Math.class, "addExact", MethodType.methodType(long.class, long.class, long.class)); } catch (Throwable ex) { throw new ExceptionInInitializerError(ex); @@ -244,15 +244,18 @@ private static long addScaledOffset(long base, long index, long stride, long bou } public MethodHandle offsetHandle() { - MethodHandle mh = MethodHandles.insertArguments(MH_ADD, 0, offset); + MethodHandle mh = MH_ADD_EXACT; for (int i = strides.length - 1; i >= 0; i--) { MethodHandle collector = MethodHandles.insertArguments(MH_ADD_SCALED_OFFSET, 2, strides[i], bounds[i]); - // (J, ...) -> J to (J, J, ...) -> J - // i.e. new coord is prefixed. Last coord will correspond to innermost layout - mh = MethodHandles.collectArguments(mh, 0, collector); - } - - return mh; + // (J, J, ...) -> J to (J, J, J, ...) -> J + // 1. the leading argument is the base offset (externally provided). + // 2. index arguments are added. The last index correspond to the innermost layout. + // 3. overflow can only occur at the outermost layer, due to the final addition with the base offset. + // This is because the layout API ensures (by construction) that all offsets generated from layout paths + // are always < Long.MAX_VALUE. + mh = MethodHandles.collectArguments(mh, 1, collector); + } + return MethodHandles.insertArguments(mh, 1, offset); } private MemoryLayout rootLayout() { diff --git a/src/java.base/share/classes/jdk/internal/foreign/abi/AbstractLinker.java b/src/java.base/share/classes/jdk/internal/foreign/abi/AbstractLinker.java index c803a2c9c84b7..103572072ac0c 100644 --- a/src/java.base/share/classes/jdk/internal/foreign/abi/AbstractLinker.java +++ b/src/java.base/share/classes/jdk/internal/foreign/abi/AbstractLinker.java @@ -88,7 +88,7 @@ private record LinkRequest(FunctionDescriptor descriptor, LinkerOptions options) @Override @CallerSensitive public final MethodHandle downcallHandle(MemorySegment symbol, FunctionDescriptor function, Option... options) { - Reflection.ensureNativeAccess(Reflection.getCallerClass(), Linker.class, "downcallHandle"); + Reflection.ensureNativeAccess(Reflection.getCallerClass(), Linker.class, "downcallHandle", false); SharedUtils.checkSymbol(symbol); return downcallHandle0(function, options).bindTo(symbol); } @@ -96,7 +96,7 @@ public final MethodHandle downcallHandle(MemorySegment symbol, FunctionDescripto @Override @CallerSensitive public final MethodHandle downcallHandle(FunctionDescriptor function, Option... options) { - Reflection.ensureNativeAccess(Reflection.getCallerClass(), Linker.class, "downcallHandle"); + Reflection.ensureNativeAccess(Reflection.getCallerClass(), Linker.class, "downcallHandle", false); return downcallHandle0(function, options); } @@ -123,7 +123,7 @@ private MethodHandle downcallHandle0(FunctionDescriptor function, Option... opti @Override @CallerSensitive public final MemorySegment upcallStub(MethodHandle target, FunctionDescriptor function, Arena arena, Linker.Option... options) { - Reflection.ensureNativeAccess(Reflection.getCallerClass(), Linker.class, "upcallStub"); + Reflection.ensureNativeAccess(Reflection.getCallerClass(), Linker.class, "upcallStub", false); Objects.requireNonNull(arena); Objects.requireNonNull(target); Objects.requireNonNull(function); diff --git a/src/java.base/share/classes/jdk/internal/foreign/abi/fallback/LibFallback.java b/src/java.base/share/classes/jdk/internal/foreign/abi/fallback/LibFallback.java index 58d6baf852554..19682d6c43f5b 100644 --- a/src/java.base/share/classes/jdk/internal/foreign/abi/fallback/LibFallback.java +++ b/src/java.base/share/classes/jdk/internal/foreign/abi/fallback/LibFallback.java @@ -36,7 +36,7 @@ private LibFallback() {} static final boolean SUPPORTED = tryLoadLibrary(); - @SuppressWarnings("removal") + @SuppressWarnings({"removal", "restricted"}) private static boolean tryLoadLibrary() { return java.security.AccessController.doPrivileged( new java.security.PrivilegedAction<>() { diff --git a/src/java.base/share/classes/jdk/internal/foreign/layout/ValueLayouts.java b/src/java.base/share/classes/jdk/internal/foreign/layout/ValueLayouts.java index 4d19879b01acd..e546773c42903 100644 --- a/src/java.base/share/classes/jdk/internal/foreign/layout/ValueLayouts.java +++ b/src/java.base/share/classes/jdk/internal/foreign/layout/ValueLayouts.java @@ -332,7 +332,7 @@ public int hashCode() { @Override @CallerSensitive public AddressLayout withTargetLayout(MemoryLayout layout) { - Reflection.ensureNativeAccess(Reflection.getCallerClass(), AddressLayout.class, "withTargetLayout"); + Reflection.ensureNativeAccess(Reflection.getCallerClass(), AddressLayout.class, "withTargetLayout", false); Objects.requireNonNull(layout); return new OfAddressImpl(order(), byteSize(), byteAlignment(), layout, name()); } diff --git a/src/java.base/share/classes/jdk/internal/jimage/NativeImageBuffer.java b/src/java.base/share/classes/jdk/internal/jimage/NativeImageBuffer.java index 8d228c050c605..0e3b178c32b0a 100644 --- a/src/java.base/share/classes/jdk/internal/jimage/NativeImageBuffer.java +++ b/src/java.base/share/classes/jdk/internal/jimage/NativeImageBuffer.java @@ -38,6 +38,7 @@ class NativeImageBuffer { static { java.security.AccessController.doPrivileged( new java.security.PrivilegedAction() { + @SuppressWarnings("restricted") public Void run() { System.loadLibrary("jimage"); return null; diff --git a/src/java.base/share/classes/jdk/internal/loader/Resource.java b/src/java.base/share/classes/jdk/internal/loader/Resource.java index d119c4b5eae9f..b72f4df7d52eb 100644 --- a/src/java.base/share/classes/jdk/internal/loader/Resource.java +++ b/src/java.base/share/classes/jdk/internal/loader/Resource.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 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 @@ -28,7 +28,6 @@ import java.io.EOFException; import java.net.URL; import java.io.IOException; -import java.io.InterruptedIOException; import java.io.InputStream; import java.security.CodeSigner; import java.util.jar.Manifest; @@ -87,25 +86,8 @@ public byte[] getBytes() throws IOException { // Get stream before content length so that a FileNotFoundException // can propagate upwards without being caught too early InputStream in = cachedInputStream(); - - // This code has been uglified to protect against interrupts. - // Even if a thread has been interrupted when loading resources, - // the IO should not abort, so must carefully retry, failing only - // if the retry leads to some other IO exception. - - boolean isInterrupted = Thread.interrupted(); - int len; - for (;;) { - try { - len = getContentLength(); - break; - } catch (InterruptedIOException iioe) { - Thread.interrupted(); - isInterrupted = true; - } - } - try { + int len = getContentLength(); b = new byte[0]; if (len == -1) len = Integer.MAX_VALUE; int pos = 0; @@ -121,13 +103,7 @@ public byte[] getBytes() throws IOException { } else { bytesToRead = b.length - pos; } - int cc = 0; - try { - cc = in.read(b, pos, bytesToRead); - } catch (InterruptedIOException iioe) { - Thread.interrupted(); - isInterrupted = true; - } + int cc = in.read(b, pos, bytesToRead); if (cc < 0) { if (len != Integer.MAX_VALUE) { throw new EOFException("Detect premature EOF"); @@ -143,13 +119,7 @@ public byte[] getBytes() throws IOException { } finally { try { in.close(); - } catch (InterruptedIOException iioe) { - isInterrupted = true; } catch (IOException ignore) {} - - if (isInterrupted) { - Thread.currentThread().interrupt(); - } } return b; } diff --git a/src/java.base/share/classes/jdk/internal/loader/URLClassPath.java b/src/java.base/share/classes/jdk/internal/loader/URLClassPath.java index dbd76e07d4f46..297c77bc106c7 100644 --- a/src/java.base/share/classes/jdk/internal/loader/URLClassPath.java +++ b/src/java.base/share/classes/jdk/internal/loader/URLClassPath.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 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 @@ -59,7 +59,6 @@ import java.util.StringTokenizer; import java.util.jar.JarFile; import java.util.zip.CRC32; -import java.util.zip.ZipEntry; import java.util.jar.JarEntry; import java.util.jar.Manifest; import java.util.jar.Attributes; @@ -439,27 +438,38 @@ private synchronized Loader getLoader(int index) { continue; } // Otherwise, create a new Loader for the URL. - Loader loader; + Loader loader = null; + final URL[] loaderClassPathURLs; try { loader = getLoader(url); // If the loader defines a local class path then add the // URLs as the next URLs to be opened. - URL[] urls = loader.getClassPath(); - if (urls != null) { - push(urls); - } + loaderClassPathURLs = loader.getClassPath(); } catch (IOException e) { - // Silently ignore for now... + // log the error and close the unusable loader (if any) + if (DEBUG) { + System.err.println("Failed to construct a loader or construct its" + + " local classpath for " + url + ", cause:" + e); + } + if (loader != null) { + closeQuietly(loader); + } continue; } catch (SecurityException se) { - // Always silently ignore. The context, if there is one, that - // this URLClassPath was given during construction will never - // have permission to access the URL. + // log the error and close the unusable loader (if any). + // The context, if there is one, that this URLClassPath was + // given during construction will never have permission to access the URL. if (DEBUG) { System.err.println("Failed to access " + url + ", " + se ); } + if (loader != null) { + closeQuietly(loader); + } continue; } + if (loaderClassPathURLs != null) { + push(loaderClassPathURLs); + } // Finally, add the Loader to the search path. loaders.add(loader); lmap.put(urlNoFragString, loader); @@ -467,6 +477,17 @@ private synchronized Loader getLoader(int index) { return loaders.get(index); } + // closes the given loader and ignores any IOException that may occur during close + private static void closeQuietly(final Loader loader) { + try { + loader.close(); + } catch (IOException ioe) { + if (DEBUG) { + System.err.println("ignoring exception " + ioe + " while closing loader " + loader); + } + } + } + /* * Returns the Loader for the specified base URL. */ diff --git a/src/java.base/share/classes/jdk/internal/module/ModuleBootstrap.java b/src/java.base/share/classes/jdk/internal/module/ModuleBootstrap.java index b97b0a2de40b0..facff0d6fdce8 100644 --- a/src/java.base/share/classes/jdk/internal/module/ModuleBootstrap.java +++ b/src/java.base/share/classes/jdk/internal/module/ModuleBootstrap.java @@ -787,17 +787,23 @@ private static void addExtraExportsOrOpens(ModuleLayer bootLayer, } } - private static final boolean HAS_ENABLE_NATIVE_ACCESS_FLAG; private static final Set USER_NATIVE_ACCESS_MODULES; private static final Set JDK_NATIVE_ACCESS_MODULES; + private static final IllegalNativeAccess ILLEGAL_NATIVE_ACCESS; - public static boolean hasEnableNativeAccessFlag() { - return HAS_ENABLE_NATIVE_ACCESS_FLAG; + public enum IllegalNativeAccess { + ALLOW, + WARN, + DENY + } + + public static IllegalNativeAccess illegalNativeAccess() { + return ILLEGAL_NATIVE_ACCESS; } static { + ILLEGAL_NATIVE_ACCESS = addIllegalNativeAccess(); USER_NATIVE_ACCESS_MODULES = decodeEnableNativeAccess(); - HAS_ENABLE_NATIVE_ACCESS_FLAG = !USER_NATIVE_ACCESS_MODULES.isEmpty(); JDK_NATIVE_ACCESS_MODULES = ModuleLoaderMap.nativeAccessModules(); } @@ -847,6 +853,27 @@ private static Set decodeEnableNativeAccess() { return modules; } + /** + * Process the --illegal-native-access option (and its default). + */ + private static IllegalNativeAccess addIllegalNativeAccess() { + String value = getAndRemoveProperty("jdk.module.illegal.native.access"); + // don't use a switch: bootstrapping issues! + if (value == null) { + return IllegalNativeAccess.WARN; // default + } else if (value.equals("deny")) { + return IllegalNativeAccess.DENY; + } else if (value.equals("allow")) { + return IllegalNativeAccess.ALLOW; + } else if (value.equals("warn")) { + return IllegalNativeAccess.WARN; + } else { + fail("Value specified to --illegal-native-access not recognized:" + + " '" + value + "'"); + return null; + } + } + /** * Decodes the values of --add-reads, -add-exports, --add-opens or * --patch-modules options that are encoded in system properties. diff --git a/src/java.base/share/classes/jdk/internal/reflect/Reflection.java b/src/java.base/share/classes/jdk/internal/reflect/Reflection.java index f6fa499538834..88098b11942be 100644 --- a/src/java.base/share/classes/jdk/internal/reflect/Reflection.java +++ b/src/java.base/share/classes/jdk/internal/reflect/Reflection.java @@ -111,7 +111,7 @@ public static void ensureMemberAccess(Class currentClass, } @ForceInline - public static void ensureNativeAccess(Class currentClass, Class owner, String methodName) { + public static void ensureNativeAccess(Class currentClass, Class owner, String methodName, boolean jni) { // if there is no caller class, act as if the call came from unnamed module of system class loader Module module = currentClass != null ? currentClass.getModule() : @@ -119,7 +119,10 @@ public static void ensureNativeAccess(Class currentClass, Class owner, Str class Holder { static final JavaLangAccess JLA = SharedSecrets.getJavaLangAccess(); } - Holder.JLA.ensureNativeAccess(module, owner, methodName, currentClass); + if (module != null) { + // not in init phase + Holder.JLA.ensureNativeAccess(module, owner, methodName, currentClass, jni); + } } /** diff --git a/src/java.base/share/classes/jdk/internal/vm/Continuation.java b/src/java.base/share/classes/jdk/internal/vm/Continuation.java index 5c1d41c36d97d..99d0c62aaec8d 100644 --- a/src/java.base/share/classes/jdk/internal/vm/Continuation.java +++ b/src/java.base/share/classes/jdk/internal/vm/Continuation.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 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 @@ -427,6 +427,7 @@ public boolean isPreempted() { * Pins the current continuation (enters a critical section). * This increments an internal semaphore that, when greater than 0, pins the continuation. */ + @IntrinsicCandidate public static native void pin(); /** @@ -434,6 +435,7 @@ public boolean isPreempted() { * This decrements an internal semaphore that, when equal 0, unpins the current continuation * if pinned with {@link #pin()}. */ + @IntrinsicCandidate public static native void unpin(); /** diff --git a/src/java.base/share/classes/module-info.java b/src/java.base/share/classes/module-info.java index 52c1029dd3d52..74a7451582cf7 100644 --- a/src/java.base/share/classes/module-info.java +++ b/src/java.base/share/classes/module-info.java @@ -256,7 +256,8 @@ jdk.internal.jvmstat, jdk.management, jdk.management.agent, - jdk.internal.vm.ci; + jdk.internal.vm.ci, + jdk.jfr; exports jdk.internal.vm.annotation to java.instrument, jdk.internal.vm.ci, diff --git a/src/java.base/share/classes/sun/launcher/resources/launcher.properties b/src/java.base/share/classes/sun/launcher/resources/launcher.properties index cd524955419a5..71cdb161fc029 100644 --- a/src/java.base/share/classes/sun/launcher/resources/launcher.properties +++ b/src/java.base/share/classes/sun/launcher/resources/launcher.properties @@ -65,6 +65,11 @@ java.launcher.opt.footer = \ \ --enable-native-access [,...]\n\ \ allow code in modules to access code and data outside the Java runtime.\n\ \ can also be ALL-UNNAMED to indicate code on the class path.\n\ +\ --illegal-native-access=\n\ +\ allow or deny access to code and data outside the Java runtime\n\ +\ by code in modules for which native access is not explicitly enabled.\n\ +\ is one of "deny", "warn" or "allow". The default value is "warn".\n\ +\ This option will be removed in a future release.\n\ \ --list-modules\n\ \ list observable modules and exit\n\ \ -d \n\ diff --git a/src/java.base/share/classes/sun/security/ssl/Finished.java b/src/java.base/share/classes/sun/security/ssl/Finished.java index 604a15fe1a683..6c7c8b4514933 100644 --- a/src/java.base/share/classes/sun/security/ssl/Finished.java +++ b/src/java.base/share/classes/sun/security/ssl/Finished.java @@ -1139,7 +1139,9 @@ private void onConsumeFinished(ServerHandshakeContext shc, // // produce - NewSessionTicket.t13PosthandshakeProducer.produce(shc); + if (SSLConfiguration.serverNewSessionTicketCount > 0) { + NewSessionTicket.t13PosthandshakeProducer.produce(shc); + } } } diff --git a/src/java.base/share/classes/sun/security/ssl/NewSessionTicket.java b/src/java.base/share/classes/sun/security/ssl/NewSessionTicket.java index 0655b0e14ee15..8be021b41114c 100644 --- a/src/java.base/share/classes/sun/security/ssl/NewSessionTicket.java +++ b/src/java.base/share/classes/sun/security/ssl/NewSessionTicket.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 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 @@ -25,11 +25,11 @@ package sun.security.ssl; import java.io.IOException; -import java.math.BigInteger; import java.nio.ByteBuffer; import java.security.GeneralSecurityException; import java.security.SecureRandom; import java.text.MessageFormat; +import java.util.Arrays; import java.util.Locale; import javax.crypto.SecretKey; import javax.net.ssl.SSLHandshakeException; @@ -118,11 +118,6 @@ static final class T12NewSessionTicketMessage extends NewSessionTicketMessage { this.ticket = Record.getBytes16(m); } - @Override - public SSLHandshake handshakeType() { - return NEW_SESSION_TICKET; - } - @Override public int messageLength() { return 4 + // ticketLifetime @@ -221,11 +216,6 @@ static final class T13NewSessionTicketMessage extends NewSessionTicketMessage { this.extensions = new SSLExtensions(this, m, supportedExtensions); } - @Override - public SSLHandshake handshakeType() { - return NEW_SESSION_TICKET; - } - int getTicketAgeAdd() { return ticketAgeAdd; } @@ -301,7 +291,7 @@ private static SecretKey derivePreSharedKey(CipherSuite.HashAlg hashAlg, "tls13 resumption".getBytes(), nonce, hashAlg.hashLength); return hkdf.expand(resumptionMasterSecret, hkdfInfo, hashAlg.hashLength, "TlsPreSharedKey"); - } catch (GeneralSecurityException gse) { + } catch (GeneralSecurityException gse) { throw new SSLHandshakeException("Could not derive PSK", gse); } } @@ -332,8 +322,7 @@ public byte[] produce(ConnectionContext context) throws IOException { // Is this session resumable? if (!hc.handshakeSession.isRejoinable()) { if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { - SSLLogger.fine( - "No session ticket produced: " + + SSLLogger.fine("No session ticket produced: " + "session is not resumable"); } @@ -351,8 +340,7 @@ public byte[] produce(ConnectionContext context) throws IOException { if (pkemSpec == null || !pkemSpec.contains(PskKeyExchangeMode.PSK_DHE_KE)) { if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { - SSLLogger.fine( - "No session ticket produced: " + + SSLLogger.fine("No session ticket produced: " + "client does not support psk_dhe_ke"); } @@ -363,8 +351,7 @@ public byte[] produce(ConnectionContext context) throws IOException { // using an allowable PSK exchange key mode. if (!hc.handshakeSession.isPSKable()) { if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { - SSLLogger.fine( - "No session ticket produced: " + + SSLLogger.fine("No session ticket produced: " + "No session ticket allowed in this session"); } @@ -375,76 +362,113 @@ public byte[] produce(ConnectionContext context) throws IOException { // get a new session ID SSLSessionContextImpl sessionCache = (SSLSessionContextImpl) hc.sslContext.engineGetServerSessionContext(); - SessionId newId = new SessionId(true, - hc.sslContext.getSecureRandom()); - - SecretKey resumptionMasterSecret = - hc.handshakeSession.getResumptionMasterSecret(); - if (resumptionMasterSecret == null) { + int sessionTimeoutSeconds = sessionCache.getSessionTimeout(); + if (sessionTimeoutSeconds > MAX_TICKET_LIFETIME) { if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { - SSLLogger.fine( - "No session ticket produced: " + - "no resumption secret"); + SSLLogger.fine("No session ticket produced: " + + "session timeout is too long"); } return null; } - // construct the PSK and handshake message - BigInteger nonce = hc.handshakeSession.incrTicketNonceCounter(); - byte[] nonceArr = nonce.toByteArray(); - SecretKey psk = derivePreSharedKey( - hc.negotiatedCipherSuite.hashAlg, - resumptionMasterSecret, nonceArr); - - int sessionTimeoutSeconds = sessionCache.getSessionTimeout(); - if (sessionTimeoutSeconds > MAX_TICKET_LIFETIME) { - if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { - SSLLogger.fine( - "No session ticket produced: " + - "session timeout"); + // Send NewSessionTickets to the client based + if (SSLConfiguration.serverNewSessionTicketCount > 0) { + int i = 0; + NewSessionTicketMessage nstm; + while (i < SSLConfiguration.serverNewSessionTicketCount) { + nstm = generateNST(hc, sessionCache); + if (nstm == null) { + break; + } + nstm.write(hc.handshakeOutput); + i++; } - return null; + hc.handshakeOutput.flush(); + } + /* + * With large NST counts, a client that quickly closes after + * TLS Finished completes can cause SocketExceptions such as: + * Windows servers read-side throwing SocketException: + * "An established connection was aborted by the software in + * your host machine", which relates to error WSAECONNABORTED. + * A SocketException caused by a "broken pipe" has been observed on + * other systems. + * These are very unlikely situations when client and server are on + * different machines. + * + * RFC 8446 does not put requirements when an NST needs to be + * sent, but it should be sent very soon after TLS Finished for + * clients that will quickly resume to create more sessions. + * TLS 1.3 is different from TLS 1.2, there is more data the client + * should be aware of + */ + + // See note on TransportContext.needHandshakeFinishedStatus. + // + // Reset the needHandshakeFinishedStatus flag. The delivery + // of this post-handshake message will indicate the FINISHED + // handshake status. It is not needed to have a follow-on + // SSLEngine.wrap() any longer. + if (hc.conContext.needHandshakeFinishedStatus) { + hc.conContext.needHandshakeFinishedStatus = false; } - NewSessionTicketMessage nstm = null; + // clean the post handshake context + hc.conContext.finishPostHandshake(); + + // The message has been delivered. + return null; + } + + private NewSessionTicketMessage generateNST(HandshakeContext hc, + SSLSessionContextImpl sessionCache) throws IOException { + + NewSessionTicketMessage nstm; + SessionId newId = new SessionId(true, + hc.sslContext.getSecureRandom()); + + // construct the PSK and handshake message + byte[] nonce = hc.handshakeSession.incrTicketNonceCounter(); SSLSessionImpl sessionCopy = - new SSLSessionImpl(hc.handshakeSession, newId); - sessionCopy.setPreSharedKey(psk); + new SSLSessionImpl(hc.handshakeSession, newId); + sessionCopy.setPreSharedKey(derivePreSharedKey( + hc.negotiatedCipherSuite.hashAlg, + hc.handshakeSession.getResumptionMasterSecret(), nonce)); sessionCopy.setPskIdentity(newId.getId()); // If a stateless ticket is allowed, attempt to make one if (hc.statelessResumption && hc.handshakeSession.isStatelessable()) { nstm = new T13NewSessionTicketMessage(hc, - sessionTimeoutSeconds, + sessionCache.getSessionTimeout(), hc.sslContext.getSecureRandom(), - nonceArr, + nonce, new SessionTicketSpec().encrypt(hc, sessionCopy)); // If ticket construction failed, switch to session cache if (!nstm.isValid()) { hc.statelessResumption = false; } else { if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { - SSLLogger.fine( - "Produced NewSessionTicket stateless " + + SSLLogger.fine("Produced NewSessionTicket stateless " + "post-handshake message", nstm); } } + return nstm; } // If a session cache ticket is being used, make one if (!hc.statelessResumption || !hc.handshakeSession.isStatelessable()) { - nstm = new T13NewSessionTicketMessage(hc, sessionTimeoutSeconds, - hc.sslContext.getSecureRandom(), nonceArr, - newId.getId()); + nstm = new T13NewSessionTicketMessage(hc, + sessionCache.getSessionTimeout(), + hc.sslContext.getSecureRandom(), nonce, + newId.getId()); if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { - SSLLogger.fine( - "Produced NewSessionTicket post-handshake message", - nstm); + SSLLogger.fine("Produced NewSessionTicket " + + "post-handshake message", nstm); } // create and cache the new session @@ -453,29 +477,13 @@ public byte[] produce(ConnectionContext context) throws IOException { hc.handshakeSession.addChild(sessionCopy); sessionCopy.setTicketAgeAdd(nstm.getTicketAgeAdd()); sessionCache.put(sessionCopy); + return nstm; } - // Output the handshake message. - if (nstm != null) { - // should never be null - nstm.write(hc.handshakeOutput); - hc.handshakeOutput.flush(); - - // See note on TransportContext.needHandshakeFinishedStatus. - // - // Reset the needHandshakeFinishedStatus flag. The delivery - // of this post-handshake message will indicate the FINISHED - // handshake status. It is not needed to have a follow-on - // SSLEngine.wrap() any longer. - if (hc.conContext.needHandshakeFinishedStatus) { - hc.conContext.needHandshakeFinishedStatus = false; - } + if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { + SSLLogger.fine("No NewSessionTicket created"); } - // clean the post handshake context - hc.conContext.finishPostHandshake(); - - // The message has been delivered. return null; } } @@ -497,8 +505,9 @@ public byte[] produce(ConnectionContext context, ServerHandshakeContext shc = (ServerHandshakeContext)context; - // Is this session resumable? - if (!shc.handshakeSession.isRejoinable()) { + // Are new tickets allowed? If so, is this session resumable? + if (SSLConfiguration.serverNewSessionTicketCount == 0 || + !shc.handshakeSession.isRejoinable()) { return null; } @@ -578,7 +587,6 @@ public void consume(ConnectionContext context, "Discarding NewSessionTicket with lifetime " + nstm.ticketLifetime, nstm); } - sessionCache.remove(hc.handshakeSession.getSessionId()); return; } @@ -619,13 +627,19 @@ public void consume(ConnectionContext context, sessionCopy.setPreSharedKey(psk); sessionCopy.setTicketAgeAdd(nstm.getTicketAgeAdd()); sessionCopy.setPskIdentity(nstm.ticket); - sessionCache.put(sessionCopy); + sessionCache.put(sessionCopy, sessionCopy.isPSK()); + + if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { + SSLLogger.fine("MultiNST PSK (Server): " + + Utilities.toHexString(Arrays.copyOf(nstm.ticket, 16))); + } // clean the post handshake context hc.conContext.finishPostHandshake(); } } + /* TLS 1.2 spec does not specify multiple NST behavior.*/ private static final class T12NewSessionTicketConsumer implements SSLConsumer { // Prevent instantiation of this class. @@ -674,8 +688,7 @@ public void consume(ConnectionContext context, hc.handshakeSession.setPskIdentity(nstm.ticket); if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { - SSLLogger.fine("Consuming NewSessionTicket\n" + - nstm.toString()); + SSLLogger.fine("Consuming NewSessionTicket\n" + nstm); } } } diff --git a/src/java.base/share/classes/sun/security/ssl/PreSharedKeyExtension.java b/src/java.base/share/classes/sun/security/ssl/PreSharedKeyExtension.java index 1d3ee2ece9d5a..43214841987f9 100644 --- a/src/java.base/share/classes/sun/security/ssl/PreSharedKeyExtension.java +++ b/src/java.base/share/classes/sun/security/ssl/PreSharedKeyExtension.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 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 @@ -699,11 +699,13 @@ public byte[] produce(ConnectionContext context, //The session cannot be used again. Remove it from the cache. SSLSessionContextImpl sessionCache = (SSLSessionContextImpl) chc.sslContext.engineGetClientSessionContext(); - sessionCache.remove(chc.resumingSession.getSessionId()); + sessionCache.remove(chc.resumingSession.getSessionId(), true); if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { SSLLogger.fine( "Found resumable session. Preparing PSK message."); + SSLLogger.fine( + "MultiNST PSK (Client): " + Utilities.toHexString(Arrays.copyOf(chc.pskIdentity, 16))); } List identities = new ArrayList<>(); diff --git a/src/java.base/share/classes/sun/security/ssl/SSLConfiguration.java b/src/java.base/share/classes/sun/security/ssl/SSLConfiguration.java index fcf93704ef9c1..421867aa4c4b2 100644 --- a/src/java.base/share/classes/sun/security/ssl/SSLConfiguration.java +++ b/src/java.base/share/classes/sun/security/ssl/SSLConfiguration.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 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 @@ -121,6 +121,11 @@ final class SSLConfiguration implements Cloneable { static final boolean enableDtlsResumeCookie = Utilities.getBooleanProperty( "jdk.tls.enableDtlsResumeCookie", true); + // Number of NewSessionTickets that will be sent by the server. + static final int serverNewSessionTicketCount; + // Default for NewSessionTickets + static final int SERVER_NST_DEFAULT = 1; + // Is the extended_master_secret extension supported? static { boolean supportExtendedMasterSecret = Utilities.getBooleanProperty( @@ -182,7 +187,7 @@ final class SSLConfiguration implements Cloneable { * - Otherwise it is set to a default value of 10. */ Integer inboundServerLen = GetIntegerAction.privilegedGetProperty( - "jdk.tls.client.maxInboundCertificateChainLength"); + "jdk.tls.client.maxInboundCertificateChainLength"); // Default for jdk.tls.client.maxInboundCertificateChainLength is 10 if (inboundServerLen == null || inboundServerLen < 0) { @@ -191,6 +196,33 @@ final class SSLConfiguration implements Cloneable { } else { maxInboundServerCertChainLen = inboundServerLen; } + + /* + * jdk.tls.server.newSessionTicketCount system property + * Sets the number of NewSessionTickets sent to a TLS 1.3 resumption + * client. The value must be between 0 and 10. Default is defined by + * SERVER_NST_DEFAULT. + */ + Integer nstServerCount = GetIntegerAction.privilegedGetProperty( + "jdk.tls.server.newSessionTicketCount"); + if (nstServerCount == null || nstServerCount < 0 || + nstServerCount > 10) { + serverNewSessionTicketCount = SERVER_NST_DEFAULT; + if (nstServerCount != null && SSLLogger.isOn && + SSLLogger.isOn("ssl,handshake")) { + SSLLogger.fine( + "jdk.tls.server.newSessionTicketCount defaults to " + + SERVER_NST_DEFAULT + " as the property was not " + + "between 0 and 10"); + } + } else { + serverNewSessionTicketCount = nstServerCount; + if (SSLLogger.isOn && SSLLogger.isOn("ssl,handshake")) { + SSLLogger.fine( + "jdk.tls.server.newSessionTicketCount set to " + + serverNewSessionTicketCount); + } + } } SSLConfiguration(SSLContextImpl sslContext, boolean isClientMode) { diff --git a/src/java.base/share/classes/sun/security/ssl/SSLEngineImpl.java b/src/java.base/share/classes/sun/security/ssl/SSLEngineImpl.java index a33f8b0d13a5f..36b5bd4a78c20 100644 --- a/src/java.base/share/classes/sun/security/ssl/SSLEngineImpl.java +++ b/src/java.base/share/classes/sun/security/ssl/SSLEngineImpl.java @@ -416,11 +416,12 @@ private HandshakeStatus tryNewSessionTicket( HandshakeStatus currentHandshakeStatus) throws IOException { // Don't bother to kickstart if handshaking is in progress, or if the // connection is not duplex-open. - if ((conContext.handshakeContext == null) && - conContext.protocolVersion.useTLS13PlusSpec() && - !conContext.isOutboundClosed() && - !conContext.isInboundClosed() && - !conContext.isBroken) { + if (SSLConfiguration.serverNewSessionTicketCount > 0 && + conContext.handshakeContext == null && + conContext.protocolVersion.useTLS13PlusSpec() && + !conContext.isOutboundClosed() && + !conContext.isInboundClosed() && + !conContext.isBroken) { if (SSLLogger.isOn && SSLLogger.isOn("ssl")) { SSLLogger.finest("trigger NST"); } diff --git a/src/java.base/share/classes/sun/security/ssl/SSLSessionContextImpl.java b/src/java.base/share/classes/sun/security/ssl/SSLSessionContextImpl.java index eb9eb75debe29..f3e22633ab4bc 100644 --- a/src/java.base/share/classes/sun/security/ssl/SSLSessionContextImpl.java +++ b/src/java.base/share/classes/sun/security/ssl/SSLSessionContextImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 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 @@ -63,6 +63,7 @@ final class SSLSessionContextImpl implements SSLSessionContext { private static final int DEFAULT_MAX_CACHE_SIZE = 20480; + private static final int DEFAULT_MAX_QUEUE_SIZE = 10; // Default lifetime of a session. 24 hours static final int DEFAULT_SESSION_TIMEOUT = 86400; @@ -87,14 +88,17 @@ final class SSLSessionContextImpl implements SSLSessionContext { cacheLimit = getDefaults(server); // default cache size // use soft reference - sessionCache = Cache.newSoftMemoryCache(cacheLimit, timeout); - sessionHostPortCache = Cache.newSoftMemoryCache(cacheLimit, timeout); if (server) { + sessionCache = Cache.newSoftMemoryCache(cacheLimit, timeout); + sessionHostPortCache = Cache.newSoftMemoryCache(cacheLimit, timeout); keyHashMap = new ConcurrentHashMap<>(); // Should be "randomly generated" according to RFC 5077, - // but doesn't necessarily has to be a true random number. + // but doesn't necessarily have to be a true random number. currentKeyID = new Random(System.nanoTime()).nextInt(); } else { + sessionCache = Cache.newSoftMemoryCache(cacheLimit, timeout); + sessionHostPortCache = Cache.newSoftMemoryQueue(cacheLimit, timeout, + DEFAULT_MAX_QUEUE_SIZE); keyHashMap = Map.of(); } } @@ -277,12 +281,22 @@ private static String getKey(String hostname, int port) { // time it created, which is a little longer than the expected. So // please do check isTimedout() while getting entry from the cache. void put(SSLSessionImpl s) { + put(s, false); + } + + /** + * Put an entry in the cache + * @param s SSLSessionImpl entry to be stored + * @param canQueue True if multiple entries may exist under one + * session entry. + */ + void put(SSLSessionImpl s, boolean canQueue) { sessionCache.put(s.getSessionId(), s); // If no hostname/port info is available, don't add this one. if ((s.getPeerHost() != null) && (s.getPeerPort() != -1)) { sessionHostPortCache.put( - getKey(s.getPeerHost(), s.getPeerPort()), s); + getKey(s.getPeerHost(), s.getPeerPort()), s, canQueue); } s.setContext(this); @@ -290,11 +304,17 @@ void put(SSLSessionImpl s) { // package-private method, remove a cached SSLSession void remove(SessionId key) { + remove(key, false); + } + void remove(SessionId key, boolean isClient) { SSLSessionImpl s = sessionCache.get(key); if (s != null) { sessionCache.remove(key); - sessionHostPortCache.remove( + // A client keeps the cache entry for queued NST resumption. + if (!isClient) { + sessionHostPortCache.remove( getKey(s.getPeerHost(), s.getPeerPort())); + } } } diff --git a/src/java.base/share/classes/sun/security/ssl/SSLSessionImpl.java b/src/java.base/share/classes/sun/security/ssl/SSLSessionImpl.java index a0708618e157b..b887eedd8dcfd 100644 --- a/src/java.base/share/classes/sun/security/ssl/SSLSessionImpl.java +++ b/src/java.base/share/classes/sun/security/ssl/SSLSessionImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 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 @@ -38,7 +38,6 @@ import java.util.Queue; import java.util.Collection; import java.util.Collections; -import java.util.Enumeration; import java.util.List; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentLinkedQueue; @@ -132,7 +131,11 @@ final class SSLSessionImpl extends ExtendedSSLSession { private final List requestedServerNames; // Counter used to create unique nonces in NewSessionTicket - private BigInteger ticketNonceCounter = BigInteger.ONE; + private byte ticketNonceCounter = 1; + + // This boolean is true when a new set of NewSessionTickets are needed after + // the initial ones sent after the handshake. + boolean updateNST = false; // The endpoint identification algorithm used to check certificates // in this session. @@ -492,7 +495,7 @@ final class SSLSessionImpl extends ExtendedSSLSession { // Length of pre-shared key algorithm (one byte) i = buf.get(); b = new byte[i]; - buf.get(b, 0 , i); + buf.get(b, 0, i); String alg = new String(b); // Get length of encoding i = Short.toUnsignedInt(buf.getShort()); @@ -501,8 +504,13 @@ final class SSLSessionImpl extends ExtendedSSLSession { buf.get(b); this.preSharedKey = new SecretKeySpec(b, alg); // Get identity len - this.pskIdentity = new byte[buf.get()]; - buf.get(pskIdentity); + i = buf.get(); + if (i > 0) { + this.pskIdentity = new byte[buf.get()]; + buf.get(pskIdentity); + } else { + this.pskIdentity = null; + } break; default: throw new SSLException("Failed local certs of session."); @@ -715,14 +723,12 @@ void setPskIdentity(byte[] pskIdentity) { this.pskIdentity = pskIdentity; } - BigInteger incrTicketNonceCounter() { - BigInteger result = ticketNonceCounter; - ticketNonceCounter = ticketNonceCounter.add(BigInteger.ONE); - return result; + byte[] incrTicketNonceCounter() { + return new byte[] {ticketNonceCounter++}; } boolean isPSKable() { - return (ticketNonceCounter.compareTo(BigInteger.ZERO) > 0); + return (ticketNonceCounter > 0); } /** @@ -781,6 +787,10 @@ byte[] getPskIdentity() { return pskIdentity; } + public boolean isPSK() { + return (pskIdentity != null && pskIdentity.length > 0); + } + void setPeerCertificates(X509Certificate[] peer) { if (peerCerts == null) { peerCerts = peer; @@ -1230,7 +1240,6 @@ public void invalidate() { * sessions can be shared across different protection domains. */ private final ConcurrentHashMap boundValues; - boolean updateNST; /** * Assigns a session value. Session change events are given if diff --git a/src/java.base/share/classes/sun/security/ssl/SSLSocketImpl.java b/src/java.base/share/classes/sun/security/ssl/SSLSocketImpl.java index 9f22a5bb455c0..bec6d84484711 100644 --- a/src/java.base/share/classes/sun/security/ssl/SSLSocketImpl.java +++ b/src/java.base/share/classes/sun/security/ssl/SSLSocketImpl.java @@ -1321,7 +1321,6 @@ public void write(byte[] b, } // Check if NewSessionTicket PostHandshake message needs to be sent if (conContext.conSession.updateNST) { - conContext.conSession.updateNST = false; tryNewSessionTicket(); } } @@ -1556,15 +1555,17 @@ private void tryKeyUpdate() throws IOException { private void tryNewSessionTicket() throws IOException { // Don't bother to kickstart if handshaking is in progress, or if the // connection is not duplex-open. - if (!conContext.sslConfig.isClientMode && - conContext.protocolVersion.useTLS13PlusSpec() && - conContext.handshakeContext == null && - !conContext.isOutboundClosed() && - !conContext.isInboundClosed() && - !conContext.isBroken) { + if (SSLConfiguration.serverNewSessionTicketCount > 0 && + !conContext.sslConfig.isClientMode && + conContext.protocolVersion.useTLS13PlusSpec() && + conContext.handshakeContext == null && + !conContext.isOutboundClosed() && + !conContext.isInboundClosed() && + !conContext.isBroken) { if (SSLLogger.isOn && SSLLogger.isOn("ssl")) { SSLLogger.finest("trigger new session ticket"); } + conContext.conSession.updateNST = false; NewSessionTicket.t13PosthandshakeProducer.produce( new PostHandshakeContext(conContext)); } diff --git a/src/java.base/share/classes/sun/security/util/Cache.java b/src/java.base/share/classes/sun/security/util/Cache.java index 29dd19830c0ae..3d8350c1ecd76 100644 --- a/src/java.base/share/classes/sun/security/util/Cache.java +++ b/src/java.base/share/classes/sun/security/util/Cache.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 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 @@ -25,8 +25,12 @@ package sun.security.util; +import javax.net.ssl.SSLSession; +import java.lang.ref.ReferenceQueue; +import java.lang.ref.SoftReference; import java.util.*; -import java.lang.ref.*; +import java.util.concurrent.ConcurrentLinkedQueue; +import java.util.concurrent.atomic.AtomicInteger; /** * Abstract base class and factory for caches. A cache is a key-value mapping. @@ -90,6 +94,15 @@ protected Cache() { */ public abstract void put(K key, V value); + /** + * Add V to the cache with the option to use a QueueCacheEntry if the + * cache is configured for it. If the cache is not configured for a queue, + * V will silently add the entry directly. + */ + public void put(K key, V value, boolean canQueue) { + put(key, value); + } + /** * Get a value from the cache. */ @@ -137,6 +150,11 @@ public static Cache newSoftMemoryCache(int size, int timeout) { return new MemoryCache<>(true, size, timeout); } + public static Cache newSoftMemoryQueue(int size, int timeout, + int maxQueueSize) { + return new MemoryCache<>(true, size, timeout, maxQueueSize); + } + /** * Return a new memory cache with the specified maximum size, unlimited * lifetime for entries, with the values held by standard references. @@ -248,13 +266,12 @@ public void accept(CacheVisitor visitor) { class MemoryCache extends Cache { - private static final float LOAD_FACTOR = 0.75f; - - // XXXX + // Debugging private static final boolean DEBUG = false; private final Map> cacheMap; private int maxSize; + final private int maxQueueSize; private long lifetime; private long nextExpirationTime = Long.MAX_VALUE; @@ -263,18 +280,25 @@ class MemoryCache extends Cache { private final ReferenceQueue queue; public MemoryCache(boolean soft, int maxSize) { - this(soft, maxSize, 0); + this(soft, maxSize, 0, 0); } public MemoryCache(boolean soft, int maxSize, int lifetime) { + this(soft, maxSize, lifetime, 0); + } + + public MemoryCache(boolean soft, int maxSize, int lifetime, int qSize) { this.maxSize = maxSize; + this.maxQueueSize = qSize; this.lifetime = lifetime * 1000L; - if (soft) + if (soft) { this.queue = new ReferenceQueue<>(); - else + } else { this.queue = null; - - cacheMap = new LinkedHashMap<>(1, LOAD_FACTOR, true); + } + // LinkedHashMap is needed for its access order. 0.75f load factor is + // default. + cacheMap = new LinkedHashMap<>(1, 0.75f, true); } /** @@ -338,6 +362,10 @@ private void expungeExpiredEntries() { cnt++; } else if (nextExpirationTime > entry.getExpirationTime()) { nextExpirationTime = entry.getExpirationTime(); + // If this is a queue, check for some expired entries + if (entry instanceof QueueCacheEntry qe) { + qe.getQueue().removeIf(e -> !e.isValid(time)); + } } } if (DEBUG) { @@ -367,18 +395,60 @@ public synchronized void clear() { cacheMap.clear(); } - public synchronized void put(K key, V value) { + public void put(K key, V value) { + put(key, value, false); + } + + /** + * This puts an entry into the cacheMap. + * + * If canQueue is true, V will be added using a QueueCacheEntry which + * is added to cacheMap. If false, V is added to the cacheMap directly. + * The caller must keep a consistent canQueue value, mixing them can + * result in a queue being replaced with a single entry. + * + * This method is synchronized to avoid multiple QueueCacheEntry + * overwriting the same key. + * + * @param key key to the cacheMap + * @param value value to be stored + * @param canQueue can the value be put into a QueueCacheEntry + */ + public synchronized void put(K key, V value, boolean canQueue) { emptyQueue(); - long expirationTime = (lifetime == 0) ? 0 : - System.currentTimeMillis() + lifetime; + long expirationTime = + (lifetime == 0) ? 0 : System.currentTimeMillis() + lifetime; if (expirationTime < nextExpirationTime) { nextExpirationTime = expirationTime; } CacheEntry newEntry = newEntry(key, value, expirationTime, queue); - CacheEntry oldEntry = cacheMap.put(key, newEntry); - if (oldEntry != null) { - oldEntry.invalidate(); - return; + if (maxQueueSize == 0 || !canQueue) { + CacheEntry oldEntry = cacheMap.put(key, newEntry); + if (oldEntry != null) { + oldEntry.invalidate(); + } + } else { + CacheEntry entry = cacheMap.get(key); + switch (entry) { + case QueueCacheEntry qe -> { + qe.putValue(newEntry); + if (DEBUG) { + System.out.println("QueueCacheEntry= " + qe); + final AtomicInteger i = new AtomicInteger(1); + qe.queue.stream().forEach(e -> + System.out.println(i.getAndIncrement() + "= " + e)); + } + } + case null, default -> + cacheMap.put(key, new QueueCacheEntry<>(key, newEntry, + expirationTime, maxQueueSize)); + } + + if (DEBUG) { + System.out.println("Cache entry added: key=" + + key.toString() + ", class=" + + (entry != null ? entry.getClass().getName() : null)); + } } if (maxSize > 0 && cacheMap.size() > maxSize) { expungeExpiredEntries(); @@ -401,25 +471,37 @@ public synchronized V get(Object key) { if (entry == null) { return null; } - long time = (lifetime == 0) ? 0 : System.currentTimeMillis(); - if (!entry.isValid(time)) { + + if (lifetime > 0 && !entry.isValid(System.currentTimeMillis())) { + cacheMap.remove(key); if (DEBUG) { System.out.println("Ignoring expired entry"); } - cacheMap.remove(key); return null; } + + // If the value is a queue, return a queue entry. + if (entry instanceof QueueCacheEntry qe) { + V result = qe.getValue(lifetime); + if (qe.isEmpty()) { + removeImpl(key); + } + return result; + } return entry.getValue(); } public synchronized void remove(Object key) { emptyQueue(); + removeImpl(key); + } + + private void removeImpl(Object key) { CacheEntry entry = cacheMap.remove(key); if (entry != null) { entry.invalidate(); } } - public synchronized V pull(Object key) { emptyQueue(); CacheEntry entry = cacheMap.remove(key); @@ -550,9 +632,8 @@ public void invalidate() { } } - private static class SoftCacheEntry - extends SoftReference - implements CacheEntry { + private static class SoftCacheEntry extends SoftReference + implements CacheEntry { private K key; private long expirationTime; @@ -589,6 +670,116 @@ public void invalidate() { key = null; expirationTime = -1; } + + @Override + public String toString() { + if (get() instanceof SSLSession se) + return HexFormat.of().formatHex(se.getId()); + return super.toString(); + } } -} + /** + * This CacheEntry type allows multiple V entries to be stored in + * one key in the cacheMap. + * + * This implementation is need for TLS clients that receive multiple + * PSKs or NewSessionTickets for server resumption. + */ + private static class QueueCacheEntry implements CacheEntry { + + // Limit the number of queue entries. + private final int MAXQUEUESIZE; + + final boolean DEBUG = false; + private K key; + private long expirationTime; + final Queue> queue = new ConcurrentLinkedQueue<>(); + + QueueCacheEntry(K key, CacheEntry entry, long expirationTime, + int maxSize) { + this.key = key; + this.expirationTime = expirationTime; + this.MAXQUEUESIZE = maxSize; + queue.add(entry); + } + + public K getKey() { + return key; + } + + public V getValue() { + return getValue(0); + } + + public V getValue(long lifetime) { + long time = (lifetime == 0) ? 0 : System.currentTimeMillis(); + do { + var entry = queue.poll(); + if (entry == null) { + return null; + } + if (entry.isValid(time)) { + return entry.getValue(); + } + entry.invalidate(); + } while (!queue.isEmpty()); + + return null; + } + + public long getExpirationTime() { + return expirationTime; + } + + public void setExpirationTime(long time) { + expirationTime = time; + } + + public void putValue(CacheEntry entry) { + if (DEBUG) { + System.out.println("Added to queue (size=" + queue.size() + + "): " + entry.getKey().toString() + ", " + entry); + } + // Update the cache entry's expiration time to the latest entry. + // The getValue() calls will remove expired tickets. + expirationTime = entry.getExpirationTime(); + // Limit the number of queue entries, removing the oldest. + if (queue.size() >= MAXQUEUESIZE) { + queue.remove(); + } + queue.add(entry); + } + + public boolean isValid(long currentTime) { + boolean valid = (currentTime <= expirationTime) && !queue.isEmpty(); + if (!valid) { + invalidate(); + } + return valid; + } + + public boolean isValid() { + return isValid(System.currentTimeMillis()); + } + + public void invalidate() { + clear(); + key = null; + expirationTime = -1; + } + + public void clear() { + queue.forEach(CacheEntry::invalidate); + queue.clear(); + } + + public boolean isEmpty() { + return queue.isEmpty(); + } + + public Queue> getQueue() { + return queue; + } + } +} \ No newline at end of file diff --git a/src/java.base/share/classes/sun/util/locale/BaseLocale.java b/src/java.base/share/classes/sun/util/locale/BaseLocale.java index ec2a6a49183ca..a744b6ce39f59 100644 --- a/src/java.base/share/classes/sun/util/locale/BaseLocale.java +++ b/src/java.base/share/classes/sun/util/locale/BaseLocale.java @@ -38,7 +38,6 @@ import jdk.internal.vm.annotation.Stable; import java.util.StringJoiner; -import java.util.function.UnaryOperator; public final class BaseLocale { @@ -91,10 +90,6 @@ public final class BaseLocale { } } - // Interned BaseLocale cache - private static final ReferencedKeySet CACHE = - ReferencedKeySet.create(true, ReferencedKeySet.concurrentHashMapSupplier()); - public static final String SEP = "_"; private final String language; @@ -163,21 +158,16 @@ public static BaseLocale getInstance(String language, String script, // Obtain the "interned" BaseLocale from the cache. The returned // "interned" instance can subsequently be used by the Locale // instance which guarantees the locale components are properly cased/interned. - return CACHE.intern(new BaseLocale(language, script, region, variant), - // Avoid lambdas since this may be on the bootstrap path in many locales - INTERNER); - } - - public static final UnaryOperator INTERNER = new UnaryOperator<>() { - @Override - public BaseLocale apply(BaseLocale b) { - return new BaseLocale( - LocaleUtils.toLowerString(b.language).intern(), - LocaleUtils.toTitleString(b.script).intern(), - LocaleUtils.toUpperString(b.region).intern(), - b.variant.intern()); + class InterningCache { // TODO: StableValue + private static final ReferencedKeySet CACHE = + ReferencedKeySet.create(true, ReferencedKeySet.concurrentHashMapSupplier()); } - }; + return InterningCache.CACHE.intern(new BaseLocale( + language.intern(), // guaranteed to be lower-case + LocaleUtils.toTitleString(script).intern(), + region.intern(), // guaranteed to be upper-case + variant.intern())); + } public static String convertOldISOCodes(String language) { return switch (language) { diff --git a/src/java.base/share/man/java.1 b/src/java.base/share/man/java.1 index 133710abc25db..5896a07304375 100644 --- a/src/java.base/share/man/java.1 +++ b/src/java.base/share/man/java.1 @@ -552,15 +552,45 @@ of the release. Native access involves access to code or data outside the Java runtime. This is generally unsafe and, if done incorrectly, might crash the JVM or result in memory corruption. -Methods that provide native access are restricted, and by default their -use causes warnings. -This option allows code in the specified modules to use restricted -methods without warnings. -\f[I]module\f[R] can be \f[V]ALL-UNNAMED\f[R] to indicate code on the -class path. -When this option is present, any use of restricted methods by code -outside the specified modules causes an +Native access can occur as a result of calling a method that is either +\f[B]restricted\f[R] [https://openjdk.org/jeps/454#Safety], or +\f[V]native\f[R]. +This option allows code in the specified modules to perform native +access. +Native access occurring in a module that has not been explicitly enabled +is deemed \f[I]illegal\f[R]. +.RS +.PP +\f[I]module\f[R] can be a module name, or \f[V]ALL-UNNAMED\f[R] to +indicate code on the class path. +.RE +.TP +-\f[V]--illegal-native-access=\f[R]\f[I]parameter\f[R] +This option specifies a mode for how illegal native access is handled: +.RS +.RS +.PP +\f[B]Note:\f[R] This option will be removed in a future release. +.RE +.IP \[bu] 2 +\f[V]allow\f[R]: This mode allows illegal native access in all modules, +without any warings. +.IP \[bu] 2 +\f[V]warn\f[R]: This mode is identical to \f[V]allow\f[R] except that a +warning message is issued for the first illegal native access found in a +module. +This mode is the default for the current JDK but will change in a future +release. +.IP \[bu] 2 +\f[V]deny\f[R]: This mode disables illegal native access. +That is, any illegal native access causes an \f[V]IllegalCallerException\f[R]. +This mode will become the default in a future release. +.PP +To verify that your application is ready for a future version of the +JDK, run it with \f[V]--illegal-native-access=deny\f[R] along with any +necessary \f[V]--enable-native-access\f[R] options. +.RE .TP \f[V]--finalization=\f[R]\f[I]value\f[R] Controls whether the JVM performs finalization of objects. diff --git a/src/java.base/share/native/libzip/Inflater.c b/src/java.base/share/native/libzip/Inflater.c index a41e9775bfa02..1f43d3d1abf56 100644 --- a/src/java.base/share/native/libzip/Inflater.c +++ b/src/java.base/share/native/libzip/Inflater.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 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 @@ -49,8 +49,8 @@ JNIEXPORT void JNICALL Java_java_util_zip_Inflater_initIDs(JNIEnv *env, jclass cls) { inputConsumedID = (*env)->GetFieldID(env, cls, "inputConsumed", "I"); - outputConsumedID = (*env)->GetFieldID(env, cls, "outputConsumed", "I"); CHECK_NULL(inputConsumedID); + outputConsumedID = (*env)->GetFieldID(env, cls, "outputConsumed", "I"); CHECK_NULL(outputConsumedID); } diff --git a/src/java.base/unix/classes/sun/nio/ch/FileKey.java b/src/java.base/unix/classes/sun/nio/ch/FileKey.java index e60e63f073d22..119abe4a3b57a 100644 --- a/src/java.base/unix/classes/sun/nio/ch/FileKey.java +++ b/src/java.base/unix/classes/sun/nio/ch/FileKey.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 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 @@ -33,15 +33,18 @@ */ public class FileKey { - private long st_dev; // ID of device - private long st_ino; // Inode number + private final long st_dev; // ID of device + private final long st_ino; // Inode number - private FileKey() { } + private FileKey(long st_dev, long st_ino) { + this.st_dev = st_dev; + this.st_ino = st_ino; + } public static FileKey create(FileDescriptor fd) throws IOException { - FileKey fk = new FileKey(); - fk.init(fd); - return fk; + long finfo[] = new long[2]; + init(fd, finfo); + return new FileKey(finfo[0], finfo[1]); } @Override @@ -59,10 +62,10 @@ public boolean equals(Object obj) { && (this.st_ino == other.st_ino); } - private native void init(FileDescriptor fd) throws IOException; - private static native void initIDs(); + private static native void init(FileDescriptor fd, long[] finfo) + throws IOException; static { - initIDs(); + IOUtil.load(); } } diff --git a/src/java.base/unix/native/libnio/ch/FileKey.c b/src/java.base/unix/native/libnio/ch/FileKey.c index c3817003b5b16..59a866bcaff3a 100644 --- a/src/java.base/unix/native/libnio/ch/FileKey.c +++ b/src/java.base/unix/native/libnio/ch/FileKey.c @@ -30,29 +30,21 @@ #include "nio_util.h" #include "sun_nio_ch_FileKey.h" -static jfieldID key_st_dev; /* id for FileKey.st_dev */ -static jfieldID key_st_ino; /* id for FileKey.st_ino */ - - -JNIEXPORT void JNICALL -Java_sun_nio_ch_FileKey_initIDs(JNIEnv *env, jclass clazz) -{ - CHECK_NULL(key_st_dev = (*env)->GetFieldID(env, clazz, "st_dev", "J")); - CHECK_NULL(key_st_ino = (*env)->GetFieldID(env, clazz, "st_ino", "J")); -} - - JNIEXPORT void JNICALL -Java_sun_nio_ch_FileKey_init(JNIEnv *env, jobject this, jobject fdo) +Java_sun_nio_ch_FileKey_init(JNIEnv* env, jclass clazz, jobject fdo, + jlongArray finfo) { struct stat fbuf; int res; + jlong deviceAndInode[2]; - RESTARTABLE(fstat(fdval(env, fdo), &fbuf), res); + int fd = fdval(env, fdo); + RESTARTABLE(fstat(fd, &fbuf), res); if (res < 0) { JNU_ThrowIOExceptionWithLastError(env, "fstat failed"); } else { - (*env)->SetLongField(env, this, key_st_dev, (jlong)fbuf.st_dev); - (*env)->SetLongField(env, this, key_st_ino, (jlong)fbuf.st_ino); + deviceAndInode[0] = (jlong)fbuf.st_dev; + deviceAndInode[1] = (jlong)fbuf.st_ino; + (*env)->SetLongArrayRegion(env, finfo, 0, 2, deviceAndInode); } } diff --git a/src/java.base/unix/native/libnio/fs/UnixNativeDispatcher.c b/src/java.base/unix/native/libnio/fs/UnixNativeDispatcher.c index 13fe39c6551b9..b91ab6f0cab92 100644 --- a/src/java.base/unix/native/libnio/fs/UnixNativeDispatcher.c +++ b/src/java.base/unix/native/libnio/fs/UnixNativeDispatcher.c @@ -133,9 +133,10 @@ struct my_statx #define STATX_BTIME 0x00000800U #endif -#ifndef STATX_ALL -#define STATX_ALL (STATX_BTIME | STATX_BASIC_STATS) -#endif +// +// STATX_ALL is deprecated; use a different name to avoid confusion. +// +#define LOCAL_STATX_ALL (STATX_BASIC_STATS | STATX_BTIME) #ifndef AT_FDCWD #define AT_FDCWD -100 @@ -619,8 +620,19 @@ static void copy_statx_attributes(JNIEnv* env, struct my_statx* buf, jobject att (*env)->SetLongField(env, attrs, attrs_st_atime_sec, (jlong)buf->stx_atime.tv_sec); (*env)->SetLongField(env, attrs, attrs_st_mtime_sec, (jlong)buf->stx_mtime.tv_sec); (*env)->SetLongField(env, attrs, attrs_st_ctime_sec, (jlong)buf->stx_ctime.tv_sec); - (*env)->SetLongField(env, attrs, attrs_st_birthtime_sec, (jlong)buf->stx_btime.tv_sec); - (*env)->SetLongField(env, attrs, attrs_st_birthtime_nsec, (jlong)buf->stx_btime.tv_nsec); + if ((buf->stx_mask & STATX_BTIME) != 0) { + // Birth time was filled in so use it + (*env)->SetLongField(env, attrs, attrs_st_birthtime_sec, + (jlong)buf->stx_btime.tv_sec); + (*env)->SetLongField(env, attrs, attrs_st_birthtime_nsec, + (jlong)buf->stx_btime.tv_nsec); + } else { + // Birth time was not filled in: fall back to last modification time + (*env)->SetLongField(env, attrs, attrs_st_birthtime_sec, + (jlong)buf->stx_mtime.tv_sec); + (*env)->SetLongField(env, attrs, attrs_st_birthtime_nsec, + (jlong)buf->stx_mtime.tv_nsec); + } (*env)->SetLongField(env, attrs, attrs_st_atime_nsec, (jlong)buf->stx_atime.tv_nsec); (*env)->SetLongField(env, attrs, attrs_st_mtime_nsec, (jlong)buf->stx_mtime.tv_nsec); (*env)->SetLongField(env, attrs, attrs_st_ctime_nsec, (jlong)buf->stx_ctime.tv_nsec); @@ -674,7 +686,7 @@ Java_sun_nio_fs_UnixNativeDispatcher_stat0(JNIEnv* env, jclass this, #if defined(__linux__) struct my_statx statx_buf; int flags = AT_STATX_SYNC_AS_STAT; - unsigned int mask = STATX_ALL; + unsigned int mask = LOCAL_STATX_ALL; if (my_statx_func != NULL) { // Prefer statx over stat on Linux if it's available @@ -706,7 +718,7 @@ Java_sun_nio_fs_UnixNativeDispatcher_lstat0(JNIEnv* env, jclass this, #if defined(__linux__) struct my_statx statx_buf; int flags = AT_STATX_SYNC_AS_STAT | AT_SYMLINK_NOFOLLOW; - unsigned int mask = STATX_ALL; + unsigned int mask = LOCAL_STATX_ALL; if (my_statx_func != NULL) { // Prefer statx over stat on Linux if it's available @@ -737,7 +749,7 @@ Java_sun_nio_fs_UnixNativeDispatcher_fstat0(JNIEnv* env, jclass this, jint fd, #if defined(__linux__) struct my_statx statx_buf; int flags = AT_EMPTY_PATH | AT_STATX_SYNC_AS_STAT; - unsigned int mask = STATX_ALL; + unsigned int mask = LOCAL_STATX_ALL; if (my_statx_func != NULL) { // statx supports FD use via dirfd iff pathname is an empty string and the @@ -770,7 +782,7 @@ Java_sun_nio_fs_UnixNativeDispatcher_fstatat0(JNIEnv* env, jclass this, jint dfd #if defined(__linux__) struct my_statx statx_buf; int flags = AT_STATX_SYNC_AS_STAT; - unsigned int mask = STATX_ALL; + unsigned int mask = LOCAL_STATX_ALL; if (my_statx_func != NULL) { // Prefer statx over stat on Linux if it's available diff --git a/src/java.base/windows/classes/sun/nio/ch/FileKey.java b/src/java.base/windows/classes/sun/nio/ch/FileKey.java index 8669517f0c581..a900c382e6895 100644 --- a/src/java.base/windows/classes/sun/nio/ch/FileKey.java +++ b/src/java.base/windows/classes/sun/nio/ch/FileKey.java @@ -33,16 +33,21 @@ */ public class FileKey { - private int dwVolumeSerialNumber; - private int nFileIndexHigh; - private int nFileIndexLow; + private final int dwVolumeSerialNumber; + private final int nFileIndexHigh; + private final int nFileIndexLow; - private FileKey() { } + private FileKey(int dwVolumeSerialNumber, int nFileIndexHigh, + int nFileIndexLow) { + this.dwVolumeSerialNumber = dwVolumeSerialNumber; + this.nFileIndexHigh = nFileIndexHigh; + this.nFileIndexLow = nFileIndexLow; + } public static FileKey create(FileDescriptor fd) throws IOException { - FileKey fk = new FileKey(); - fk.init(fd); - return fk; + int finfo[] = new int[3]; + init(fd, finfo); + return new FileKey(finfo[0], finfo[1], finfo[2]); } @Override @@ -60,11 +65,10 @@ public boolean equals(Object obj) { && this.nFileIndexLow == other.nFileIndexLow; } - private native void init(FileDescriptor fd) throws IOException; - private static native void initIDs(); + private static native void init(FileDescriptor fd, int[] finfo) + throws IOException; static { IOUtil.load(); - initIDs(); } } diff --git a/src/java.base/windows/native/libjli/cmdtoargs.c b/src/java.base/windows/native/libjli/cmdtoargs.c index 548e70b9bbf7e..27a28b4cd450e 100644 --- a/src/java.base/windows/native/libjli/cmdtoargs.c +++ b/src/java.base/windows/native/libjli/cmdtoargs.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 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 @@ -328,7 +328,7 @@ class Vector { printf("*** cannot allocate memory\n"); doabort(); } - _snprintf(cptr, MAX_PATH, "\"%s\" %s", argv[0], cmdline); + snprintf(cptr, MAX_PATH, "\"%s\" %s", argv[0], cmdline); JLI_CmdToArgs(cptr); free(cptr); StdArg *kargv = JLI_GetStdArgs(); diff --git a/src/java.base/windows/native/libnio/ch/FileKey.c b/src/java.base/windows/native/libnio/ch/FileKey.c index 9cd3459aef861..e552ed6b7ae2a 100644 --- a/src/java.base/windows/native/libnio/ch/FileKey.c +++ b/src/java.base/windows/native/libnio/ch/FileKey.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 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 @@ -30,32 +30,20 @@ #include "nio_util.h" #include "sun_nio_ch_FileKey.h" -static jfieldID key_volumeSN; /* id for FileKey.dwVolumeSerialNumber */ -static jfieldID key_indexHigh; /* id for FileKey.nFileIndexHigh */ -static jfieldID key_indexLow; /* id for FileKey.nFileIndexLow */ - - -JNIEXPORT void JNICALL -Java_sun_nio_ch_FileKey_initIDs(JNIEnv *env, jclass clazz) -{ - CHECK_NULL(key_volumeSN = (*env)->GetFieldID(env, clazz, "dwVolumeSerialNumber", "I")); - CHECK_NULL(key_indexHigh = (*env)->GetFieldID(env, clazz, "nFileIndexHigh", "I")); - CHECK_NULL(key_indexLow = (*env)->GetFieldID(env, clazz, "nFileIndexLow", "I")); -} - - JNIEXPORT void JNICALL -Java_sun_nio_ch_FileKey_init(JNIEnv *env, jobject this, jobject fdo) +Java_sun_nio_ch_FileKey_init(JNIEnv *env, jclass clazz, jobject fdo, jintArray finfo) { - HANDLE fileHandle = (HANDLE)(handleval(env, fdo)); + HANDLE fileHandle = (HANDLE)handleval(env, fdo); BOOL result; BY_HANDLE_FILE_INFORMATION fileInfo; + jint info[3]; result = GetFileInformationByHandle(fileHandle, &fileInfo); if (result) { - (*env)->SetIntField(env, this, key_volumeSN, fileInfo.dwVolumeSerialNumber); - (*env)->SetIntField(env, this, key_indexHigh, fileInfo.nFileIndexHigh); - (*env)->SetIntField(env, this, key_indexLow, fileInfo.nFileIndexLow); + info[0] = (jint)fileInfo.dwVolumeSerialNumber; + info[1] = (jint)fileInfo.nFileIndexHigh; + info[2] = (jint)fileInfo.nFileIndexLow; + (*env)->SetIntArrayRegion(env, finfo, 0, 3, info); } else { JNU_ThrowIOExceptionWithLastError(env, "GetFileInformationByHandle failed"); } diff --git a/src/java.compiler/share/classes/javax/annotation/processing/Filer.java b/src/java.compiler/share/classes/javax/annotation/processing/Filer.java index 61af2aae0c7a5..ba9b7ed60ecab 100644 --- a/src/java.compiler/share/classes/javax/annotation/processing/Filer.java +++ b/src/java.compiler/share/classes/javax/annotation/processing/Filer.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 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 @@ -25,10 +25,8 @@ package javax.annotation.processing; -import javax.tools.JavaFileManager; import javax.tools.*; import javax.lang.model.element.Element; -import javax.lang.model.element.TypeElement; import javax.lang.model.util.Elements; import java.io.IOException; diff --git a/src/java.compiler/share/classes/javax/lang/model/SourceVersion.java b/src/java.compiler/share/classes/javax/lang/model/SourceVersion.java index fd3cb1cb0f8ea..4e32f0cdcd88e 100644 --- a/src/java.compiler/share/classes/javax/lang/model/SourceVersion.java +++ b/src/java.compiler/share/classes/javax/lang/model/SourceVersion.java @@ -25,10 +25,6 @@ package javax.lang.model; -import java.util.Collections; -import java.util.Set; -import java.util.HashSet; - /** * Source versions of the Java programming language. * diff --git a/src/java.compiler/share/classes/javax/lang/model/element/Element.java b/src/java.compiler/share/classes/javax/lang/model/element/Element.java index 59866114325ae..129dad29020ed 100644 --- a/src/java.compiler/share/classes/javax/lang/model/element/Element.java +++ b/src/java.compiler/share/classes/javax/lang/model/element/Element.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 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 @@ -27,8 +27,6 @@ import java.lang.annotation.Annotation; -import java.lang.annotation.AnnotationTypeMismatchException; -import java.lang.annotation.IncompleteAnnotationException; import java.util.List; import java.util.Set; diff --git a/src/java.compiler/share/classes/javax/lang/model/element/TypeElement.java b/src/java.compiler/share/classes/javax/lang/model/element/TypeElement.java index a8c3b91f8b504..3f34b1799929d 100644 --- a/src/java.compiler/share/classes/javax/lang/model/element/TypeElement.java +++ b/src/java.compiler/share/classes/javax/lang/model/element/TypeElement.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 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 @@ -25,8 +25,6 @@ package javax.lang.model.element; -import jdk.internal.javac.PreviewFeature; - import java.util.List; import javax.lang.model.type.*; import javax.lang.model.util.*; diff --git a/src/java.compiler/share/classes/javax/lang/model/element/VariableElement.java b/src/java.compiler/share/classes/javax/lang/model/element/VariableElement.java index 07e8c25b8f77f..4d2b2582901f8 100644 --- a/src/java.compiler/share/classes/javax/lang/model/element/VariableElement.java +++ b/src/java.compiler/share/classes/javax/lang/model/element/VariableElement.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 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 @@ -25,8 +25,6 @@ package javax.lang.model.element; -import jdk.internal.javac.PreviewFeature; - import javax.lang.model.util.Elements; import javax.lang.model.type.TypeMirror; import javax.lang.model.type.TypeKind; diff --git a/src/java.compiler/share/classes/javax/lang/model/type/TypeVariable.java b/src/java.compiler/share/classes/javax/lang/model/type/TypeVariable.java index e5ab0458f693a..abea88fb6f263 100644 --- a/src/java.compiler/share/classes/javax/lang/model/type/TypeVariable.java +++ b/src/java.compiler/share/classes/javax/lang/model/type/TypeVariable.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 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 @@ -28,8 +28,6 @@ import javax.lang.model.element.Element; import javax.lang.model.element.TypeParameterElement; -import javax.lang.model.util.Types; - /** * Represents a type variable. diff --git a/src/java.compiler/share/classes/javax/lang/model/type/TypeVisitor.java b/src/java.compiler/share/classes/javax/lang/model/type/TypeVisitor.java index 31d75fe792940..f3f76803e8f43 100644 --- a/src/java.compiler/share/classes/javax/lang/model/type/TypeVisitor.java +++ b/src/java.compiler/share/classes/javax/lang/model/type/TypeVisitor.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 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 @@ -25,7 +25,6 @@ package javax.lang.model.type; -import javax.lang.model.element.*; import javax.lang.model.util.*; /** diff --git a/src/java.compiler/share/classes/javax/lang/model/util/AbstractAnnotationValueVisitorPreview.java b/src/java.compiler/share/classes/javax/lang/model/util/AbstractAnnotationValueVisitorPreview.java index fed666eb32f44..724ebe593790c 100644 --- a/src/java.compiler/share/classes/javax/lang/model/util/AbstractAnnotationValueVisitorPreview.java +++ b/src/java.compiler/share/classes/javax/lang/model/util/AbstractAnnotationValueVisitorPreview.java @@ -28,7 +28,6 @@ import jdk.internal.javac.PreviewFeature; import static javax.lang.model.SourceVersion.*; -import javax.lang.model.SourceVersion; import javax.annotation.processing.SupportedSourceVersion; import javax.annotation.processing.ProcessingEnvironment; diff --git a/src/java.compiler/share/classes/javax/lang/model/util/AbstractElementVisitorPreview.java b/src/java.compiler/share/classes/javax/lang/model/util/AbstractElementVisitorPreview.java index 66a62b7fcb69c..7297e7c0c7b26 100644 --- a/src/java.compiler/share/classes/javax/lang/model/util/AbstractElementVisitorPreview.java +++ b/src/java.compiler/share/classes/javax/lang/model/util/AbstractElementVisitorPreview.java @@ -29,9 +29,6 @@ import javax.annotation.processing.SupportedSourceVersion; import javax.annotation.processing.ProcessingEnvironment; -import javax.lang.model.SourceVersion; -import javax.lang.model.element.ElementVisitor; -import javax.lang.model.element.RecordComponentElement; import static javax.lang.model.SourceVersion.*; /** diff --git a/src/java.compiler/share/classes/javax/lang/model/util/AbstractTypeVisitor9.java b/src/java.compiler/share/classes/javax/lang/model/util/AbstractTypeVisitor9.java index b5b9cfb23b0fc..f802c3bf1b99f 100644 --- a/src/java.compiler/share/classes/javax/lang/model/util/AbstractTypeVisitor9.java +++ b/src/java.compiler/share/classes/javax/lang/model/util/AbstractTypeVisitor9.java @@ -26,7 +26,6 @@ package javax.lang.model.util; import javax.annotation.processing.SupportedSourceVersion; -import javax.lang.model.type.*; import javax.lang.model.SourceVersion; import static javax.lang.model.SourceVersion.*; diff --git a/src/java.compiler/share/classes/javax/lang/model/util/AbstractTypeVisitorPreview.java b/src/java.compiler/share/classes/javax/lang/model/util/AbstractTypeVisitorPreview.java index c066f1c2f6f4f..823bad0748acd 100644 --- a/src/java.compiler/share/classes/javax/lang/model/util/AbstractTypeVisitorPreview.java +++ b/src/java.compiler/share/classes/javax/lang/model/util/AbstractTypeVisitorPreview.java @@ -29,7 +29,6 @@ import javax.annotation.processing.SupportedSourceVersion; import javax.annotation.processing.ProcessingEnvironment; -import javax.lang.model.SourceVersion; import static javax.lang.model.SourceVersion.*; /** diff --git a/src/java.compiler/share/classes/javax/lang/model/util/ElementKindVisitor6.java b/src/java.compiler/share/classes/javax/lang/model/util/ElementKindVisitor6.java index 41ad8ffe218fb..764f4e327372c 100644 --- a/src/java.compiler/share/classes/javax/lang/model/util/ElementKindVisitor6.java +++ b/src/java.compiler/share/classes/javax/lang/model/util/ElementKindVisitor6.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 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 @@ -28,7 +28,6 @@ import javax.lang.model.element.*; import javax.annotation.processing.SupportedSourceVersion; import javax.lang.model.SourceVersion; -import javax.lang.model.element.ElementVisitor; import static javax.lang.model.element.ElementKind.*; import static javax.lang.model.SourceVersion.*; diff --git a/src/java.compiler/share/classes/javax/lang/model/util/ElementKindVisitor9.java b/src/java.compiler/share/classes/javax/lang/model/util/ElementKindVisitor9.java index 4197f53940839..89dcb1f51f33b 100644 --- a/src/java.compiler/share/classes/javax/lang/model/util/ElementKindVisitor9.java +++ b/src/java.compiler/share/classes/javax/lang/model/util/ElementKindVisitor9.java @@ -28,7 +28,6 @@ import javax.lang.model.element.*; import javax.annotation.processing.SupportedSourceVersion; import javax.lang.model.SourceVersion; -import javax.lang.model.element.ElementVisitor; import static javax.lang.model.SourceVersion.*; /** diff --git a/src/java.compiler/share/classes/javax/lang/model/util/ElementKindVisitorPreview.java b/src/java.compiler/share/classes/javax/lang/model/util/ElementKindVisitorPreview.java index 7c3a1166e317b..71d5f15fc85b9 100644 --- a/src/java.compiler/share/classes/javax/lang/model/util/ElementKindVisitorPreview.java +++ b/src/java.compiler/share/classes/javax/lang/model/util/ElementKindVisitorPreview.java @@ -30,7 +30,6 @@ import javax.annotation.processing.SupportedSourceVersion; import javax.annotation.processing.ProcessingEnvironment; import javax.lang.model.element.*; -import javax.lang.model.SourceVersion; import static javax.lang.model.SourceVersion.*; /** diff --git a/src/java.compiler/share/classes/javax/lang/model/util/ElementScanner14.java b/src/java.compiler/share/classes/javax/lang/model/util/ElementScanner14.java index 03a69516b514f..2f6fb0e03a0d7 100644 --- a/src/java.compiler/share/classes/javax/lang/model/util/ElementScanner14.java +++ b/src/java.compiler/share/classes/javax/lang/model/util/ElementScanner14.java @@ -30,7 +30,6 @@ import javax.lang.model.element.*; import javax.annotation.processing.SupportedSourceVersion; import javax.lang.model.SourceVersion; -import javax.lang.model.element.ElementVisitor; import static javax.lang.model.SourceVersion.*; /** diff --git a/src/java.compiler/share/classes/javax/lang/model/util/ElementScanner6.java b/src/java.compiler/share/classes/javax/lang/model/util/ElementScanner6.java index c5bde23b47e1f..bff95313508dd 100644 --- a/src/java.compiler/share/classes/javax/lang/model/util/ElementScanner6.java +++ b/src/java.compiler/share/classes/javax/lang/model/util/ElementScanner6.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 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 @@ -27,7 +27,6 @@ import javax.lang.model.element.*; import javax.annotation.processing.SupportedSourceVersion; -import javax.lang.model.element.ElementVisitor; import javax.lang.model.SourceVersion; import static javax.lang.model.SourceVersion.*; diff --git a/src/java.compiler/share/classes/javax/lang/model/util/ElementScanner7.java b/src/java.compiler/share/classes/javax/lang/model/util/ElementScanner7.java index 51c78c60067b5..be7fa9908b6bb 100644 --- a/src/java.compiler/share/classes/javax/lang/model/util/ElementScanner7.java +++ b/src/java.compiler/share/classes/javax/lang/model/util/ElementScanner7.java @@ -28,7 +28,6 @@ import javax.lang.model.element.*; import javax.annotation.processing.SupportedSourceVersion; import javax.lang.model.SourceVersion; -import javax.lang.model.element.ElementVisitor; import static javax.lang.model.SourceVersion.*; diff --git a/src/java.compiler/share/classes/javax/lang/model/util/ElementScanner9.java b/src/java.compiler/share/classes/javax/lang/model/util/ElementScanner9.java index a9a66d6c18566..d572181b32c73 100644 --- a/src/java.compiler/share/classes/javax/lang/model/util/ElementScanner9.java +++ b/src/java.compiler/share/classes/javax/lang/model/util/ElementScanner9.java @@ -28,7 +28,6 @@ import javax.lang.model.element.*; import javax.annotation.processing.SupportedSourceVersion; import javax.lang.model.SourceVersion; -import javax.lang.model.element.ElementVisitor; import static javax.lang.model.SourceVersion.*; diff --git a/src/java.compiler/share/classes/javax/lang/model/util/ElementScannerPreview.java b/src/java.compiler/share/classes/javax/lang/model/util/ElementScannerPreview.java index 6e21554132a7b..85c30afcf2bc2 100644 --- a/src/java.compiler/share/classes/javax/lang/model/util/ElementScannerPreview.java +++ b/src/java.compiler/share/classes/javax/lang/model/util/ElementScannerPreview.java @@ -27,13 +27,9 @@ import jdk.internal.javac.PreviewFeature; -import java.util.List; -import java.util.ArrayList; import javax.annotation.processing.SupportedSourceVersion; import javax.annotation.processing.ProcessingEnvironment; import javax.lang.model.element.*; -import javax.lang.model.SourceVersion; -import javax.lang.model.element.ElementVisitor; import static javax.lang.model.SourceVersion.*; /** diff --git a/src/java.compiler/share/classes/javax/lang/model/util/SimpleAnnotationValueVisitorPreview.java b/src/java.compiler/share/classes/javax/lang/model/util/SimpleAnnotationValueVisitorPreview.java index 48182072416c6..c0444c91060a2 100644 --- a/src/java.compiler/share/classes/javax/lang/model/util/SimpleAnnotationValueVisitorPreview.java +++ b/src/java.compiler/share/classes/javax/lang/model/util/SimpleAnnotationValueVisitorPreview.java @@ -29,7 +29,6 @@ import javax.annotation.processing.SupportedSourceVersion; import javax.annotation.processing.ProcessingEnvironment; -import javax.lang.model.SourceVersion; import static javax.lang.model.SourceVersion.*; /** diff --git a/src/java.compiler/share/classes/javax/lang/model/util/SimpleElementVisitor6.java b/src/java.compiler/share/classes/javax/lang/model/util/SimpleElementVisitor6.java index 2e8e27eeff00a..c28b13d4992cb 100644 --- a/src/java.compiler/share/classes/javax/lang/model/util/SimpleElementVisitor6.java +++ b/src/java.compiler/share/classes/javax/lang/model/util/SimpleElementVisitor6.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 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 @@ -28,7 +28,6 @@ import javax.lang.model.element.*; import javax.annotation.processing.SupportedSourceVersion; import javax.lang.model.SourceVersion; -import javax.lang.model.element.ElementVisitor; import static javax.lang.model.SourceVersion.*; diff --git a/src/java.compiler/share/classes/javax/lang/model/util/SimpleElementVisitor7.java b/src/java.compiler/share/classes/javax/lang/model/util/SimpleElementVisitor7.java index fcd26dda60d00..3c71f97b67543 100644 --- a/src/java.compiler/share/classes/javax/lang/model/util/SimpleElementVisitor7.java +++ b/src/java.compiler/share/classes/javax/lang/model/util/SimpleElementVisitor7.java @@ -28,7 +28,6 @@ import javax.lang.model.element.*; import javax.annotation.processing.SupportedSourceVersion; import javax.lang.model.SourceVersion; -import javax.lang.model.element.ElementVisitor; import static javax.lang.model.SourceVersion.*; /** diff --git a/src/java.compiler/share/classes/javax/lang/model/util/SimpleElementVisitorPreview.java b/src/java.compiler/share/classes/javax/lang/model/util/SimpleElementVisitorPreview.java index 6acc8f2da48a3..79da686ee0869 100644 --- a/src/java.compiler/share/classes/javax/lang/model/util/SimpleElementVisitorPreview.java +++ b/src/java.compiler/share/classes/javax/lang/model/util/SimpleElementVisitorPreview.java @@ -29,9 +29,6 @@ import javax.annotation.processing.SupportedSourceVersion; import javax.annotation.processing.ProcessingEnvironment; -import javax.lang.model.SourceVersion; -import javax.lang.model.element.ElementVisitor; -import javax.lang.model.element.RecordComponentElement; import static javax.lang.model.SourceVersion.*; /** diff --git a/src/java.compiler/share/classes/javax/lang/model/util/SimpleTypeVisitor6.java b/src/java.compiler/share/classes/javax/lang/model/util/SimpleTypeVisitor6.java index ce6321d9fd3fa..9386c02731600 100644 --- a/src/java.compiler/share/classes/javax/lang/model/util/SimpleTypeVisitor6.java +++ b/src/java.compiler/share/classes/javax/lang/model/util/SimpleTypeVisitor6.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 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 @@ -29,7 +29,6 @@ import javax.annotation.processing.SupportedSourceVersion; import javax.lang.model.SourceVersion; import static javax.lang.model.SourceVersion.*; -import javax.lang.model.type.TypeVisitor; /** diff --git a/src/java.compiler/share/classes/javax/lang/model/util/SimpleTypeVisitor7.java b/src/java.compiler/share/classes/javax/lang/model/util/SimpleTypeVisitor7.java index f47314aeeb24c..c550a76e4b6cd 100644 --- a/src/java.compiler/share/classes/javax/lang/model/util/SimpleTypeVisitor7.java +++ b/src/java.compiler/share/classes/javax/lang/model/util/SimpleTypeVisitor7.java @@ -29,7 +29,6 @@ import javax.annotation.processing.SupportedSourceVersion; import javax.lang.model.SourceVersion; import static javax.lang.model.SourceVersion.*; -import javax.lang.model.type.TypeVisitor; /** * A simple visitor of types with default behavior appropriate for the diff --git a/src/java.compiler/share/classes/javax/lang/model/util/SimpleTypeVisitor9.java b/src/java.compiler/share/classes/javax/lang/model/util/SimpleTypeVisitor9.java index 8f97b34d547bf..32174be9949bd 100644 --- a/src/java.compiler/share/classes/javax/lang/model/util/SimpleTypeVisitor9.java +++ b/src/java.compiler/share/classes/javax/lang/model/util/SimpleTypeVisitor9.java @@ -27,7 +27,6 @@ import javax.annotation.processing.SupportedSourceVersion; import javax.lang.model.SourceVersion; -import javax.lang.model.type.IntersectionType; import static javax.lang.model.SourceVersion.*; /** diff --git a/src/java.compiler/share/classes/javax/lang/model/util/SimpleTypeVisitorPreview.java b/src/java.compiler/share/classes/javax/lang/model/util/SimpleTypeVisitorPreview.java index a058f42937a65..1efbe7108370c 100644 --- a/src/java.compiler/share/classes/javax/lang/model/util/SimpleTypeVisitorPreview.java +++ b/src/java.compiler/share/classes/javax/lang/model/util/SimpleTypeVisitorPreview.java @@ -29,7 +29,6 @@ import javax.annotation.processing.SupportedSourceVersion; import javax.annotation.processing.ProcessingEnvironment; -import javax.lang.model.SourceVersion; import static javax.lang.model.SourceVersion.*; /** diff --git a/src/java.compiler/share/classes/javax/lang/model/util/TypeKindVisitorPreview.java b/src/java.compiler/share/classes/javax/lang/model/util/TypeKindVisitorPreview.java index 703ef744edc20..70e0498f5658b 100644 --- a/src/java.compiler/share/classes/javax/lang/model/util/TypeKindVisitorPreview.java +++ b/src/java.compiler/share/classes/javax/lang/model/util/TypeKindVisitorPreview.java @@ -29,7 +29,6 @@ import javax.annotation.processing.SupportedSourceVersion; import javax.annotation.processing.ProcessingEnvironment; -import javax.lang.model.SourceVersion; import javax.lang.model.type.*; import static javax.lang.model.SourceVersion.*; diff --git a/src/java.compiler/share/classes/javax/lang/model/util/Types.java b/src/java.compiler/share/classes/javax/lang/model/util/Types.java index f6296050ca9f5..0cea2734e213c 100644 --- a/src/java.compiler/share/classes/javax/lang/model/util/Types.java +++ b/src/java.compiler/share/classes/javax/lang/model/util/Types.java @@ -25,9 +25,6 @@ package javax.lang.model.util; -import java.lang.annotation.Annotation; -import java.lang.annotation.AnnotationTypeMismatchException; -import java.lang.annotation.IncompleteAnnotationException; import java.util.List; import javax.lang.model.element.*; import javax.lang.model.type.*; diff --git a/src/java.datatransfer/share/classes/java/awt/datatransfer/SystemFlavorMap.java b/src/java.datatransfer/share/classes/java/awt/datatransfer/SystemFlavorMap.java index d481465138b47..6b2dc14c05fc1 100644 --- a/src/java.datatransfer/share/classes/java/awt/datatransfer/SystemFlavorMap.java +++ b/src/java.datatransfer/share/classes/java/awt/datatransfer/SystemFlavorMap.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 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 @@ -61,8 +61,6 @@ public final class SystemFlavorMap implements FlavorMap, FlavorTable { */ private static String JavaMIME = "JAVA_DATAFLAVOR:"; - private static final Object FLAVOR_MAP_KEY = new Object(); - /** * The list of valid, decoded text flavor representation classes, in order * from best to worst. diff --git a/src/java.desktop/macosx/classes/com/apple/eio/FileManager.java b/src/java.desktop/macosx/classes/com/apple/eio/FileManager.java index 8967a99f15e39..1a77ddd760049 100644 --- a/src/java.desktop/macosx/classes/com/apple/eio/FileManager.java +++ b/src/java.desktop/macosx/classes/com/apple/eio/FileManager.java @@ -58,7 +58,7 @@ public class FileManager { loadOSXLibrary(); } - @SuppressWarnings("removal") + @SuppressWarnings({"removal", "restricted"}) private static void loadOSXLibrary() { java.security.AccessController.doPrivileged( new java.security.PrivilegedAction() { diff --git a/src/java.desktop/macosx/classes/com/apple/laf/AquaFileView.java b/src/java.desktop/macosx/classes/com/apple/laf/AquaFileView.java index 4177e32f63d81..34e5b7c9b7c87 100644 --- a/src/java.desktop/macosx/classes/com/apple/laf/AquaFileView.java +++ b/src/java.desktop/macosx/classes/com/apple/laf/AquaFileView.java @@ -65,7 +65,7 @@ class AquaFileView extends FileView { loadOSXUILibrary(); } - @SuppressWarnings("removal") + @SuppressWarnings({"removal", "restricted"}) private static void loadOSXUILibrary() { java.security.AccessController.doPrivileged( new java.security.PrivilegedAction() { diff --git a/src/java.desktop/macosx/classes/com/apple/laf/AquaKeyBindings.java b/src/java.desktop/macosx/classes/com/apple/laf/AquaKeyBindings.java index d64ac90e9ac7f..60bb3da9f87db 100644 --- a/src/java.desktop/macosx/classes/com/apple/laf/AquaKeyBindings.java +++ b/src/java.desktop/macosx/classes/com/apple/laf/AquaKeyBindings.java @@ -388,7 +388,9 @@ LateBoundInputMap getTableInputMap() { "alt shift TAB", "focusHeader", "F8", "focusHeader", "ctrl shift UP", "selectFirstRowExtendSelection", - "ctrl shift DOWN", "selectLastRowExtendSelection" + "ctrl shift DOWN", "selectLastRowExtendSelection", + "ctrl shift RIGHT", "selectLastColumnExtendSelection", + "ctrl shift LEFT", "selectFirstColumnExtendSelection" })); } diff --git a/src/java.desktop/macosx/classes/com/apple/laf/AquaLookAndFeel.java b/src/java.desktop/macosx/classes/com/apple/laf/AquaLookAndFeel.java index 83604e5d835cd..9748f9008272f 100644 --- a/src/java.desktop/macosx/classes/com/apple/laf/AquaLookAndFeel.java +++ b/src/java.desktop/macosx/classes/com/apple/laf/AquaLookAndFeel.java @@ -154,7 +154,7 @@ public boolean isSupportedLookAndFeel() { * @see #uninitialize * @see UIManager#setLookAndFeel */ - @SuppressWarnings("removal") + @SuppressWarnings({"removal", "restricted"}) public void initialize() { java.security.AccessController.doPrivileged(new PrivilegedAction() { public Void run() { diff --git a/src/java.desktop/macosx/classes/com/apple/laf/AquaMenuBarUI.java b/src/java.desktop/macosx/classes/com/apple/laf/AquaMenuBarUI.java index 5d6b15671775d..f252e310750c7 100644 --- a/src/java.desktop/macosx/classes/com/apple/laf/AquaMenuBarUI.java +++ b/src/java.desktop/macosx/classes/com/apple/laf/AquaMenuBarUI.java @@ -41,7 +41,7 @@ import sun.security.action.GetBooleanAction; // MenuBar implementation for Mac L&F -@SuppressWarnings("removal") +@SuppressWarnings({"removal", "restricted"}) public class AquaMenuBarUI extends BasicMenuBarUI implements ScreenMenuBarProvider { static { diff --git a/src/java.desktop/macosx/classes/com/apple/laf/AquaNativeResources.java b/src/java.desktop/macosx/classes/com/apple/laf/AquaNativeResources.java index 3e31eca43d0e3..a8abf1a6cd8d0 100644 --- a/src/java.desktop/macosx/classes/com/apple/laf/AquaNativeResources.java +++ b/src/java.desktop/macosx/classes/com/apple/laf/AquaNativeResources.java @@ -32,7 +32,7 @@ import com.apple.laf.AquaUtils.RecyclableSingleton; -@SuppressWarnings("removal") +@SuppressWarnings({"removal", "restricted"}) public class AquaNativeResources { static { java.security.AccessController.doPrivileged( diff --git a/src/java.desktop/macosx/classes/com/apple/laf/ScreenMenu.java b/src/java.desktop/macosx/classes/com/apple/laf/ScreenMenu.java index b3ec61b5c7913..d8d0928c55fcf 100644 --- a/src/java.desktop/macosx/classes/com/apple/laf/ScreenMenu.java +++ b/src/java.desktop/macosx/classes/com/apple/laf/ScreenMenu.java @@ -45,7 +45,7 @@ final class ScreenMenu extends Menu loadAWTLibrary(); } - @SuppressWarnings("removal") + @SuppressWarnings({"removal", "restricted"}) private static void loadAWTLibrary() { java.security.AccessController.doPrivileged( new java.security.PrivilegedAction() { diff --git a/src/java.desktop/macosx/classes/sun/awt/PlatformGraphicsInfo.java b/src/java.desktop/macosx/classes/sun/awt/PlatformGraphicsInfo.java index 796dee199ad01..6af002fc04f70 100644 --- a/src/java.desktop/macosx/classes/sun/awt/PlatformGraphicsInfo.java +++ b/src/java.desktop/macosx/classes/sun/awt/PlatformGraphicsInfo.java @@ -30,7 +30,7 @@ import java.security.AccessController; import java.security.PrivilegedAction; -@SuppressWarnings("removal") +@SuppressWarnings({"removal", "restricted"}) public class PlatformGraphicsInfo { static { diff --git a/src/java.desktop/macosx/classes/sun/lwawt/macosx/CAccessibility.java b/src/java.desktop/macosx/classes/sun/lwawt/macosx/CAccessibility.java index 2da02e34b450f..436ab6138faa4 100644 --- a/src/java.desktop/macosx/classes/sun/lwawt/macosx/CAccessibility.java +++ b/src/java.desktop/macosx/classes/sun/lwawt/macosx/CAccessibility.java @@ -77,7 +77,7 @@ class CAccessibility implements PropertyChangeListener { loadAWTLibrary(); } - @SuppressWarnings("removal") + @SuppressWarnings({"removal", "restricted"}) private static void loadAWTLibrary() { // Need to load the native library for this code. java.security.AccessController.doPrivileged( diff --git a/src/java.desktop/macosx/classes/sun/lwawt/macosx/LWCToolkit.java b/src/java.desktop/macosx/classes/sun/lwawt/macosx/LWCToolkit.java index d430825bb8565..9a9be0e65c7e4 100644 --- a/src/java.desktop/macosx/classes/sun/lwawt/macosx/LWCToolkit.java +++ b/src/java.desktop/macosx/classes/sun/lwawt/macosx/LWCToolkit.java @@ -146,7 +146,7 @@ public final class LWCToolkit extends LWToolkit { static { System.err.flush(); - @SuppressWarnings("removal") + @SuppressWarnings({"removal", "restricted"}) ResourceBundle platformResources = java.security.AccessController.doPrivileged( new java.security.PrivilegedAction() { @Override diff --git a/src/java.desktop/share/classes/com/sun/imageio/plugins/jpeg/JPEGImageReader.java b/src/java.desktop/share/classes/com/sun/imageio/plugins/jpeg/JPEGImageReader.java index e2b3b3537ac06..c28759058c086 100644 --- a/src/java.desktop/share/classes/com/sun/imageio/plugins/jpeg/JPEGImageReader.java +++ b/src/java.desktop/share/classes/com/sun/imageio/plugins/jpeg/JPEGImageReader.java @@ -90,7 +90,7 @@ public class JPEGImageReader extends ImageReader { initStatic(); } - @SuppressWarnings("removal") + @SuppressWarnings({"removal", "restricted"}) private static void initStatic() { java.security.AccessController.doPrivileged( new java.security.PrivilegedAction() { diff --git a/src/java.desktop/share/classes/com/sun/imageio/plugins/jpeg/JPEGImageWriter.java b/src/java.desktop/share/classes/com/sun/imageio/plugins/jpeg/JPEGImageWriter.java index 0d41c4d2961ee..39189130be356 100644 --- a/src/java.desktop/share/classes/com/sun/imageio/plugins/jpeg/JPEGImageWriter.java +++ b/src/java.desktop/share/classes/com/sun/imageio/plugins/jpeg/JPEGImageWriter.java @@ -175,7 +175,7 @@ public class JPEGImageWriter extends ImageWriter { initStatic(); } - @SuppressWarnings("removal") + @SuppressWarnings({"removal", "restricted"}) private static void initStatic() { java.security.AccessController.doPrivileged( new java.security.PrivilegedAction() { diff --git a/src/java.desktop/share/classes/com/sun/java/swing/plaf/gtk/GTKLookAndFeel.java b/src/java.desktop/share/classes/com/sun/java/swing/plaf/gtk/GTKLookAndFeel.java index 681c0e5195838..a2414da455955 100644 --- a/src/java.desktop/share/classes/com/sun/java/swing/plaf/gtk/GTKLookAndFeel.java +++ b/src/java.desktop/share/classes/com/sun/java/swing/plaf/gtk/GTKLookAndFeel.java @@ -1058,7 +1058,7 @@ public Object createValue(UIDefaults table) { "KP_RIGHT", "selectNextColumn", "shift RIGHT", "selectNextColumnExtendSelection", "shift KP_RIGHT", "selectNextColumnExtendSelection", - "ctrl shift RIGHT", "selectNextColumnExtendSelection", + "ctrl shift RIGHT", "selectLastColumnExtendSelection", "ctrl shift KP_RIGHT", "selectNextColumnExtendSelection", "ctrl RIGHT", "selectNextColumnChangeLead", "ctrl KP_RIGHT", "selectNextColumnChangeLead", @@ -1066,7 +1066,7 @@ public Object createValue(UIDefaults table) { "KP_LEFT", "selectPreviousColumn", "shift LEFT", "selectPreviousColumnExtendSelection", "shift KP_LEFT", "selectPreviousColumnExtendSelection", - "ctrl shift LEFT", "selectPreviousColumnExtendSelection", + "ctrl shift LEFT", "selectFirstColumnExtendSelection", "ctrl shift KP_LEFT", "selectPreviousColumnExtendSelection", "ctrl LEFT", "selectPreviousColumnChangeLead", "ctrl KP_LEFT", "selectPreviousColumnChangeLead", diff --git a/src/java.desktop/share/classes/com/sun/media/sound/Platform.java b/src/java.desktop/share/classes/com/sun/media/sound/Platform.java index c4387a2109cc9..727718c6ca90f 100644 --- a/src/java.desktop/share/classes/com/sun/media/sound/Platform.java +++ b/src/java.desktop/share/classes/com/sun/media/sound/Platform.java @@ -74,7 +74,7 @@ static boolean isBigEndian() { /** * Load the native library or libraries. */ - @SuppressWarnings("removal") + @SuppressWarnings({"removal", "restricted"}) private static void loadLibraries() { // load the native library isNativeLibLoaded = true; diff --git a/src/java.desktop/share/classes/java/awt/SplashScreen.java b/src/java.desktop/share/classes/java/awt/SplashScreen.java index a7939f4a385c5..78ec4ed7aa0e9 100644 --- a/src/java.desktop/share/classes/java/awt/SplashScreen.java +++ b/src/java.desktop/share/classes/java/awt/SplashScreen.java @@ -121,7 +121,7 @@ public final class SplashScreen { * @return the {@link SplashScreen} instance, or {@code null} if there is * none or it has already been closed */ - @SuppressWarnings("removal") + @SuppressWarnings({"removal", "restricted"}) public static SplashScreen getSplashScreen() { synchronized (SplashScreen.class) { if (GraphicsEnvironment.isHeadless()) { diff --git a/src/java.desktop/share/classes/java/awt/Toolkit.java b/src/java.desktop/share/classes/java/awt/Toolkit.java index 54053fdc2e179..cf6260e9bda21 100644 --- a/src/java.desktop/share/classes/java/awt/Toolkit.java +++ b/src/java.desktop/share/classes/java/awt/Toolkit.java @@ -1375,7 +1375,7 @@ private static void setPlatformResources(ResourceBundle bundle) { * directly. -hung */ private static boolean loaded = false; - @SuppressWarnings("removal") + @SuppressWarnings({"removal", "restricted"}) static void loadLibraries() { if (!loaded) { java.security.AccessController.doPrivileged( diff --git a/src/java.desktop/share/classes/java/awt/event/NativeLibLoader.java b/src/java.desktop/share/classes/java/awt/event/NativeLibLoader.java index 04414f4fa2f3c..27a2c4397476b 100644 --- a/src/java.desktop/share/classes/java/awt/event/NativeLibLoader.java +++ b/src/java.desktop/share/classes/java/awt/event/NativeLibLoader.java @@ -52,7 +52,7 @@ class NativeLibLoader { * For now, we know it's done by the implementation, and we assume * that the name of the library is "awt". -br. */ - @SuppressWarnings("removal") + @SuppressWarnings({"removal", "restricted"}) static void loadLibraries() { java.security.AccessController.doPrivileged( new java.security.PrivilegedAction() { diff --git a/src/java.desktop/share/classes/java/awt/image/ColorModel.java b/src/java.desktop/share/classes/java/awt/image/ColorModel.java index 03ee479951d82..a0aa8fddc10f8 100644 --- a/src/java.desktop/share/classes/java/awt/image/ColorModel.java +++ b/src/java.desktop/share/classes/java/awt/image/ColorModel.java @@ -202,7 +202,7 @@ public abstract class ColorModel implements Transparency{ * that the name of the library is "awt". -br. */ private static boolean loaded = false; - @SuppressWarnings("removal") + @SuppressWarnings({"removal", "restricted"}) static void loadLibraries() { if (!loaded) { java.security.AccessController.doPrivileged( diff --git a/src/java.desktop/share/classes/javax/swing/plaf/basic/BasicSplitPaneDivider.java b/src/java.desktop/share/classes/javax/swing/plaf/basic/BasicSplitPaneDivider.java index 188e675388776..119e12276c790 100644 --- a/src/java.desktop/share/classes/javax/swing/plaf/basic/BasicSplitPaneDivider.java +++ b/src/java.desktop/share/classes/javax/swing/plaf/basic/BasicSplitPaneDivider.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 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 @@ -394,7 +394,10 @@ public void paint(Graphics g) { /** * Messaged when the oneTouchExpandable value of the JSplitPane the - * divider is contained in changes. Will create the + * divider is contained in changes. + * If a particular L&F supports this Swing + * "SplitPane.supportsOneTouchButtons" property + * it will create the * leftButton and rightButton if they are null * and corresponding JSplitPane supports oneTouchExpandable property. * Invalidates the corresponding JSplitPane as well. diff --git a/src/java.desktop/share/classes/sun/awt/NativeLibLoader.java b/src/java.desktop/share/classes/sun/awt/NativeLibLoader.java index ef524f0b39aea..868ebdf3699bd 100644 --- a/src/java.desktop/share/classes/sun/awt/NativeLibLoader.java +++ b/src/java.desktop/share/classes/sun/awt/NativeLibLoader.java @@ -52,7 +52,7 @@ class NativeLibLoader { * For now, we know it's done by the implementation, and we assume * that the name of the library is "awt". -br. */ - @SuppressWarnings("removal") + @SuppressWarnings({"removal", "restricted"}) static void loadLibraries() { java.security.AccessController.doPrivileged( new java.security.PrivilegedAction() { diff --git a/src/java.desktop/share/classes/sun/awt/image/ImagingLib.java b/src/java.desktop/share/classes/sun/awt/image/ImagingLib.java index ed09560fc9904..a98e6fc81fbad 100644 --- a/src/java.desktop/share/classes/sun/awt/image/ImagingLib.java +++ b/src/java.desktop/share/classes/sun/awt/image/ImagingLib.java @@ -51,7 +51,7 @@ * (in which case our java code will be executed) or may throw * an exception. */ -@SuppressWarnings("removal") +@SuppressWarnings({"removal", "restricted"}) public class ImagingLib { static boolean useLib = true; diff --git a/src/java.desktop/share/classes/sun/awt/image/JPEGImageDecoder.java b/src/java.desktop/share/classes/sun/awt/image/JPEGImageDecoder.java index eb28029589770..b976a716deda8 100644 --- a/src/java.desktop/share/classes/sun/awt/image/JPEGImageDecoder.java +++ b/src/java.desktop/share/classes/sun/awt/image/JPEGImageDecoder.java @@ -42,7 +42,7 @@ * * @author Jim Graham */ -@SuppressWarnings("removal") +@SuppressWarnings({"removal", "restricted"}) public class JPEGImageDecoder extends ImageDecoder { private static ColorModel RGBcolormodel; private static ColorModel ARGBcolormodel; diff --git a/src/java.desktop/share/classes/sun/awt/image/NativeLibLoader.java b/src/java.desktop/share/classes/sun/awt/image/NativeLibLoader.java index 3cf7f1ba5ef0c..e1fe5658e6377 100644 --- a/src/java.desktop/share/classes/sun/awt/image/NativeLibLoader.java +++ b/src/java.desktop/share/classes/sun/awt/image/NativeLibLoader.java @@ -52,7 +52,7 @@ class NativeLibLoader { * For now, we know it's done by the implementation, and we assume * that the name of the library is "awt". -br. */ - @SuppressWarnings("removal") + @SuppressWarnings({"removal", "restricted"}) static void loadLibraries() { java.security.AccessController.doPrivileged( new java.security.PrivilegedAction() { diff --git a/src/java.desktop/share/classes/sun/font/FontManagerNativeLibrary.java b/src/java.desktop/share/classes/sun/font/FontManagerNativeLibrary.java index ede2d0348b7f6..9439f6ed8574a 100644 --- a/src/java.desktop/share/classes/sun/font/FontManagerNativeLibrary.java +++ b/src/java.desktop/share/classes/sun/font/FontManagerNativeLibrary.java @@ -27,7 +27,7 @@ import sun.awt.OSInfo; -@SuppressWarnings("removal") +@SuppressWarnings({"removal", "restricted"}) public class FontManagerNativeLibrary { static { java.security.AccessController.doPrivileged( diff --git a/src/java.desktop/share/classes/sun/java2d/Disposer.java b/src/java.desktop/share/classes/sun/java2d/Disposer.java index 6b152dda3b028..5a80a61604544 100644 --- a/src/java.desktop/share/classes/sun/java2d/Disposer.java +++ b/src/java.desktop/share/classes/sun/java2d/Disposer.java @@ -50,7 +50,7 @@ * * @see DisposerRecord */ -@SuppressWarnings("removal") +@SuppressWarnings({"removal", "restricted"}) public class Disposer implements Runnable { private static final ReferenceQueue queue = new ReferenceQueue<>(); private static final Hashtable, DisposerRecord> records = diff --git a/src/java.desktop/share/classes/sun/java2d/cmm/lcms/LCMS.java b/src/java.desktop/share/classes/sun/java2d/cmm/lcms/LCMS.java index 9da28ab1548a9..2fe86b3500cf9 100644 --- a/src/java.desktop/share/classes/sun/java2d/cmm/lcms/LCMS.java +++ b/src/java.desktop/share/classes/sun/java2d/cmm/lcms/LCMS.java @@ -143,7 +143,7 @@ private LCMS() {} private static LCMS theLcms = null; - @SuppressWarnings("removal") + @SuppressWarnings({"removal", "restricted"}) static synchronized PCMM getModule() { if (theLcms != null) { return theLcms; diff --git a/src/java.desktop/share/native/libsplashscreen/splashscreen_impl.c b/src/java.desktop/share/native/libsplashscreen/splashscreen_impl.c index 5891a66d6ac76..05ef8c33a83c2 100644 --- a/src/java.desktop/share/native/libsplashscreen/splashscreen_impl.c +++ b/src/java.desktop/share/native/libsplashscreen/splashscreen_impl.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 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 @@ -26,11 +26,6 @@ #include "splashscreen_impl.h" #include "splashscreen_gfx_impl.h" #define BUFF_SIZE 1024 -#ifdef _MSC_VER -# ifndef snprintf -# define snprintf _snprintf -# endif -#endif int splashIsVisible = 0; Splash * diff --git a/src/java.desktop/unix/classes/sun/awt/X11GraphicsEnvironment.java b/src/java.desktop/unix/classes/sun/awt/X11GraphicsEnvironment.java index 93f5eaf6656c0..42b20f6684398 100644 --- a/src/java.desktop/unix/classes/sun/awt/X11GraphicsEnvironment.java +++ b/src/java.desktop/unix/classes/sun/awt/X11GraphicsEnvironment.java @@ -59,7 +59,7 @@ public final class X11GraphicsEnvironment extends SunGraphicsEnvironment { initStatic(); } - @SuppressWarnings("removal") + @SuppressWarnings({"removal", "restricted"}) private static void initStatic() { java.security.AccessController.doPrivileged( new java.security.PrivilegedAction() { diff --git a/src/java.desktop/unix/classes/sun/print/CUPSPrinter.java b/src/java.desktop/unix/classes/sun/print/CUPSPrinter.java index 4d2a4d616aa41..8be118c42a570 100644 --- a/src/java.desktop/unix/classes/sun/print/CUPSPrinter.java +++ b/src/java.desktop/unix/classes/sun/print/CUPSPrinter.java @@ -90,7 +90,7 @@ public class CUPSPrinter { initStatic(); } - @SuppressWarnings("removal") + @SuppressWarnings({"removal", "restricted"}) private static void initStatic() { // load awt library to access native code java.security.AccessController.doPrivileged( diff --git a/src/java.desktop/windows/classes/sun/awt/PlatformGraphicsInfo.java b/src/java.desktop/windows/classes/sun/awt/PlatformGraphicsInfo.java index 4644a2e5f46ac..6d14a72400c0c 100644 --- a/src/java.desktop/windows/classes/sun/awt/PlatformGraphicsInfo.java +++ b/src/java.desktop/windows/classes/sun/awt/PlatformGraphicsInfo.java @@ -39,7 +39,7 @@ public class PlatformGraphicsInfo { hasDisplays = hasDisplays0(); } - @SuppressWarnings("removal") + @SuppressWarnings({"removal", "restricted"}) private static void loadAWTLibrary() { java.security.AccessController.doPrivileged( new java.security.PrivilegedAction() { diff --git a/src/java.desktop/windows/classes/sun/awt/windows/WToolkit.java b/src/java.desktop/windows/classes/sun/awt/windows/WToolkit.java index eff6f930a5be7..ad643ccbd3dfd 100644 --- a/src/java.desktop/windows/classes/sun/awt/windows/WToolkit.java +++ b/src/java.desktop/windows/classes/sun/awt/windows/WToolkit.java @@ -168,7 +168,7 @@ public final class WToolkit extends SunToolkit implements Runnable { */ private static native void initIDs(); private static boolean loaded = false; - @SuppressWarnings("removal") + @SuppressWarnings({"removal", "restricted"}) public static void loadLibraries() { if (!loaded) { java.security.AccessController.doPrivileged( diff --git a/src/java.desktop/windows/classes/sun/print/PrintServiceLookupProvider.java b/src/java.desktop/windows/classes/sun/print/PrintServiceLookupProvider.java index 28055c1afece6..9079e7c2bfeff 100644 --- a/src/java.desktop/windows/classes/sun/print/PrintServiceLookupProvider.java +++ b/src/java.desktop/windows/classes/sun/print/PrintServiceLookupProvider.java @@ -54,7 +54,7 @@ public class PrintServiceLookupProvider extends PrintServiceLookup { loadAWTLibrary(); } - @SuppressWarnings("removal") + @SuppressWarnings({"removal", "restricted"}) private static void loadAWTLibrary() { java.security.AccessController.doPrivileged( new java.security.PrivilegedAction() { diff --git a/src/java.desktop/windows/native/libawt/windows/awt_Debug.cpp b/src/java.desktop/windows/native/libawt/windows/awt_Debug.cpp index 9e4b1ff1bf05c..3b8043385a1ce 100644 --- a/src/java.desktop/windows/native/libawt/windows/awt_Debug.cpp +++ b/src/java.desktop/windows/native/libawt/windows/awt_Debug.cpp @@ -141,7 +141,7 @@ void AwtDebugSupport::AssertCallback(const char * expr, const char * file, int l msgBuffer = (LPSTR)""; } // format the assertion message - _snprintf(assertMsg, ASSERT_MSG_SIZE, AssertFmt, expr, file, line, lastError, msgBuffer); + snprintf(assertMsg, ASSERT_MSG_SIZE, AssertFmt, expr, file, line, lastError, msgBuffer); if (fret != 0) { LocalFree(msgBuffer); } diff --git a/src/java.instrument/share/classes/sun/instrument/InstrumentationImpl.java b/src/java.instrument/share/classes/sun/instrument/InstrumentationImpl.java index bd610c3648069..3aeddd1c90d9c 100644 --- a/src/java.instrument/share/classes/sun/instrument/InstrumentationImpl.java +++ b/src/java.instrument/share/classes/sun/instrument/InstrumentationImpl.java @@ -63,6 +63,7 @@ * Keeps a pointer to the native data structure in a scalar field to allow native * processing behind native methods. */ +@SuppressWarnings("restricted") public class InstrumentationImpl implements Instrumentation { private static final String TRACE_USAGE_PROP_NAME = "jdk.instrument.traceUsage"; private static final boolean TRACE_USAGE; diff --git a/src/java.management/share/classes/java/lang/management/ManagementFactory.java b/src/java.management/share/classes/java/lang/management/ManagementFactory.java index 8e290f373b72b..b1ac1d0391e54 100644 --- a/src/java.management/share/classes/java/lang/management/ManagementFactory.java +++ b/src/java.management/share/classes/java/lang/management/ManagementFactory.java @@ -1020,7 +1020,7 @@ static PlatformComponent findSingleton(Class mbeanIntf) loadNativeLib(); } - @SuppressWarnings("removal") + @SuppressWarnings({"removal", "restricted"}) private static void loadNativeLib() { AccessController.doPrivileged((PrivilegedAction) () -> { System.loadLibrary("management"); diff --git a/src/java.prefs/macosx/classes/java/util/prefs/MacOSXPreferencesFile.java b/src/java.prefs/macosx/classes/java/util/prefs/MacOSXPreferencesFile.java index 61ee92cf6013a..c222bc3d81f02 100644 --- a/src/java.prefs/macosx/classes/java/util/prefs/MacOSXPreferencesFile.java +++ b/src/java.prefs/macosx/classes/java/util/prefs/MacOSXPreferencesFile.java @@ -82,7 +82,7 @@ class MacOSXPreferencesFile { loadPrefsLib(); } - @SuppressWarnings("removal") + @SuppressWarnings({"removal", "restricted"}) private static void loadPrefsLib() { java.security.AccessController.doPrivileged( new java.security.PrivilegedAction() { diff --git a/src/java.prefs/unix/classes/java/util/prefs/FileSystemPreferences.java b/src/java.prefs/unix/classes/java/util/prefs/FileSystemPreferences.java index 2a8947146666c..ed76ce57f9472 100644 --- a/src/java.prefs/unix/classes/java/util/prefs/FileSystemPreferences.java +++ b/src/java.prefs/unix/classes/java/util/prefs/FileSystemPreferences.java @@ -53,7 +53,7 @@ class FileSystemPreferences extends AbstractPreferences { loadPrefsLib(); } - @SuppressWarnings("removal") + @SuppressWarnings({"removal", "restricted"}) private static void loadPrefsLib() { PrivilegedAction load = () -> { System.loadLibrary("prefs"); diff --git a/src/java.prefs/windows/classes/java/util/prefs/WindowsPreferences.java b/src/java.prefs/windows/classes/java/util/prefs/WindowsPreferences.java index df1f29c9c1353..885535755a2aa 100644 --- a/src/java.prefs/windows/classes/java/util/prefs/WindowsPreferences.java +++ b/src/java.prefs/windows/classes/java/util/prefs/WindowsPreferences.java @@ -50,7 +50,7 @@ class WindowsPreferences extends AbstractPreferences { loadPrefsLib(); } - @SuppressWarnings("removal") + @SuppressWarnings({"removal", "restricted"}) private static void loadPrefsLib() { PrivilegedAction load = () -> { System.loadLibrary("prefs"); diff --git a/src/java.rmi/share/classes/sun/rmi/transport/GC.java b/src/java.rmi/share/classes/sun/rmi/transport/GC.java index f15a46beacaca..4bd50511dd45a 100644 --- a/src/java.rmi/share/classes/sun/rmi/transport/GC.java +++ b/src/java.rmi/share/classes/sun/rmi/transport/GC.java @@ -39,7 +39,7 @@ * @since 1.2 */ -@SuppressWarnings("removal") +@SuppressWarnings({"removal", "restricted"}) class GC { private GC() { } /* To prevent instantiation */ diff --git a/src/java.security.jgss/share/classes/sun/security/jgss/wrapper/SunNativeProvider.java b/src/java.security.jgss/share/classes/sun/security/jgss/wrapper/SunNativeProvider.java index 2099eaf779e0b..11545a25a6351 100644 --- a/src/java.security.jgss/share/classes/sun/security/jgss/wrapper/SunNativeProvider.java +++ b/src/java.security.jgss/share/classes/sun/security/jgss/wrapper/SunNativeProvider.java @@ -68,7 +68,7 @@ static void debug(String message) { System.err.println(NAME + ": " + message); } - @SuppressWarnings("removal") + @SuppressWarnings({"removal", "restricted"}) private static final HashMap MECH_MAP = AccessController.doPrivileged( new PrivilegedAction<>() { diff --git a/src/java.security.jgss/share/classes/sun/security/krb5/Credentials.java b/src/java.security.jgss/share/classes/sun/security/krb5/Credentials.java index 9ec0b7b7c12fa..d31418ac35104 100644 --- a/src/java.security.jgss/share/classes/sun/security/krb5/Credentials.java +++ b/src/java.security.jgss/share/classes/sun/security/krb5/Credentials.java @@ -524,7 +524,7 @@ public static void printDebug(Credentials c) { } - @SuppressWarnings("removal") + @SuppressWarnings({"removal", "restricted"}) static void ensureLoaded() { java.security.AccessController.doPrivileged( new java.security.PrivilegedAction () { diff --git a/src/java.security.jgss/share/classes/sun/security/krb5/SCDynamicStoreConfig.java b/src/java.security.jgss/share/classes/sun/security/krb5/SCDynamicStoreConfig.java index 41c93afcf4074..1d917c226c600 100644 --- a/src/java.security.jgss/share/classes/sun/security/krb5/SCDynamicStoreConfig.java +++ b/src/java.security.jgss/share/classes/sun/security/krb5/SCDynamicStoreConfig.java @@ -45,7 +45,7 @@ public class SCDynamicStoreConfig { private static native List getKerberosConfig(); static { - @SuppressWarnings("removal") + @SuppressWarnings({"removal", "restricted"}) boolean isMac = java.security.AccessController.doPrivileged( new java.security.PrivilegedAction() { public Boolean run() { diff --git a/src/java.smartcardio/unix/classes/sun/security/smartcardio/PlatformPCSC.java b/src/java.smartcardio/unix/classes/sun/security/smartcardio/PlatformPCSC.java index 10a27e7a1b2eb..93d213bc1495e 100644 --- a/src/java.smartcardio/unix/classes/sun/security/smartcardio/PlatformPCSC.java +++ b/src/java.smartcardio/unix/classes/sun/security/smartcardio/PlatformPCSC.java @@ -61,7 +61,7 @@ class PlatformPCSC { // empty } - @SuppressWarnings("removal") + @SuppressWarnings({"removal", "restricted"}) static final Throwable initException = AccessController.doPrivileged(new PrivilegedAction() { public Throwable run() { diff --git a/src/java.smartcardio/windows/classes/sun/security/smartcardio/PlatformPCSC.java b/src/java.smartcardio/windows/classes/sun/security/smartcardio/PlatformPCSC.java index 8541b67f61312..01cddcf8aa376 100644 --- a/src/java.smartcardio/windows/classes/sun/security/smartcardio/PlatformPCSC.java +++ b/src/java.smartcardio/windows/classes/sun/security/smartcardio/PlatformPCSC.java @@ -41,7 +41,7 @@ class PlatformPCSC { initException = loadLibrary(); } - @SuppressWarnings("removal") + @SuppressWarnings({"removal", "restricted"}) private static Throwable loadLibrary() { try { AccessController.doPrivileged(new PrivilegedAction() { diff --git a/src/jdk.accessibility/windows/classes/com/sun/java/accessibility/internal/AccessBridge.java b/src/jdk.accessibility/windows/classes/com/sun/java/accessibility/internal/AccessBridge.java index 8488fb526ee09..b5a5943d2d907 100644 --- a/src/jdk.accessibility/windows/classes/com/sun/java/accessibility/internal/AccessBridge.java +++ b/src/jdk.accessibility/windows/classes/com/sun/java/accessibility/internal/AccessBridge.java @@ -160,7 +160,7 @@ public final class AccessBridge { initStatic(); } - @SuppressWarnings("removal") + @SuppressWarnings({"removal", "restricted"}) private static void initStatic() { // Load the appropriate DLLs boolean is32on64 = false; diff --git a/src/jdk.accessibility/windows/native/jaccessinspector/jaccessinspector.cpp b/src/jdk.accessibility/windows/native/jaccessinspector/jaccessinspector.cpp index 22992d481edef..38e093eda0948 100644 --- a/src/jdk.accessibility/windows/native/jaccessinspector/jaccessinspector.cpp +++ b/src/jdk.accessibility/windows/native/jaccessinspector/jaccessinspector.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 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 @@ -1526,8 +1526,8 @@ BOOL UpdateMessageNumber () { size_t messageNumber = g_MessageHistory.GetCurrentMessageIndex() + 1; char text [32] = {0}; if ( 0 != messageCount ) { - ::_snprintf(text, sizeof(text), "%d of %d", (int)messageNumber, - (int) messageCount); + ::snprintf(text, sizeof(text), "%d of %d", (int)messageNumber, + (int) messageCount); } return ::SetWindowText(dlgItem, text); } diff --git a/src/jdk.attach/aix/classes/sun/tools/attach/VirtualMachineImpl.java b/src/jdk.attach/aix/classes/sun/tools/attach/VirtualMachineImpl.java index d0a6dac40c86f..9f9f96a9416df 100644 --- a/src/jdk.attach/aix/classes/sun/tools/attach/VirtualMachineImpl.java +++ b/src/jdk.attach/aix/classes/sun/tools/attach/VirtualMachineImpl.java @@ -38,6 +38,7 @@ /* * Aix implementation of HotSpotVirtualMachine */ +@SuppressWarnings("restricted") public class VirtualMachineImpl extends HotSpotVirtualMachine { // "/tmp" is used as a global well-known location for the files // .java_pid. and .attach_pid. It is important that this diff --git a/src/jdk.attach/linux/classes/sun/tools/attach/VirtualMachineImpl.java b/src/jdk.attach/linux/classes/sun/tools/attach/VirtualMachineImpl.java index 81d4fd259ed00..4eb29482e29ec 100644 --- a/src/jdk.attach/linux/classes/sun/tools/attach/VirtualMachineImpl.java +++ b/src/jdk.attach/linux/classes/sun/tools/attach/VirtualMachineImpl.java @@ -40,6 +40,7 @@ /* * Linux implementation of HotSpotVirtualMachine */ +@SuppressWarnings("restricted") public class VirtualMachineImpl extends HotSpotVirtualMachine { // "/tmp" is used as a global well-known location for the files // .java_pid. and .attach_pid. It is important that this diff --git a/src/jdk.attach/macosx/classes/sun/tools/attach/VirtualMachineImpl.java b/src/jdk.attach/macosx/classes/sun/tools/attach/VirtualMachineImpl.java index 891a0561a8abd..19104d49014ac 100644 --- a/src/jdk.attach/macosx/classes/sun/tools/attach/VirtualMachineImpl.java +++ b/src/jdk.attach/macosx/classes/sun/tools/attach/VirtualMachineImpl.java @@ -37,6 +37,7 @@ /* * Bsd implementation of HotSpotVirtualMachine */ +@SuppressWarnings("restricted") public class VirtualMachineImpl extends HotSpotVirtualMachine { // "tmpdir" is used as a global well-known location for the files // .java_pid. and .attach_pid. It is important that this diff --git a/src/jdk.attach/windows/classes/sun/tools/attach/AttachProviderImpl.java b/src/jdk.attach/windows/classes/sun/tools/attach/AttachProviderImpl.java index cd40cdc8266c6..503d9592370ab 100644 --- a/src/jdk.attach/windows/classes/sun/tools/attach/AttachProviderImpl.java +++ b/src/jdk.attach/windows/classes/sun/tools/attach/AttachProviderImpl.java @@ -34,6 +34,7 @@ import java.net.InetAddress; import java.net.UnknownHostException; +@SuppressWarnings("restricted") public class AttachProviderImpl extends HotSpotAttachProvider { public AttachProviderImpl() { diff --git a/src/jdk.attach/windows/classes/sun/tools/attach/VirtualMachineImpl.java b/src/jdk.attach/windows/classes/sun/tools/attach/VirtualMachineImpl.java index 184d07137e289..9c30f5618d66e 100644 --- a/src/jdk.attach/windows/classes/sun/tools/attach/VirtualMachineImpl.java +++ b/src/jdk.attach/windows/classes/sun/tools/attach/VirtualMachineImpl.java @@ -35,6 +35,7 @@ /* * Windows implementation of HotSpotVirtualMachine */ +@SuppressWarnings("restricted") public class VirtualMachineImpl extends HotSpotVirtualMachine { // the enqueue code stub (copied into each target VM) diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Type.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Type.java index 702b51d3b96b6..151c39fae40f0 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Type.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Type.java @@ -2338,7 +2338,7 @@ public ErrorType(Type originalType, TypeSymbol tsym) { this.originalType = (originalType == null ? noType : originalType); } - private ErrorType(Type originalType, TypeSymbol tsym, + public ErrorType(Type originalType, TypeSymbol tsym, List metadata) { super(noType, List.nil(), null, metadata); this.tsym = tsym; @@ -2393,10 +2393,6 @@ public R accept(Type.Visitor v, S s) { public boolean isCompound() { return false; } public boolean isInterface() { return false; } - public List allparams() { return List.nil(); } - @DefinedBy(Api.LANGUAGE_MODEL) - public List getTypeArguments() { return List.nil(); } - @DefinedBy(Api.LANGUAGE_MODEL) public TypeKind getKind() { return TypeKind.ERROR; diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java index 54edc19560bd1..44ccbade4a900 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java @@ -5081,6 +5081,14 @@ public void visitTypeApply(JCTypeApply tree) { } owntype = types.createErrorType(tree.type); } + } else if (clazztype.hasTag(ERROR)) { + ErrorType parameterizedErroneous = + new ErrorType(clazztype.getOriginalType(), + clazztype.tsym, + clazztype.getMetadata()); + + parameterizedErroneous.typarams_field = actuals; + owntype = parameterizedErroneous; } result = check(tree, owntype, KindSelector.TYP, resultInfo); } diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/JavacParser.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/JavacParser.java index 6fc93fdc591ab..27cb44bebba15 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/JavacParser.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/JavacParser.java @@ -59,6 +59,7 @@ import static com.sun.tools.javac.parser.Tokens.TokenKind.GT; import static com.sun.tools.javac.parser.Tokens.TokenKind.IMPORT; import static com.sun.tools.javac.parser.Tokens.TokenKind.LT; +import com.sun.tools.javac.parser.VirtualParser.VirtualScanner; import static com.sun.tools.javac.tree.JCTree.Tag.*; import static com.sun.tools.javac.resources.CompilerProperties.Fragments.ImplicitAndExplicitNotAllowed; import static com.sun.tools.javac.resources.CompilerProperties.Fragments.VarAndExplicitNotAllowed; @@ -5019,13 +5020,17 @@ protected JCTree methodDeclaratorRest(int pos, // Parsing formalParameters sets the receiverParam, if present List params = List.nil(); List thrown = List.nil(); + boolean unclosedParameterList; if (!isRecord || name != names.init || token.kind == LPAREN) { params = formalParameters(); + unclosedParameterList = token.pos == endPosTable.errorEndPos; if (!isVoid) type = bracketsOpt(type); if (token.kind == THROWS) { nextToken(); thrown = qualidentList(true); } + } else { + unclosedParameterList = false; } saveDanglingDocComments(dc); @@ -5039,14 +5044,18 @@ protected JCTree methodDeclaratorRest(int pos, if (token.kind == DEFAULT) { accept(DEFAULT); defaultValue = annotationValue(); + accept(SEMI); } else { defaultValue = null; + accept(SEMI, tk -> Errors.Expected2(LBRACE, SEMI)); } - accept(SEMI); if (token.pos <= endPosTable.errorEndPos) { // error recovery - skip(false, true, false, false); - if (token.kind == LBRACE) { + // look if there is a probable missing opening brace, + // and if yes, parse as a block + boolean parseAsBlock = openingBraceMissing(unclosedParameterList); + + if (parseAsBlock) { body = block(); } } @@ -5063,6 +5072,84 @@ protected JCTree methodDeclaratorRest(int pos, } } + /** + * After seeing a method header, and not seeing an opening left brace, + * attempt to estimate if acting as if the left brace was present and + * parsing the upcoming code will get better results than not parsing + * the code as a block. + * + * The estimate is as follows: + * - tokens are skipped until member, statement or identifier is found, + * - then, if there is a left brace, parse as a block, + * - otherwise, if the head was broken, do not parse as a block, + * - otherwise, look at the next token and: + * - if it definitelly starts a statement, parse as a block, + * - otherwise, if it is a closing/right brace, count opening and closing + * braces in the rest of the file, to see if imaginarily "adding" an opening + * brace would lead to a balanced count - if yes, parse as a block, + * - otherwise, speculatively parse the following code as a block, and if + * it contains statements that cannot be members, parse as a block, + * - otherwise, don't parse as a block. + * + * @param unclosedParameterList whether there was a serious problem in the + * parameters list + * @return true if and only if the following code should be parsed as a block. + */ + private boolean openingBraceMissing(boolean unclosedParameterList) { + skip(false, true, !unclosedParameterList, !unclosedParameterList); + + if (token.kind == LBRACE) { + return true; + } else if (unclosedParameterList) { + return false; + } else { + return switch (token.kind) { + //definitelly sees a statement: + case CASE, DEFAULT, IF, FOR, WHILE, DO, TRY, SWITCH, + RETURN, THROW, BREAK, CONTINUE, ELSE, FINALLY, + CATCH, THIS, SUPER, NEW -> true; + case RBRACE -> { + //check if adding an opening brace would balance out + //the opening and closing braces: + int braceBalance = 1; + VirtualScanner virtualScanner = new VirtualScanner(S); + + virtualScanner.nextToken(); + + while (virtualScanner.token().kind != TokenKind.EOF) { + switch (virtualScanner.token().kind) { + case LBRACE -> braceBalance++; + case RBRACE -> braceBalance--; + } + virtualScanner.nextToken(); + } + + yield braceBalance == 0; + } + default -> { + //speculatively try to parse as a block, and check + //if the result would suggest there is a block + //e.g.: it contains a statement that is not + //a member declaration + JavacParser speculative = new VirtualParser(this); + JCBlock speculativeResult = + speculative.block(); + if (!speculativeResult.stats.isEmpty()) { + JCStatement last = speculativeResult.stats.last(); + yield !speculativeResult.stats.stream().allMatch(s -> s.hasTag(VARDEF) || + s.hasTag(CLASSDEF) || + s.hasTag(BLOCK) || + s == last) || + !(last instanceof JCExpressionStatement exprStatement && + exprStatement.expr.hasTag(ERRONEOUS)); + } else { + yield false; + } + } + }; + } + } + /** QualidentList = [Annotations] Qualident {"," [Annotations] Qualident} */ List qualidentList(boolean allowAnnos) { diff --git a/src/jdk.compiler/share/data/symbols/java.base-N.sym.txt b/src/jdk.compiler/share/data/symbols/java.base-N.sym.txt index fd1bd11f6b9c3..f14c1fb1a4ca5 100644 --- a/src/jdk.compiler/share/data/symbols/java.base-N.sym.txt +++ b/src/jdk.compiler/share/data/symbols/java.base-N.sym.txt @@ -462,18 +462,6 @@ class name java/net/Socket method name descriptor (Ljava/lang/String;IZ)V thrownTypes java/io/IOException flags 1 deprecated true runtimeAnnotations @Ljava/lang/Deprecated;(forRemoval=Ztrue,since="1.1") method name descriptor (Ljava/net/InetAddress;IZ)V thrownTypes java/io/IOException flags 1 deprecated true runtimeAnnotations @Ljava/lang/Deprecated;(forRemoval=Ztrue,since="1.1") -class name java/nio/HeapByteBuffer -method name hashCode descriptor ()I flags 1 - -class name java/nio/HeapByteBufferR -method name hashCode descriptor ()I flags 1 - -class name java/nio/HeapCharBuffer -method name hashCode descriptor ()I flags 1 - -class name java/nio/HeapCharBufferR -method name hashCode descriptor ()I flags 1 - class name java/security/Provider header extends java/util/Properties nestMembers java/security/Provider$Service flags 421 innerclass innerClass java/util/Map$Entry outerClass java/util/Map innerClassName Entry flags 609 diff --git a/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/wrapper/PKCS11.java b/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/wrapper/PKCS11.java index db4a471f33474..f7dfd05500093 100644 --- a/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/wrapper/PKCS11.java +++ b/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/wrapper/PKCS11.java @@ -83,7 +83,7 @@ public class PKCS11 { // cannot use LoadLibraryAction because that would make the native // library available to the bootclassloader, but we run in the // extension classloader. - @SuppressWarnings("removal") + @SuppressWarnings({"removal", "restricted"}) var dummy = AccessController.doPrivileged(new PrivilegedAction() { public Object run() { System.loadLibrary(PKCS11_WRAPPER); diff --git a/src/jdk.crypto.cryptoki/windows/native/libj2pkcs11/j2secmod_md.c b/src/jdk.crypto.cryptoki/windows/native/libj2pkcs11/j2secmod_md.c index 305d202030bf3..a5cd5e63d02b3 100644 --- a/src/jdk.crypto.cryptoki/windows/native/libj2pkcs11/j2secmod_md.c +++ b/src/jdk.crypto.cryptoki/windows/native/libj2pkcs11/j2secmod_md.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 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 @@ -39,7 +39,7 @@ void *p11FindFunction(JNIEnv *env, jlong jHandle, const char *functionName) { void *fAddress = GetProcAddress(hModule, functionName); if (fAddress == NULL) { char errorMessage[256]; - _snprintf(errorMessage, sizeof(errorMessage), "Symbol not found: %s", functionName); + snprintf(errorMessage, sizeof(errorMessage), "Symbol not found: %s", functionName); p11ThrowNullPointerException(env, errorMessage); return NULL; } diff --git a/src/jdk.crypto.mscapi/windows/classes/sun/security/mscapi/SunMSCAPI.java b/src/jdk.crypto.mscapi/windows/classes/sun/security/mscapi/SunMSCAPI.java index c66258628210c..e57fe331f2832 100644 --- a/src/jdk.crypto.mscapi/windows/classes/sun/security/mscapi/SunMSCAPI.java +++ b/src/jdk.crypto.mscapi/windows/classes/sun/security/mscapi/SunMSCAPI.java @@ -50,7 +50,7 @@ public final class SunMSCAPI extends Provider { private static final String INFO = "Sun's Microsoft Crypto API provider"; static { - @SuppressWarnings("removal") + @SuppressWarnings({"removal", "restricted"}) var dummy = AccessController.doPrivileged(new PrivilegedAction() { public Void run() { System.loadLibrary("sunmscapi"); diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/bsd/BsdDebuggerLocal.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/bsd/BsdDebuggerLocal.java index 163d253e36051..0ce2a4507ae74 100644 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/bsd/BsdDebuggerLocal.java +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/bsd/BsdDebuggerLocal.java @@ -62,6 +62,7 @@ can be fetched. The readJ(Type) routines here will throw a RuntimeException if they are called before the debugger is configured with the Java primitive type sizes.

*/ +@SuppressWarnings("restricted") public class BsdDebuggerLocal extends DebuggerBase implements BsdDebugger { private boolean useGCC32ABI; private boolean attached; diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/linux/LinuxDebuggerLocal.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/linux/LinuxDebuggerLocal.java index 5a91c06e83ea4..5bab3d252d03a 100644 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/linux/LinuxDebuggerLocal.java +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/linux/LinuxDebuggerLocal.java @@ -67,6 +67,7 @@ can be fetched. The readJ(Type) routines here will throw a RuntimeException if they are called before the debugger is configured with the Java primitive type sizes.

*/ +@SuppressWarnings("restricted") public class LinuxDebuggerLocal extends DebuggerBase implements LinuxDebugger { private boolean useGCC32ABI; private boolean attached; diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/windbg/WindbgDebuggerLocal.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/windbg/WindbgDebuggerLocal.java index fa00159f6a86c..f082b7e52c639 100644 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/windbg/WindbgDebuggerLocal.java +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/windbg/WindbgDebuggerLocal.java @@ -54,6 +54,7 @@ can be fetched. The readJ(Type) routines here will throw a RuntimeException if they are called before the debugger is configured with the Java primitive type sizes.

*/ +@SuppressWarnings("restricted") public class WindbgDebuggerLocal extends DebuggerBase implements WindbgDebugger { private PageCache cache; private boolean attached; diff --git a/src/jdk.hotspot.agent/share/native/libsaproc/sadis.c b/src/jdk.hotspot.agent/share/native/libsaproc/sadis.c index 62f6303c32b68..cf66b7184e3ac 100644 --- a/src/jdk.hotspot.agent/share/native/libsaproc/sadis.c +++ b/src/jdk.hotspot.agent/share/native/libsaproc/sadis.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 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 @@ -33,12 +33,6 @@ */ #ifdef _WINDOWS -// Disable CRT security warning against _snprintf -#pragma warning (disable : 4996) - -#define snprintf _snprintf -#define vsnprintf _vsnprintf - #include #include #include diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/standard.properties b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/standard.properties index ecff358ce22c6..6141ce46fe8fc 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/standard.properties +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/standard.properties @@ -478,7 +478,8 @@ doclet.usage.author.description=\ Include @author paragraphs doclet.usage.docfilessubdirs.description=\ - Recursively copy doc-file subdirectories + Enables deep copying of 'doc-files' directories. Subdirectories and all\n\ + contents are recursively copied to the destination doclet.usage.splitindex.description=\ Split index into one file per letter @@ -515,7 +516,7 @@ doclet.usage.html5.description=\ doclet.usage.footer.parameters=\ doclet.usage.footer.description=\ - Include footer text for each page + This option is no longer supported and reports a warning doclet.usage.top.parameters=\ @@ -553,7 +554,7 @@ doclet.usage.link-platform-properties.description=\ doclet.usage.excludedocfilessubdir.parameters=\ ,,... doclet.usage.excludedocfilessubdir.description=\ - Exclude any doc-files subdirectories with given name.\n\ + Exclude any 'doc-files' subdirectories with given name.\n\ ':' can also be used anywhere in the argument as a separator. doclet.usage.group.parameters=\ @@ -614,7 +615,7 @@ doclet.usage.nooverview.description=\ Do not generate overview pages doclet.usage.serialwarn.description=\ - Generate warning about @serial tag + Reports compile-time warnings for missing '@serial' tags doclet.usage.since.parameters=\ (,)* @@ -629,7 +630,7 @@ doclet.usage.since-label.description=\ doclet.usage.tag.parameters=\ ::
doclet.usage.tag.description=\ - Specify single argument custom tags + Specifies a custom tag with a single argument doclet.usage.taglet.description=\ The fully qualified name of Taglet to register @@ -654,7 +655,8 @@ doclet.usage.javafx.description=\ doclet.usage.helpfile.parameters=\ doclet.usage.helpfile.description=\ - Include file that help link links to + Specifies a file containing the text that will be displayed when the\n\ + help link in the navigation bar is clicked doclet.usage.linksource.description=\ Generate source in HTML @@ -691,7 +693,8 @@ doclet.usage.override-methods.description=\ The default is 'detail'. doclet.usage.allow-script-in-comments.description=\ - Allow JavaScript in options and comments + Allow JavaScript in documentation comments, and options\n\ + whose value is html-code doclet.usage.xdocrootparent.parameters=\ diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/tool/ToolOptions.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/tool/ToolOptions.java index 17bf628114a67..39d9f2834e183 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/tool/ToolOptions.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/tool/ToolOptions.java @@ -678,7 +678,7 @@ interface ShowHelper { /** * Show command-line help for the extended options, as requested by - * the {@code --help-extended} option and its aliases. + * the {@code --help-extra} option and its aliases. */ void Xusage(); diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/tool/resources/javadoc.properties b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/tool/resources/javadoc.properties index 7db420e46d587..8178380972509 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/tool/resources/javadoc.properties +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/tool/resources/javadoc.properties @@ -67,7 +67,7 @@ main.opt.private.desc=\ main.opt.show.members.arg=\ main.opt.show.members.desc=\ - Specifies which members (fields, methods, etc.) will be\n\ + Specifies which members (fields, methods, or constructors) will be\n\ documented, where value can be one of "public", "protected",\n\ "package" or "private". The default is "protected", which will\n\ show public and protected members, "public" will show only\n\ @@ -87,7 +87,7 @@ main.opt.show.types.desc=\ main.opt.show.packages.arg=\ main.opt.show.packages.desc=\ - Specifies which module's packages will be documented. Possible\n\ + Specifies which module packages will be documented. Possible\n\ values are "exported" or "all" packages. main.opt.show.module.contents.arg=\ @@ -97,7 +97,7 @@ main.opt.show.module.contents.desc=\ declarations. Possible values are "api" or "all". main.opt.expand.requires.arg=\ - + (transitive|all) main.opt.expand.requires.desc=\ Instructs the tool to expand the set of modules to be\n\ documented. By default, only the modules given explicitly on\n\ diff --git a/src/jdk.jdi/windows/classes/com/sun/tools/jdi/SharedMemoryTransportService.java b/src/jdk.jdi/windows/classes/com/sun/tools/jdi/SharedMemoryTransportService.java index d16ee6e1dd546..ae3ccf7f14921 100644 --- a/src/jdk.jdi/windows/classes/com/sun/tools/jdi/SharedMemoryTransportService.java +++ b/src/jdk.jdi/windows/classes/com/sun/tools/jdi/SharedMemoryTransportService.java @@ -65,6 +65,7 @@ public String toString() { } } + @SuppressWarnings("restricted") SharedMemoryTransportService() { System.loadLibrary("dt_shmem"); initialize(); diff --git a/src/jdk.jdwp.agent/windows/native/libjdwp/linker_md.c b/src/jdk.jdwp.agent/windows/native/libjdwp/linker_md.c index 97eb1498f5873..a2cc952db815d 100644 --- a/src/jdk.jdwp.agent/windows/native/libjdwp/linker_md.c +++ b/src/jdk.jdwp.agent/windows/native/libjdwp/linker_md.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 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 @@ -56,7 +56,7 @@ static void dll_build_name(char* buffer, size_t buflen, path = strtok_s(paths_copy, PATH_SEPARATOR, &next_token); while (path != NULL) { - size_t result_len = (size_t)_snprintf(buffer, buflen, "%s\\%s.dll", path, fname); + size_t result_len = (size_t) snprintf(buffer, buflen, "%s\\%s.dll", path, fname); if (result_len >= buflen) { EXIT_ERROR(JVMTI_ERROR_INVALID_LOCATION, "One or more of the library paths supplied to jdwp, " "likely by sun.boot.library.path, is too long."); diff --git a/src/jdk.jdwp.agent/windows/native/libjdwp/util_md.h b/src/jdk.jdwp.agent/windows/native/libjdwp/util_md.h index 4af5aced1143d..cefb301e09503 100644 --- a/src/jdk.jdwp.agent/windows/native/libjdwp/util_md.h +++ b/src/jdk.jdwp.agent/windows/native/libjdwp/util_md.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2008, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 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 @@ -34,11 +34,6 @@ typedef unsigned long UNSIGNED_JINT; #define MAXPATHLEN _MAX_PATH -/* Needed on Windows because names seem to be hidden in stdio.h. */ - -#define snprintf _snprintf -#define vsnprintf _vsnprintf - /* On little endian machines, convert java big endian numbers. */ #define HOST_TO_JAVA_CHAR(x) (((x & 0xff) << 8) | ((x >> 8) & (0xff))) diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/Control.java b/src/jdk.jfr/share/classes/jdk/jfr/internal/Control.java index 05c75a0e48e9b..8f246948710fc 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/internal/Control.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/Control.java @@ -141,7 +141,7 @@ public String combine(Set values) { @Override public String run() { try { - delegate.combine(Collections.unmodifiableSet(values)); + return delegate.combine(Collections.unmodifiableSet(values)); } catch (Throwable t) { // Prevent malicious user to propagate exception callback in the wrong context Logger.log(LogTag.JFR_SETTING, LogLevel.WARN, "Exception occurred when combining " + values + " for " + getClass()); diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/StringPool.java b/src/jdk.jfr/share/classes/jdk/jfr/internal/StringPool.java index 6513895069e17..c0dc4e6ba5884 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/internal/StringPool.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/StringPool.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 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 @@ -26,11 +26,12 @@ import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.atomic.AtomicLong; +import jdk.internal.vm.Continuation; public final class StringPool { public static final int MIN_LIMIT = 16; - public static final int MAX_LIMIT = 128; /* 0 MAX means disabled */ - + public static final int MAX_LIMIT = 131072; /* 0 MAX means disabled */ + private static final int PRECACHE_THRESHOLD = 128; private static final long DO_NOT_POOL = -1; /* max size */ private static final int MAX_SIZE = 32 * 1024; @@ -71,33 +72,49 @@ private static long externalSid(long internalSid) { return internalSid >> 16; } - /* synchronized because of writing the string to the JVM. */ - private static synchronized long storeString(String s) { - Long lsid = cache.get(s); - long internalSid; - if (lsid != null) { - internalSid = lsid.longValue(); - if (isCurrentGeneration(internalSid)) { - // Someone already updated the cache. - return externalSid(internalSid); + /* Explicitly pin a virtual thread before acquiring the string pool monitor + * because migrating the EventWriter onto another carrier thread is impossible. + */ + private static long storeString(String s, boolean pinVirtualThread) { + if (pinVirtualThread) { + assert(Thread.currentThread().isVirtual()); + Continuation.pin(); + } + try { + /* synchronized because of writing the string to the JVM. */ + synchronized (StringPool.class) { + Long lsid = cache.get(s); + long internalSid; + if (lsid != null) { + internalSid = lsid.longValue(); + if (isCurrentGeneration(internalSid)) { + // Someone already updated the cache. + return externalSid(internalSid); + } + internalSid = updateInternalSid(internalSid); + } else { + // Not yet added or the cache was cleared. + internalSid = nextInternalSid(); + currentSizeUTF16 += s.length(); + } + long extSid = externalSid(internalSid); + // Write the string to the JVM before publishing to the cache. + JVM.addStringConstant(extSid, s); + cache.put(s, internalSid); + return extSid; + } + } finally { + if (pinVirtualThread) { + assert(Thread.currentThread().isVirtual()); + Continuation.unpin(); } - internalSid = updateInternalSid(internalSid); - } else { - // Not yet added or the cache was cleared. - internalSid = nextInternalSid(); - currentSizeUTF16 += s.length(); } - long extSid = externalSid(internalSid); - // Write the string to the JVM before publishing to the cache. - JVM.addStringConstant(extSid, s); - cache.put(s, internalSid); - return extSid; } /* a string fetched from the string pool must be of the current generation */ - private static long ensureCurrentGeneration(String s, Long lsid) { + private static long ensureCurrentGeneration(String s, Long lsid, boolean pinVirtualThread) { long internalSid = lsid.longValue(); - return isCurrentGeneration(internalSid) ? externalSid(internalSid) : storeString(s); + return isCurrentGeneration(internalSid) ? externalSid(internalSid) : storeString(s, pinVirtualThread); } /* @@ -109,20 +126,20 @@ private static long ensureCurrentGeneration(String s, Long lsid) { * effectively invalidating the fetched string id. The event restart mechanism * of the EventWriter ensures that committed strings are in the correct generation. */ - public static long addString(String s) { + public static long addString(String s, boolean pinVirtualThread) { Long lsid = cache.get(s); if (lsid != null) { - return ensureCurrentGeneration(s, lsid); + return ensureCurrentGeneration(s, lsid, pinVirtualThread); } - if (!preCache(s)) { + if (s.length() <= PRECACHE_THRESHOLD && !preCache(s)) { /* we should not pool this string */ return DO_NOT_POOL; } if (cache.size() > MAX_SIZE || currentSizeUTF16 > MAX_SIZE_UTF16) { /* pool was full */ - reset(); + reset(pinVirtualThread); } - return storeString(s); + return storeString(s, pinVirtualThread); } private static boolean preCache(String s) { @@ -143,8 +160,21 @@ private static boolean preCache(String s) { return false; } - private static synchronized void reset() { - cache.clear(); - currentSizeUTF16 = 0; + private static void reset(boolean pinVirtualThread) { + if (pinVirtualThread) { + assert(Thread.currentThread().isVirtual()); + Continuation.pin(); + } + try { + synchronized (StringPool.class) { + cache.clear(); + currentSizeUTF16 = 0; + } + } finally { + if (pinVirtualThread) { + assert(Thread.currentThread().isVirtual()); + Continuation.unpin(); + } + } } } diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/event/EventWriter.java b/src/jdk.jfr/share/classes/jdk/jfr/internal/event/EventWriter.java index 833fb087e2420..970365ef73dfe 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/internal/event/EventWriter.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/event/EventWriter.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 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 @@ -65,6 +65,7 @@ public final class EventWriter { private long currentPosition; private long maxPosition; private boolean valid; + private boolean pinVirtualThread; boolean excluded; private PlatformEventType eventType; @@ -144,7 +145,7 @@ public void putString(String s) { return; } if (length > StringPool.MIN_LIMIT && length < StringPool.MAX_LIMIT) { - long l = StringPool.addString(s); + long l = StringPool.addString(s, pinVirtualThread); if (l > 0) { putByte(StringParser.Encoding.CONSTANT_POOL.byteValue()); putLong(l); @@ -296,11 +297,12 @@ public boolean endEvent() { return false; } - private EventWriter(long startPos, long maxPos, long threadID, boolean valid, boolean excluded) { + private EventWriter(long startPos, long maxPos, long threadID, boolean valid, boolean pinVirtualThread, boolean excluded) { startPosition = currentPosition = startPos; maxPosition = maxPos; this.threadID = threadID; this.valid = valid; + this.pinVirtualThread = pinVirtualThread; this.excluded = excluded; } diff --git a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/ExecutableRebrander.java b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/ExecutableRebrander.java index 060c94b12cf8a..a297f507da84a 100644 --- a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/ExecutableRebrander.java +++ b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/ExecutableRebrander.java @@ -48,7 +48,7 @@ import static jdk.jpackage.internal.StandardBundlerParam.VERSION; import static jdk.jpackage.internal.WindowsAppImageBuilder.ICON_ICO; - +@SuppressWarnings("restricted") final class ExecutableRebrander { private static final ResourceBundle I18N = ResourceBundle.getBundle( "jdk.jpackage.internal.resources.WinResources"); diff --git a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinExeBundler.java b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinExeBundler.java index c8aae5922873a..fa81b4278b06a 100644 --- a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinExeBundler.java +++ b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinExeBundler.java @@ -31,6 +31,7 @@ import java.text.MessageFormat; import java.util.Map; +@SuppressWarnings("restricted") public class WinExeBundler extends AbstractBundler { static { diff --git a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WindowsRegistry.java b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WindowsRegistry.java index a62d9c3b68775..7c4b6092901b4 100644 --- a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WindowsRegistry.java +++ b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WindowsRegistry.java @@ -28,6 +28,7 @@ import java.util.ArrayList; import java.util.List; +@SuppressWarnings("restricted") final class WindowsRegistry { // Currently we only support HKEY_LOCAL_MACHINE. Native implementation will diff --git a/src/jdk.management.agent/unix/classes/jdk/internal/agent/FileSystemImpl.java b/src/jdk.management.agent/unix/classes/jdk/internal/agent/FileSystemImpl.java index 9582a97cb8f79..a11b580d443d8 100644 --- a/src/jdk.management.agent/unix/classes/jdk/internal/agent/FileSystemImpl.java +++ b/src/jdk.management.agent/unix/classes/jdk/internal/agent/FileSystemImpl.java @@ -31,7 +31,7 @@ /* * Linux implementation of jdk.internal.agent.FileSystem */ -@SuppressWarnings("removal") +@SuppressWarnings({"removal", "restricted"}) public class FileSystemImpl extends FileSystem { public boolean supportsFileSecurity(File f) throws IOException { diff --git a/src/jdk.management.agent/windows/classes/jdk/internal/agent/FileSystemImpl.java b/src/jdk.management.agent/windows/classes/jdk/internal/agent/FileSystemImpl.java index f0fd31c0f9e52..5a913f9c0aa01 100644 --- a/src/jdk.management.agent/windows/classes/jdk/internal/agent/FileSystemImpl.java +++ b/src/jdk.management.agent/windows/classes/jdk/internal/agent/FileSystemImpl.java @@ -31,7 +31,7 @@ /* * Windows implementation of sun.management.FileSystem */ -@SuppressWarnings("removal") +@SuppressWarnings({"removal", "restricted"}) public class FileSystemImpl extends FileSystem { public boolean supportsFileSecurity(File f) throws IOException { diff --git a/src/jdk.management/share/classes/com/sun/management/internal/Flag.java b/src/jdk.management/share/classes/com/sun/management/internal/Flag.java index 6fb2c80247dcc..bf83f40f722c1 100644 --- a/src/jdk.management/share/classes/com/sun/management/internal/Flag.java +++ b/src/jdk.management/share/classes/com/sun/management/internal/Flag.java @@ -36,7 +36,7 @@ * corresponds to one VMOption. * */ -@SuppressWarnings("removal") +@SuppressWarnings({"removal", "restricted"}) class Flag { private String name; private Object value; diff --git a/src/jdk.management/share/classes/com/sun/management/internal/PlatformMBeanProviderImpl.java b/src/jdk.management/share/classes/com/sun/management/internal/PlatformMBeanProviderImpl.java index cddb9127d2e9b..cdc5998426d9a 100644 --- a/src/jdk.management/share/classes/com/sun/management/internal/PlatformMBeanProviderImpl.java +++ b/src/jdk.management/share/classes/com/sun/management/internal/PlatformMBeanProviderImpl.java @@ -44,7 +44,7 @@ import sun.management.ManagementFactoryHelper; import sun.management.spi.PlatformMBeanProvider; -@SuppressWarnings("removal") +@SuppressWarnings({"removal", "restricted"}) public final class PlatformMBeanProviderImpl extends PlatformMBeanProvider { static final String DIAGNOSTIC_COMMAND_MBEAN_NAME = "com.sun.management:type=DiagnosticCommand"; diff --git a/src/jdk.management/windows/native/libmanagement_ext/OperatingSystemImpl.c b/src/jdk.management/windows/native/libmanagement_ext/OperatingSystemImpl.c index 746bd97c7ff42..3cfd46791343d 100644 --- a/src/jdk.management/windows/native/libmanagement_ext/OperatingSystemImpl.c +++ b/src/jdk.management/windows/native/libmanagement_ext/OperatingSystemImpl.c @@ -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. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -436,13 +436,13 @@ makeFullCounterPath(const char* const objectName, return NULL; } - _snprintf(fullCounterPath, - fullCounterPathLen, - PROCESS_OBJECT_INSTANCE_COUNTER_FMT, - objectName, - imageName, - instance, - counterName); + snprintf(fullCounterPath, + fullCounterPathLen, + PROCESS_OBJECT_INSTANCE_COUNTER_FMT, + objectName, + imageName, + instance, + counterName); } else { if (instance) { /* @@ -472,18 +472,18 @@ makeFullCounterPath(const char* const objectName, } if (instance) { - _snprintf(fullCounterPath, - fullCounterPathLen, - OBJECT_WITH_INSTANCES_COUNTER_FMT, - objectName, - instance, - counterName); + snprintf(fullCounterPath, + fullCounterPathLen, + OBJECT_WITH_INSTANCES_COUNTER_FMT, + objectName, + instance, + counterName); } else { - _snprintf(fullCounterPath, - fullCounterPathLen, - OBJECT_COUNTER_FMT, - objectName, - counterName); + snprintf(fullCounterPath, + fullCounterPathLen, + OBJECT_COUNTER_FMT, + objectName, + counterName); } } @@ -719,10 +719,10 @@ currentQueryIndexForProcess(void) { PDH_FMT_COUNTERVALUE counterValue; PDH_STATUS res; - _snprintf(fullIDProcessCounterPath, - MAX_PATH, - pdhIDProcessCounterFmt, - index); + snprintf(fullIDProcessCounterPath, + MAX_PATH, + pdhIDProcessCounterFmt, + index); if (addCounter(tmpQuery, fullIDProcessCounterPath, &handleCounter) != 0) { break; @@ -1059,13 +1059,13 @@ allocateAndInitializePdhConstants() { } /* "\Process(java#%d)\ID Process" */ - _snprintf(pdhIDProcessCounterFmt, - pdhIDProcessCounterFmtLen, - PROCESS_OBJECT_INSTANCE_COUNTER_FMT, - pdhLocalizedProcessObject, - pdhProcessImageName, - "%d", - pdhLocalizedIDProcessCounter); + snprintf(pdhIDProcessCounterFmt, + pdhIDProcessCounterFmtLen, + PROCESS_OBJECT_INSTANCE_COUNTER_FMT, + pdhLocalizedProcessObject, + pdhProcessImageName, + "%d", + pdhLocalizedIDProcessCounter); pdhIDProcessCounterFmt[pdhIDProcessCounterFmtLen] = '\0'; diff --git a/src/jdk.net/aix/classes/jdk/net/AIXSocketOptions.java b/src/jdk.net/aix/classes/jdk/net/AIXSocketOptions.java index 9ace5aa33f2e0..086c346ff8f97 100644 --- a/src/jdk.net/aix/classes/jdk/net/AIXSocketOptions.java +++ b/src/jdk.net/aix/classes/jdk/net/AIXSocketOptions.java @@ -32,7 +32,7 @@ import jdk.net.ExtendedSocketOptions.PlatformSocketOptions; import sun.nio.fs.UnixUserPrincipals; -@SuppressWarnings("removal") +@SuppressWarnings({"removal", "restricted"}) class AIXSocketOptions extends PlatformSocketOptions { public AIXSocketOptions() { diff --git a/src/jdk.net/linux/classes/jdk/net/LinuxSocketOptions.java b/src/jdk.net/linux/classes/jdk/net/LinuxSocketOptions.java index 20241bc5f334d..8d3ceeebfa9a3 100644 --- a/src/jdk.net/linux/classes/jdk/net/LinuxSocketOptions.java +++ b/src/jdk.net/linux/classes/jdk/net/LinuxSocketOptions.java @@ -32,7 +32,7 @@ import jdk.net.ExtendedSocketOptions.PlatformSocketOptions; import sun.nio.fs.UnixUserPrincipals; -@SuppressWarnings("removal") +@SuppressWarnings({"removal", "restricted"}) class LinuxSocketOptions extends PlatformSocketOptions { public LinuxSocketOptions() { diff --git a/src/jdk.net/macosx/classes/jdk/net/MacOSXSocketOptions.java b/src/jdk.net/macosx/classes/jdk/net/MacOSXSocketOptions.java index 7ad4bc7650ae7..c2912e8b80808 100644 --- a/src/jdk.net/macosx/classes/jdk/net/MacOSXSocketOptions.java +++ b/src/jdk.net/macosx/classes/jdk/net/MacOSXSocketOptions.java @@ -32,7 +32,7 @@ import jdk.net.ExtendedSocketOptions.PlatformSocketOptions; import sun.nio.fs.UnixUserPrincipals; -@SuppressWarnings("removal") +@SuppressWarnings({"removal", "restricted"}) class MacOSXSocketOptions extends PlatformSocketOptions { public MacOSXSocketOptions() { diff --git a/src/jdk.net/windows/classes/jdk/net/WindowsSocketOptions.java b/src/jdk.net/windows/classes/jdk/net/WindowsSocketOptions.java index 543d584bfe5a1..f5f69e205176f 100644 --- a/src/jdk.net/windows/classes/jdk/net/WindowsSocketOptions.java +++ b/src/jdk.net/windows/classes/jdk/net/WindowsSocketOptions.java @@ -30,7 +30,7 @@ import jdk.net.ExtendedSocketOptions.PlatformSocketOptions; -@SuppressWarnings("removal") +@SuppressWarnings({"removal", "restricted"}) class WindowsSocketOptions extends PlatformSocketOptions { public WindowsSocketOptions() { diff --git a/src/jdk.sctp/unix/classes/sun/nio/ch/sctp/SctpChannelImpl.java b/src/jdk.sctp/unix/classes/sun/nio/ch/sctp/SctpChannelImpl.java index 4355605e25815..2e12e67c6c72c 100644 --- a/src/jdk.sctp/unix/classes/sun/nio/ch/sctp/SctpChannelImpl.java +++ b/src/jdk.sctp/unix/classes/sun/nio/ch/sctp/SctpChannelImpl.java @@ -1094,7 +1094,7 @@ static native int send0(int fd, long address, int length, loadSctpLibrary(); } - @SuppressWarnings("removal") + @SuppressWarnings({"removal", "restricted"}) private static void loadSctpLibrary() { IOUtil.load(); /* loads nio & net native libraries */ AccessController.doPrivileged( diff --git a/src/jdk.sctp/unix/classes/sun/nio/ch/sctp/SctpNet.java b/src/jdk.sctp/unix/classes/sun/nio/ch/sctp/SctpNet.java index 239e09837f7a9..decf964c6cb72 100644 --- a/src/jdk.sctp/unix/classes/sun/nio/ch/sctp/SctpNet.java +++ b/src/jdk.sctp/unix/classes/sun/nio/ch/sctp/SctpNet.java @@ -333,7 +333,7 @@ static native void setInitMsgOption0(int fd, int arg1, int arg2) loadSctpLibrary(); } - @SuppressWarnings("removal") + @SuppressWarnings({"removal", "restricted"}) private static void loadSctpLibrary() { IOUtil.load(); // loads nio & net native libraries java.security.AccessController.doPrivileged( diff --git a/src/jdk.security.auth/share/classes/com/sun/security/auth/module/NTSystem.java b/src/jdk.security.auth/share/classes/com/sun/security/auth/module/NTSystem.java index 0814f0f733282..677d4aefc8663 100644 --- a/src/jdk.security.auth/share/classes/com/sun/security/auth/module/NTSystem.java +++ b/src/jdk.security.auth/share/classes/com/sun/security/auth/module/NTSystem.java @@ -129,7 +129,7 @@ public synchronized long getImpersonationToken() { return impersonationToken; } - + @SuppressWarnings("restricted") private void loadNative() { System.loadLibrary("jaas"); } diff --git a/src/jdk.security.auth/share/classes/com/sun/security/auth/module/UnixSystem.java b/src/jdk.security.auth/share/classes/com/sun/security/auth/module/UnixSystem.java index 96bc1fb32fce4..f3741c1040401 100644 --- a/src/jdk.security.auth/share/classes/com/sun/security/auth/module/UnixSystem.java +++ b/src/jdk.security.auth/share/classes/com/sun/security/auth/module/UnixSystem.java @@ -53,6 +53,7 @@ public class UnixSystem { * Instantiate a {@code UnixSystem} and load * the native library to access the underlying system information. */ + @SuppressWarnings("restricted") public UnixSystem() { System.loadLibrary("jaas"); getUnixInfo(); diff --git a/test/hotspot/gtest/gc/shared/test_collectorPolicy.cpp b/test/hotspot/gtest/gc/shared/test_collectorPolicy.cpp index b38586a89753b..06874ee0698e5 100644 --- a/test/hotspot/gtest/gc/shared/test_collectorPolicy.cpp +++ b/test/hotspot/gtest/gc/shared/test_collectorPolicy.cpp @@ -67,7 +67,7 @@ class TestGenCollectorPolicy { MinHeapSize = 40 * M; FLAG_SET_ERGO(InitialHeapSize, 100 * M); FLAG_SET_ERGO(NewSize, 1 * M); - FLAG_SET_ERGO(MaxNewSize, 80 * M); + FLAG_SET_ERGO(MaxNewSize, 40 * M); ASSERT_NO_FATAL_FAILURE(setter1->execute()); @@ -159,10 +159,16 @@ class TestGenCollectorPolicy { // depends on so many other configurable variables. These tests only try to // verify that there are some basic rules for NewSize honored by the policies. +// Tests require at least 128M of MaxHeap +// otherwise ergonomic is different and generation sizes might be changed. + // If NewSize has been ergonomically set, the collector policy // should use it for min but calculate the initial young size // using NewRatio. TEST_VM(CollectorPolicy, young_scaled_initial_ergo) { + if (MaxHeapSize < 128 * M) { + return; + } TestGenCollectorPolicy::SetNewSizeErgo setter(20 * M); TestGenCollectorPolicy::CheckScaledYoungInitial checker; @@ -175,6 +181,9 @@ TEST_VM(CollectorPolicy, young_scaled_initial_ergo) { // the rest of the VM lifetime. This is an irreversible change and // could impact other tests so we use TEST_OTHER_VM TEST_OTHER_VM(CollectorPolicy, young_cmd) { + if (MaxHeapSize < 128 * M) { + return; + } // If NewSize is set on the command line, it should be used // for both min and initial young size if less than min heap. TestGenCollectorPolicy::SetNewSizeCmd setter(20 * M); @@ -187,7 +196,7 @@ TEST_OTHER_VM(CollectorPolicy, young_cmd) { // If NewSize is set on command line, but is larger than the min // heap size, it should only be used for initial young size. - TestGenCollectorPolicy::SetNewSizeCmd setter_large(80 * M); - TestGenCollectorPolicy::CheckYoungInitial checker_large(80 * M); + TestGenCollectorPolicy::SetNewSizeCmd setter_large(40 * M); + TestGenCollectorPolicy::CheckYoungInitial checker_large(40 * M); TestGenCollectorPolicy::TestWrapper::test(&setter_large, &checker_large); } diff --git a/test/hotspot/gtest/metaspace/test_metaspace_misc.cpp b/test/hotspot/gtest/metaspace/test_metaspace_misc.cpp index 6a2282960e6f6..4d0a3e0774f50 100644 --- a/test/hotspot/gtest/metaspace/test_metaspace_misc.cpp +++ b/test/hotspot/gtest/metaspace/test_metaspace_misc.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2024, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2020 SAP SE. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -67,7 +67,7 @@ TEST_VM(metaspace, misc_max_alloc_size) { ASSERT_NOT_NULL(p); } // And also, successfully deallocate it. - cld->metaspace_non_null()->deallocate(p, sz, in_class_space); + cld->metaspace_non_null()->deallocate(p, sz); } } diff --git a/test/hotspot/jtreg/ProblemList-Xcomp.txt b/test/hotspot/jtreg/ProblemList-Xcomp.txt index 9d91cad1ddeae..8d6b74c8132b6 100644 --- a/test/hotspot/jtreg/ProblemList-Xcomp.txt +++ b/test/hotspot/jtreg/ProblemList-Xcomp.txt @@ -51,3 +51,5 @@ vmTestbase/nsk/jvmti/scenarios/capability/CM03/cm03t001/TestDescription.java 829 vmTestbase/nsk/stress/thread/thread006.java 8321476 linux-all gc/arguments/TestNewSizeFlags.java 8299116 macosx-aarch64 + +runtime/interpreter/LastJsrTest.java 8338924 generic-all diff --git a/test/hotspot/jtreg/compiler/c2/gvn/TestBoolNodeGVN.java b/test/hotspot/jtreg/compiler/c2/gvn/TestBoolNodeGVN.java new file mode 100644 index 0000000000000..3f2fe7ecf053b --- /dev/null +++ b/test/hotspot/jtreg/compiler/c2/gvn/TestBoolNodeGVN.java @@ -0,0 +1,135 @@ +/* + * Copyright (c) 2024 Red Hat and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package compiler.c2.gvn; + +import compiler.lib.ir_framework.*; + +import java.util.Random; + +/** + * @test + * @bug 8327381 + * @summary Refactor boolean node tautology transformations + * @library /test/lib / + * @run driver compiler.c2.gvn.TestBoolNodeGVN + */ +public class TestBoolNodeGVN { + public static void main(String[] args) { + TestFramework.run(); + testCorrectness(); + } + + /** + * Test changing ((x & m) u<= m) or ((m & x) u<= m) to always true, same with ((x & m) u< m+1) and ((m & x) u< m+1) + * The test is only applicable to x64, aarch64 and riscv64 for having Integer.compareUnsigned + * intrinsified. + */ + @Test + @Arguments(values = {Argument.DEFAULT, Argument.DEFAULT}) + @IR(failOn = IRNode.CMP_U, + phase = CompilePhase.AFTER_PARSING, + applyIfPlatformOr = {"x64", "true", "aarch64", "true", "riscv64", "true"}) + public static boolean testShouldReplaceCpmUCase1(int x, int m) { + return !(Integer.compareUnsigned((x & m), m) > 0); // assert in inversions to generates the pattern looking for + } + @Test + @Arguments(values = {Argument.DEFAULT, Argument.DEFAULT}) + @IR(failOn = IRNode.CMP_U, + phase = CompilePhase.AFTER_PARSING, + applyIfPlatformOr = {"x64", "true", "aarch64", "true", "riscv64", "true"}) + public static boolean testShouldReplaceCpmUCase2(int x, int m) { + return !(Integer.compareUnsigned((m & x), m) > 0); + } + + @Test + @Arguments(values = {Argument.DEFAULT, Argument.DEFAULT}) + @IR(failOn = IRNode.CMP_U, + phase = CompilePhase.AFTER_PARSING, + applyIfPlatformOr = {"x64", "true", "aarch64", "true", "riscv64", "true"}) + public static boolean testShouldReplaceCpmUCase3(int x, int m) { + return Integer.compareUnsigned((x & m), m + 1) < 0; + } + + @Test + @Arguments(values = {Argument.DEFAULT, Argument.DEFAULT}) + @IR(failOn = IRNode.CMP_U, + phase = CompilePhase.AFTER_PARSING, + applyIfPlatformOr = {"x64", "true", "aarch64", "true", "riscv64", "true"}) + public static boolean testShouldReplaceCpmUCase4(int x, int m) { + return Integer.compareUnsigned((m & x), m + 1) < 0; + } + + @Test + @Arguments(values = {Argument.DEFAULT, Argument.DEFAULT}) + @IR(counts = {IRNode.CMP_U, "1"}, + phase = CompilePhase.AFTER_PARSING, + applyIfPlatformOr = {"x64", "true", "aarch64", "true", "riscv64", "true"}) + public static boolean testShouldHaveCpmUCase1(int x, int m) { + return !(Integer.compareUnsigned((x & m), m - 1) > 0); + } + + @Test + @Arguments(values = {Argument.DEFAULT, Argument.DEFAULT}) + @IR(counts = {IRNode.CMP_U, "1"}, + phase = CompilePhase.AFTER_PARSING, + applyIfPlatformOr = {"x64", "true", "aarch64", "true", "riscv64", "true"}) + public static boolean testShouldHaveCpmUCase2(int x, int m) { + return !(Integer.compareUnsigned((m & x), m - 1) > 0); + } + + @Test + @Arguments(values = {Argument.DEFAULT, Argument.DEFAULT}) + @IR(counts = {IRNode.CMP_U, "1"}, + phase = CompilePhase.AFTER_PARSING, + applyIfPlatformOr = {"x64", "true", "aarch64", "true", "riscv64", "true"}) + public static boolean testShouldHaveCpmUCase3(int x, int m) { + return Integer.compareUnsigned((x & m), m + 2) < 0; + } + + @Test + @Arguments(values = {Argument.DEFAULT, Argument.DEFAULT}) + @IR(counts = {IRNode.CMP_U, "1"}, + phase = CompilePhase.AFTER_PARSING, + applyIfPlatformOr = {"x64", "true", "aarch64", "true", "riscv64", "true"}) + public static boolean testShouldHaveCpmUCase4(int x, int m) { + return Integer.compareUnsigned((m & x), m + 2) < 0; + } + + private static void testCorrectness() { + int[] values = { + 0, 1, 5, 8, 16, 42, 100, new Random().nextInt(0, Integer.MAX_VALUE), Integer.MAX_VALUE + }; + + for (int x : values) { + for (int m : values) { + if (!testShouldReplaceCpmUCase1(x, m) | + !testShouldReplaceCpmUCase2(x, m) | + !testShouldReplaceCpmUCase3(x, m) | + !testShouldReplaceCpmUCase4(x, m)) { + throw new RuntimeException("Bad result for x = " + x + " and m = " + m + ", expected always true"); + } + } + } + } +} diff --git a/test/hotspot/jtreg/compiler/c2/irTests/scalarReplacement/ScalarReplacementWithGCBarrierTests.java b/test/hotspot/jtreg/compiler/c2/irTests/scalarReplacement/ScalarReplacementWithGCBarrierTests.java new file mode 100644 index 0000000000000..fbf5cdd61cc03 --- /dev/null +++ b/test/hotspot/jtreg/compiler/c2/irTests/scalarReplacement/ScalarReplacementWithGCBarrierTests.java @@ -0,0 +1,118 @@ +/* + * Copyright (c) 2024 Alibaba Group Holding Limited. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package compiler.c2.irTests.scalarReplacement; + +import compiler.lib.ir_framework.*; + +/* + * @test + * @bug 8333334 + * @summary Tests that dead barrier control flows do not affect the scalar replacement. + * @library /test/lib / + * @requires vm.compiler2.enabled + * @requires vm.gc.G1 + * @run driver compiler.c2.irTests.scalarReplacement.ScalarReplacementWithGCBarrierTests + */ +public class ScalarReplacementWithGCBarrierTests { + static class List { + public Node head; + + public void push(int value) { + Node n = new Node(); + n.value = value; + n.next = head; + head = n; + } + + @ForceInline + public Iter iter() { + Iter iter = new Iter(); + iter.list = this; + iter.n = head; + iter.sum = 0; + return iter; + } + } + + static class Node { + public int value; + public Node next; + } + + static class Iter { + public List list; + public Node n; + public Integer sum; + + @ForceInline + public boolean next() { + int lastSum = sum; + while (sum - lastSum < 1000) { + while (n != null && n.value < 30) n = n.next; + if (n == null) return false; + sum += n.value; + n = n.next; + } + return true; + } + } + + private static final int SIZE = 1000; + + public static void main(String[] args) { + // Must use G1 GC to ensure there is a pre-barrier + // before the first field write. + TestFramework.runWithFlags("-XX:+UseG1GC"); + } + + @Run(test = "testScalarReplacementWithGCBarrier") + private void runner() { + List list = new List(); + for (int i = 0; i < SIZE; i++) { + list.push(i); + } + testScalarReplacementWithGCBarrier(list); + } + + // Allocation of `Iter iter` should be eliminated by scalar replacement, and + // the allocation of `Integer sum` can not be eliminated, so there should be + // 1 allocation after allocations and locks elimination. + // + // Before the patch of JDK-8333334, both allocations of `Iter` and `Integer` + // could not be eliminated. + @Test + @IR(phase = { CompilePhase.AFTER_PARSING }, counts = { IRNode.ALLOC, "1" }) + @IR(phase = { CompilePhase.INCREMENTAL_BOXING_INLINE }, counts = { IRNode.ALLOC, "2" }) + @IR(phase = { CompilePhase.ITER_GVN_AFTER_ELIMINATION }, counts = { IRNode.ALLOC, "1" }) + private int testScalarReplacementWithGCBarrier(List list) { + Iter iter = list.iter(); + while (true) { + while (iter.next()) {} + if (list.head == null) break; + list.head = list.head.next; + iter.n = list.head; + } + return iter.sum; + } +} diff --git a/test/hotspot/jtreg/compiler/lib/ir_framework/IRNode.java b/test/hotspot/jtreg/compiler/lib/ir_framework/IRNode.java index 9fe3f42f61afb..7055e001118dc 100644 --- a/test/hotspot/jtreg/compiler/lib/ir_framework/IRNode.java +++ b/test/hotspot/jtreg/compiler/lib/ir_framework/IRNode.java @@ -445,7 +445,7 @@ public class IRNode { public static final String CMP_U = PREFIX + "CMP_U" + POSTFIX; static { - beforeMatchingNameRegex(CMP_U, "CmpU"); + beforeMatchingNameRegex(CMP_U, "CmpU\\b"); } public static final String CMP_U3 = PREFIX + "CMP_U3" + POSTFIX; diff --git a/test/hotspot/jtreg/compiler/loopopts/TestSunkNodeInInfiniteLoop.java b/test/hotspot/jtreg/compiler/loopopts/TestSunkNodeInInfiniteLoop.java new file mode 100644 index 0000000000000..7ab05cca242d6 --- /dev/null +++ b/test/hotspot/jtreg/compiler/loopopts/TestSunkNodeInInfiniteLoop.java @@ -0,0 +1,57 @@ +/* + * Copyright (c) 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8336830 + * @summary C2: assert(get_loop(lca)->_nest < n_loop->_nest || lca->in(0)->is_NeverBranch()) failed: must not be moved into inner loop + * @library /test/lib + * @run main/othervm -XX:CompileCommand=compileonly,TestSunkNodeInInfiniteLoop::* -Xcomp TestSunkNodeInInfiniteLoop + * + */ + +import jdk.test.lib.Utils; + +public class TestSunkNodeInInfiniteLoop { + public static void main(String[] args) throws InterruptedException { + byte[] a = new byte[1]; + Thread thread = new Thread(() -> test(a)); + thread.setDaemon(true); + thread.start(); + Thread.sleep(Utils.adjustTimeout(4000)); + } + + static void test(byte[] a) { + // L0: + while(true) { + int i1 = a.length; + // L3: + while(true) { + int i2 = 0; + if ((i1--) <= 0) { break; /* ifle L0 */} + a[i2++] = -1; + // goto L3 + } + } + } +} diff --git a/test/hotspot/jtreg/runtime/CommandLine/VMDeprecatedOptions.java b/test/hotspot/jtreg/runtime/CommandLine/VMDeprecatedOptions.java index 4e6252ae20510..96bc22dfb1d05 100644 --- a/test/hotspot/jtreg/runtime/CommandLine/VMDeprecatedOptions.java +++ b/test/hotspot/jtreg/runtime/CommandLine/VMDeprecatedOptions.java @@ -70,6 +70,9 @@ public class VMDeprecatedOptions { }) ); } + if (Platform.isLinux()) { + deprecated.add(new String[] { "UseLinuxPosixThreadCPUClocks", "true" }); + } if (wb.isJFRIncluded()) { deprecated.add(new String[] {"FlightRecorder", "false"}); } diff --git a/test/hotspot/jtreg/runtime/cds/appcds/TestParallelGCWithCDS.java b/test/hotspot/jtreg/runtime/cds/appcds/TestParallelGCWithCDS.java index 3f759d13a4ca9..691c87fef360c 100644 --- a/test/hotspot/jtreg/runtime/cds/appcds/TestParallelGCWithCDS.java +++ b/test/hotspot/jtreg/runtime/cds/appcds/TestParallelGCWithCDS.java @@ -116,8 +116,9 @@ static void test(boolean dumpWithParallel, boolean execWithParallel, boolean use } else { String pattern = "((Too small maximum heap)" + "|(GC triggered before VM initialization completed)" + - "|(java.lang.OutOfMemoryError: Java heap space)" + - "|(Initial heap size set to a larger value than the maximum heap size))"; + "|(Initial heap size set to a larger value than the maximum heap size)" + + "|(java.lang.OutOfMemoryError)" + + "|(Error: A JNI error has occurred, please check your installation and try again))"; out.shouldMatch(pattern); out.shouldNotHaveFatalError(); } diff --git a/test/hotspot/jtreg/runtime/exceptionMsgs/NoClassDefFoundError/NoClassDefFoundErrorTest.java b/test/hotspot/jtreg/runtime/exceptionMsgs/NoClassDefFoundError/NoClassDefFoundErrorTest.java index d369f77f32433..b03d627485014 100644 --- a/test/hotspot/jtreg/runtime/exceptionMsgs/NoClassDefFoundError/NoClassDefFoundErrorTest.java +++ b/test/hotspot/jtreg/runtime/exceptionMsgs/NoClassDefFoundError/NoClassDefFoundErrorTest.java @@ -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 @@ -23,12 +23,12 @@ /* * @test - * @bug 8056900 + * @bug 8056900 8338888 * @summary Verifies message returned with NoClassDefFoundError exception. * @library /test/lib * @modules java.base/jdk.internal.misc * java.compiler - * @run main/native NoClassDefFoundErrorTest + * @run main/native/othervm -Xlog:exceptions=info NoClassDefFoundErrorTest */ import jdk.test.lib.compiler.InMemoryJavaCompiler; @@ -36,8 +36,14 @@ public class NoClassDefFoundErrorTest { + // Use the specified name static native void callDefineClass(String className); static native void callFindClass(String className); + // Use a name longer than a Java string - returns false + // if native allocation failed. + static native boolean tryCallDefineClass(); + static native boolean tryCallFindClass(); + static { System.loadLibrary("NoClassDefFoundErrorTest"); } @@ -54,7 +60,7 @@ public static void main(String args[]) throws Exception { tooBigClassName = tooBigClassName.append(tooBigClassName); } - // Test JVM_DefineClass() with long name. + System.out.println("Test JVM_DefineClass() with long name"); try { unsafe.defineClass(tooBigClassName.toString(), klassbuf, 4, klassbuf.length - 4, null, null); throw new RuntimeException("defineClass did not throw expected NoClassDefFoundError"); @@ -64,7 +70,7 @@ public static void main(String args[]) throws Exception { } } - // Test JNI_DefineClass() with long name. + System.out.println("Test JNI_DefineClass() with long name"); try { callDefineClass(tooBigClassName.toString()); throw new RuntimeException("DefineClass did not throw expected NoClassDefFoundError"); @@ -74,17 +80,17 @@ public static void main(String args[]) throws Exception { } } - // Test JNI_FindClass() with long name. + System.out.println("Test JNI_FindClass() with long name"); try { callFindClass(tooBigClassName.toString()); - throw new RuntimeException("DefineClass did not throw expected NoClassDefFoundError"); + throw new RuntimeException("FindClass did not throw expected NoClassDefFoundError"); } catch (NoClassDefFoundError e) { if (!e.getMessage().contains("Class name exceeds maximum length of ")) { throw new RuntimeException("Wrong NoClassDefFoundError: " + e.getMessage()); } } - // Test JNI_FindClass() with null name. + System.out.println("Test JNI_FindClass() with null name"); try { callFindClass(null); throw new RuntimeException("FindClass did not throw expected NoClassDefFoundError"); @@ -93,5 +99,31 @@ public static void main(String args[]) throws Exception { throw new RuntimeException("Wrong NoClassDefFoundError: " + e.getMessage()); } } + + System.out.println("Test JNI_DefineClass() with giant name"); + try { + if (tryCallDefineClass()) { + throw new RuntimeException("DefineClass did not throw expected NoClassDefFoundError"); + } else { + System.out.println("Test skipped due to native allocation failure"); + } + } catch (NoClassDefFoundError e) { + if (!e.getMessage().contains("Class name exceeds maximum length of ")) { + throw new RuntimeException("Wrong NoClassDefFoundError: " + e.getMessage()); + } + } + + System.out.println("Test JNI_FindClass() with giant name"); + try { + if (tryCallFindClass()) { + throw new RuntimeException("FindClass did not throw expected NoClassDefFoundError"); + } else { + System.out.println("Test skipped due to native allocation failure"); + } + } catch (NoClassDefFoundError e) { + if (!e.getMessage().contains("Class name exceeds maximum length of ")) { + throw new RuntimeException("Wrong NoClassDefFoundError: " + e.getMessage()); + } + } } } diff --git a/test/hotspot/jtreg/runtime/exceptionMsgs/NoClassDefFoundError/libNoClassDefFoundErrorTest.c b/test/hotspot/jtreg/runtime/exceptionMsgs/NoClassDefFoundError/libNoClassDefFoundErrorTest.c index 607d2541a8994..023f299a5d404 100644 --- a/test/hotspot/jtreg/runtime/exceptionMsgs/NoClassDefFoundError/libNoClassDefFoundErrorTest.c +++ b/test/hotspot/jtreg/runtime/exceptionMsgs/NoClassDefFoundError/libNoClassDefFoundErrorTest.c @@ -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 @@ -22,6 +22,10 @@ */ #include +#include +#include +#include + JNIEXPORT void JNICALL Java_NoClassDefFoundErrorTest_callDefineClass(JNIEnv *env, jclass klass, jstring className) { @@ -42,3 +46,34 @@ Java_NoClassDefFoundErrorTest_callFindClass(JNIEnv *env, jclass klass, jstring c } +static char* giant_string() { + size_t len = ((size_t)INT_MAX) + 3; + char* c_name = malloc(len * sizeof(char)); + if (c_name != NULL) { + memset(c_name, 'Y', len - 1); + c_name[len - 1] = '\0'; + } + return c_name; +} + +JNIEXPORT jboolean JNICALL +Java_NoClassDefFoundErrorTest_tryCallDefineClass(JNIEnv *env, jclass klass) { + char* c_name = giant_string(); + if (c_name != NULL) { + (*env)->DefineClass(env, c_name, NULL, NULL, 0); + free(c_name); + return JNI_TRUE; + } + return JNI_FALSE; +} + +JNIEXPORT jboolean JNICALL +Java_NoClassDefFoundErrorTest_tryCallFindClass(JNIEnv *env, jclass klass) { + char* c_name = giant_string(); + if (c_name != NULL) { + jclass cls = (*env)->FindClass(env, c_name); + free(c_name); + return JNI_TRUE; + } + return JNI_FALSE; +} diff --git a/test/hotspot/jtreg/runtime/interpreter/LastJsr.jasm b/test/hotspot/jtreg/runtime/interpreter/LastJsr.jasm new file mode 100644 index 0000000000000..4f53cbc18ad7b --- /dev/null +++ b/test/hotspot/jtreg/runtime/interpreter/LastJsr.jasm @@ -0,0 +1,35 @@ +/* + * Copyright (c) 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 + * 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. + * + */ + +super public class LastJsr +{ + public static Method test:"()V" + stack 100 locals 100 + { + return; + LABEL: + nop; + jsr LABEL; // bci=2. Compute bci + length(jsr) -> bci = 5 accessed, out of bounds. + } +} diff --git a/test/hotspot/jtreg/runtime/interpreter/LastJsrReachable.jasm b/test/hotspot/jtreg/runtime/interpreter/LastJsrReachable.jasm new file mode 100644 index 0000000000000..5bcc3ffd382a8 --- /dev/null +++ b/test/hotspot/jtreg/runtime/interpreter/LastJsrReachable.jasm @@ -0,0 +1,37 @@ +/* + * Copyright (c) 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 + * 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. + * + */ + +super public class LastJsrReachable +{ + public static Method test:"()V" + stack 100 locals 100 + { + goto LB2; + LABEL: + return; + LB2: + nop; + jsr LABEL; + } +} diff --git a/test/hotspot/jtreg/runtime/interpreter/LastJsrTest.java b/test/hotspot/jtreg/runtime/interpreter/LastJsrTest.java new file mode 100644 index 0000000000000..913a304ae38a3 --- /dev/null +++ b/test/hotspot/jtreg/runtime/interpreter/LastJsrTest.java @@ -0,0 +1,40 @@ +/* + * Copyright (c) 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @bug 8335664 + * @summary Ensure a program that ends with a JSR does not crash + * @library /test/lib + * @compile LastJsr.jasm + * @compile LastJsrReachable.jasm + * @run main/othervm LastJsrTest + */ + +public class LastJsrTest { + public static void main(String[] args) { + LastJsr.test(); + LastJsrReachable.test(); + System.out.println("PASSED"); + } +} diff --git a/test/hotspot/jtreg/runtime/jni/checked/TestCheckedReleaseArrayElements.java b/test/hotspot/jtreg/runtime/jni/checked/TestCheckedReleaseArrayElements.java index 6bc09b8a03451..07e46a1dfcac0 100644 --- a/test/hotspot/jtreg/runtime/jni/checked/TestCheckedReleaseArrayElements.java +++ b/test/hotspot/jtreg/runtime/jni/checked/TestCheckedReleaseArrayElements.java @@ -49,6 +49,7 @@ public static void main(String[] args) throws Throwable { // that might generate output on stderr (which should be empty for this test). ProcessBuilder pb = ProcessTools.createLimitedTestJavaProcessBuilder("-Xcheck:jni", + "--enable-native-access=ALL-UNNAMED", "-Djava.library.path=" + Utils.TEST_NATIVE_PATH, "TestCheckedReleaseArrayElements"); OutputAnalyzer output = ProcessTools.executeProcess(pb); diff --git a/test/jdk/ProblemList.txt b/test/jdk/ProblemList.txt index bbf594f3bc70b..697fe82187ca3 100644 --- a/test/jdk/ProblemList.txt +++ b/test/jdk/ProblemList.txt @@ -375,7 +375,7 @@ java/awt/Modal/MultipleDialogs/MultipleDialogs3Test.java 8198665 macosx-all java/awt/Modal/MultipleDialogs/MultipleDialogs4Test.java 8198665 macosx-all java/awt/Modal/MultipleDialogs/MultipleDialogs5Test.java 8198665 macosx-all java/awt/Mouse/EnterExitEvents/DragWindowOutOfFrameTest.java 8177326 macosx-all -java/awt/Mouse/EnterExitEvents/ResizingFrameTest.java 8005021,8332158 macosx-all,linux-x64 +java/awt/Mouse/EnterExitEvents/ResizingFrameTest.java 8005021 macosx-all java/awt/Mouse/EnterExitEvents/FullscreenEnterEventTest.java 8051455 macosx-all java/awt/Mouse/MouseModifiersUnitTest/MouseModifiersUnitTest_Standard.java 7124407,8302787 macosx-all,windows-all java/awt/Mouse/RemovedComponentMouseListener/RemovedComponentMouseListener.java 8157170 macosx-all diff --git a/test/jdk/java/awt/Mouse/EnterExitEvents/ResizingFrameTest.java b/test/jdk/java/awt/Mouse/EnterExitEvents/ResizingFrameTest.java index 51e5dd353a98d..2918a6a5e0a89 100644 --- a/test/jdk/java/awt/Mouse/EnterExitEvents/ResizingFrameTest.java +++ b/test/jdk/java/awt/Mouse/EnterExitEvents/ResizingFrameTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2006, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 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 @@ -27,12 +27,19 @@ * @bug 7154048 * @summary Programmatically resized window does not receive mouse entered/exited events * @author alexandr.scherbatiy area=awt.event + * @library /test/lib + * @build jdk.test.lib.Platform * @run main ResizingFrameTest */ -import java.awt.*; -import java.awt.event.*; -import javax.swing.*; +import java.awt.Frame; +import java.awt.Robot; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; +import javax.swing.JFrame; +import javax.swing.SwingUtilities; + +import jdk.test.lib.Platform; public class ResizingFrameTest { @@ -41,6 +48,9 @@ public class ResizingFrameTest { private static JFrame frame; public static void main(String[] args) throws Exception { + if (Platform.isOnWayland()) { + return; + } Robot robot = new Robot(); robot.setAutoDelay(50); diff --git a/test/jdk/java/foreign/TestDereferencePath.java b/test/jdk/java/foreign/TestDereferencePath.java index 1b26cce9c6fcf..116f2d318fc6f 100644 --- a/test/jdk/java/foreign/TestDereferencePath.java +++ b/test/jdk/java/foreign/TestDereferencePath.java @@ -119,6 +119,30 @@ public void testMulti() { } } + static final MemoryLayout A_VALUE = MemoryLayout.structLayout( + ValueLayout.ADDRESS.withName("b") + .withTargetLayout(ValueLayout.JAVA_INT) + ); + + static final VarHandle a_value = A_VALUE.varHandle( + PathElement.groupElement("b"), PathElement.dereferenceElement()); + + @Test + public void testDerefValue() { + try (Arena arena = Arena.ofConfined()) { + // init structs + MemorySegment a = arena.allocate(A); + MemorySegment b = arena.allocate(ValueLayout.JAVA_INT); + // init struct fields + a.set(ValueLayout.ADDRESS, 0, b); + b.set(ValueLayout.JAVA_INT, 0, 42); + // dereference + int val = (int) a_value.get(a, 0L); + assertEquals(val, 42); + } + } + + @Test(expectedExceptions = IllegalArgumentException.class) void testBadDerefInSelect() { A.select(PathElement.groupElement("b"), PathElement.dereferenceElement()); diff --git a/test/jdk/java/foreign/TestLayoutPaths.java b/test/jdk/java/foreign/TestLayoutPaths.java index 414eb4117ced7..6729fbf823682 100644 --- a/test/jdk/java/foreign/TestLayoutPaths.java +++ b/test/jdk/java/foreign/TestLayoutPaths.java @@ -332,6 +332,14 @@ public void testOffsetHandleOOBIndex(MemoryLayout layout, PathElement[] pathElem } } + @Test(dataProvider = "testLayouts", expectedExceptions = ArithmeticException.class) + public void testOffsetHandleOverflow(MemoryLayout layout, PathElement[] pathElements, long[] indexes, + long expectedByteOffset) throws Throwable { + MethodHandle byteOffsetHandle = layout.byteOffsetHandle(pathElements); + byteOffsetHandle = byteOffsetHandle.asSpreader(long[].class, indexes.length); + byteOffsetHandle.invoke(Long.MAX_VALUE, indexes); + } + @Test(dataProvider = "testLayouts") public void testVarHandleBadSegment(MemoryLayout layout, PathElement[] pathElements, long[] indexes, long expectedByteOffset) throws Throwable { diff --git a/test/jdk/java/foreign/TestRestricted.java b/test/jdk/java/foreign/TestRestricted.java index beccd89582978..b5b0974e57ab2 100644 --- a/test/jdk/java/foreign/TestRestricted.java +++ b/test/jdk/java/foreign/TestRestricted.java @@ -88,7 +88,11 @@ static RestrictedMethod of(Class owner, String name, Class returnType, Cla RestrictedMethod.of(MemorySegment.class, "reinterpret", MemorySegment.class, Arena.class, Consumer.class), RestrictedMethod.of(MemorySegment.class, "reinterpret", MemorySegment.class, long.class, Arena.class, Consumer.class), RestrictedMethod.of(AddressLayout.class, "withTargetLayout", AddressLayout.class, MemoryLayout.class), - RestrictedMethod.of(ModuleLayer.Controller.class, "enableNativeAccess", ModuleLayer.Controller.class, Module.class) + RestrictedMethod.of(ModuleLayer.Controller.class, "enableNativeAccess", ModuleLayer.Controller.class, Module.class), + RestrictedMethod.of(System.class, "load", void.class, String.class), + RestrictedMethod.of(System.class, "loadLibrary", void.class, String.class), + RestrictedMethod.of(Runtime.class, "load", void.class, String.class), + RestrictedMethod.of(Runtime.class, "loadLibrary", void.class, String.class) ); @Test diff --git a/test/jdk/java/foreign/enablenativeaccess/TestEnableNativeAccess.java b/test/jdk/java/foreign/enablenativeaccess/TestEnableNativeAccess.java index 9dd228f5152b6..230b32968da0a 100644 --- a/test/jdk/java/foreign/enablenativeaccess/TestEnableNativeAccess.java +++ b/test/jdk/java/foreign/enablenativeaccess/TestEnableNativeAccess.java @@ -28,6 +28,10 @@ * @library /test/lib * @build TestEnableNativeAccess * panama_module/* + * panama_jni_load_module/* + * panama_jni_def_module/* + * panama_jni_use_module/* + * * org.openjdk.foreigntest.unnamed.PanamaMainUnnamedModule * @run testng/othervm/timeout=180 TestEnableNativeAccess * @summary Basic test for java --enable-native-access @@ -62,20 +66,25 @@ public Object[][] succeedCases() { { "panama_enable_native_access", PANAMA_MAIN, successNoWarning(), new String[]{"--enable-native-access=panama_module"} }, { "panama_enable_native_access_reflection", PANAMA_REFLECTION, successNoWarning(), new String[]{"--enable-native-access=panama_module"} }, { "panama_enable_native_access_invoke", PANAMA_INVOKE, successNoWarning(), new String[]{"--enable-native-access=panama_module"} }, - { "panama_enable_native_access_jni", PANAMA_JNI, successNoWarning(), new String[]{"--enable-native-access=ALL-UNNAMED"} }, { "panama_comma_separated_enable", PANAMA_MAIN, successNoWarning(), new String[]{"--enable-native-access=java.base,panama_module"} }, { "panama_comma_separated_enable_reflection", PANAMA_REFLECTION, successNoWarning(), new String[]{"--enable-native-access=java.base,panama_module"} }, { "panama_comma_separated_enable_invoke", PANAMA_INVOKE, successNoWarning(), new String[]{"--enable-native-access=java.base,panama_module"} }, - { "panama_comma_separated_enable_jni", PANAMA_JNI, successNoWarning(), new String[]{"--enable-native-access=java.base,ALL-UNNAMED"} }, + { "panama_comma_separated_enable_jni", PANAMA_JNI, successNoWarning(), new String[]{"--enable-native-access=panama_jni_load_module,panama_jni_def_module,ALL-UNNAMED"} }, { "panama_enable_native_access_warn", PANAMA_MAIN, successWithWarning("panama"), new String[]{} }, { "panama_enable_native_access_warn_reflection", PANAMA_REFLECTION, successWithWarning("panama"), new String[]{} }, { "panama_enable_native_access_warn_invoke", PANAMA_INVOKE, successWithWarning("panama"), new String[]{} }, - { "panama_enable_native_access_warn_jni", PANAMA_JNI, successWithWarning("ALL-UNNAMED"), new String[]{} }, + { "panama_enable_native_access_warn_jni", PANAMA_JNI, successWithWarnings("panama_jni_load_module", "panama_jni_def_module", "ALL-UNNAMED"), new String[]{} }, + + { "panama_enable_native_access_allow", PANAMA_MAIN, successNoWarning(), new String[]{"--illegal-native-access=allow"} }, + { "panama_enable_native_access_allow_reflection", PANAMA_REFLECTION, successNoWarning(), new String[]{"--illegal-native-access=allow"} }, + { "panama_enable_native_access_allow_invoke", PANAMA_INVOKE, successNoWarning(), new String[]{"--illegal-native-access=allow"} }, + { "panama_enable_native_access_allow_jni", PANAMA_JNI, successNoWarning(), new String[]{"--illegal-native-access=allow"} }, { "panama_no_unnamed_module_native_access", UNNAMED, successWithWarning("ALL-UNNAMED"), new String[]{} }, { "panama_all_unnamed_module_native_access", UNNAMED, successNoWarning(), new String[]{"--enable-native-access=ALL-UNNAMED"} }, + { "panama_allow_unnamed_module_native_access", UNNAMED, successNoWarning(), new String[]{"--illegal-native-access=allow"} }, }; } @@ -131,12 +140,38 @@ public void testRepeatedOption() throws Exception { * Specifies bad value to --enable-native-access. */ public void testBadValue() throws Exception { - run("panama_enable_native_access_warn_unknown_module", PANAMA_MAIN, + run("panama_deny_bad_unknown_module", PANAMA_MAIN, failWithWarning("WARNING: Unknown module: BAD specified to --enable-native-access"), - "--enable-native-access=BAD"); - run("panama_no_all_module_path_blanket_native_access", PANAMA_MAIN, + "--illegal-native-access=deny", "--enable-native-access=BAD"); + run("panama_deny_bad_all_module_path_module", PANAMA_MAIN, failWithWarning("WARNING: Unknown module: ALL-MODULE-PATH specified to --enable-native-access"), - "--enable-native-access=ALL-MODULE-PATH" ); + "--illegal-native-access=deny", "--enable-native-access=ALL-MODULE-PATH" ); + run("panama_deny_no_module_main", PANAMA_MAIN, + failWithError("module panama_module"), + "--illegal-native-access=deny"); + run("panama_deny_no_module_invoke", PANAMA_INVOKE, + failWithError("module panama_module"), + "--illegal-native-access=deny"); + run("panama_deny_no_module_reflection", PANAMA_REFLECTION, + failWithError("module panama_module"), + "--illegal-native-access=deny"); + run("panama_deny_no_module_jni", PANAMA_JNI, + failWithError("module panama_jni_load_module"), + "--illegal-native-access=deny"); + } + + public void testDetailedWarningMessage() throws Exception { + run("panama_enable_native_access_warn_jni", PANAMA_JNI, + success() + // call to System::loadLibrary from panama_jni_load_module + .expect("WARNING: A restricted method in java.lang.System has been called") + .expect("WARNING: java.lang.System::loadLibrary has been called by org.openjdk.jni.PanamaMainJNI in module panama_jni_load_module") + // JNI native method binding in panama_jni_def_module + .expect("WARNING: A native method in org.openjdk.jni.def.PanamaJNIDef has been bound") + .expect("WARNING: org.openjdk.jni.def.PanamaJNIDef::nativeLinker0 is declared in module panama_jni_def_module") + // upcall to Linker::downcallHandle from JNI code + .expect("WARNING: A restricted method in java.lang.foreign.Linker has been called") + .expect("WARNING: java.lang.foreign.Linker::downcallHandle has been called by code in an unnamed module")); } private int count(Iterable lines, CharSequence cs) { diff --git a/test/jdk/java/foreign/enablenativeaccess/TestEnableNativeAccessBase.java b/test/jdk/java/foreign/enablenativeaccess/TestEnableNativeAccessBase.java index b5afb727997ba..5f02e7cc4ace7 100644 --- a/test/jdk/java/foreign/enablenativeaccess/TestEnableNativeAccessBase.java +++ b/test/jdk/java/foreign/enablenativeaccess/TestEnableNativeAccessBase.java @@ -38,8 +38,8 @@ public class TestEnableNativeAccessBase { static final String PANAMA_REFLECTION = "panama_module/" + PANAMA_REFLECTION_CLS; static final String PANAMA_INVOKE_CLS = "org.openjdk.foreigntest.PanamaMainInvoke"; static final String PANAMA_INVOKE = "panama_module/" + PANAMA_INVOKE_CLS; - static final String PANAMA_JNI_CLS = "org.openjdk.foreigntest.PanamaMainJNI"; - static final String PANAMA_JNI = "panama_module/" + PANAMA_JNI_CLS; + static final String PANAMA_JNI_CLS = "org.openjdk.jni.PanamaMainJNI"; + static final String PANAMA_JNI = "panama_jni_load_module/" + PANAMA_JNI_CLS; static final String UNNAMED = "org.openjdk.foreigntest.unnamed.PanamaMainUnnamedModule"; /** @@ -99,6 +99,14 @@ static Result successWithWarning(String moduleName) { return success().expect("WARNING").expect("--enable-native-access=" + moduleName); } + static Result successWithWarnings(String... moduleNames) { + Result result = success(); + for (String moduleName : moduleNames) { + result = result.expect("WARNING").expect("--enable-native-access=" + moduleName); + } + return result; + } + static Result failWithWarning(String expectedOutput) { return new Result(false).expect(expectedOutput).expect("WARNING"); } diff --git a/test/jdk/java/foreign/enablenativeaccess/TestEnableNativeAccessDynamic.java b/test/jdk/java/foreign/enablenativeaccess/TestEnableNativeAccessDynamic.java index fa09b0eb41454..f0a8d463a7fc0 100644 --- a/test/jdk/java/foreign/enablenativeaccess/TestEnableNativeAccessDynamic.java +++ b/test/jdk/java/foreign/enablenativeaccess/TestEnableNativeAccessDynamic.java @@ -56,7 +56,7 @@ public Object[][] succeedCases() { @DataProvider(name = "failureCases") public Object[][] failureCases() { - String errMsg = "Illegal native access from: module panama_module"; + String errMsg = "Illegal native access from module panama_module"; return new Object[][] { { "panama_enable_native_access_fail", PANAMA_MAIN, failWithError(errMsg) }, { "panama_enable_native_access_fail_reflection", PANAMA_REFLECTION, failWithError(errMsg) }, @@ -73,6 +73,7 @@ OutputAnalyzer run(String action, String moduleAndCls, boolean enableNativeAcces Result expectedResult, boolean panamaModuleInBootLayer) throws Exception { List list = new ArrayList<>(); + list.add("--illegal-native-access=deny"); if (panamaModuleInBootLayer) { list.addAll(List.of("-p", MODULE_PATH)); list.add("--add-modules=panama_module"); diff --git a/test/jdk/java/foreign/enablenativeaccess/panama_jni_def_module/module-info.java b/test/jdk/java/foreign/enablenativeaccess/panama_jni_def_module/module-info.java new file mode 100644 index 0000000000000..85c00ce5daec3 --- /dev/null +++ b/test/jdk/java/foreign/enablenativeaccess/panama_jni_def_module/module-info.java @@ -0,0 +1,26 @@ +/* + * Copyright (c) 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 + * 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. + */ + +module panama_jni_def_module { + exports org.openjdk.jni.def; +} diff --git a/test/jdk/java/foreign/enablenativeaccess/panama_jni_def_module/org/openjdk/jni/def/PanamaJNIDef.java b/test/jdk/java/foreign/enablenativeaccess/panama_jni_def_module/org/openjdk/jni/def/PanamaJNIDef.java new file mode 100644 index 0000000000000..402ce9278e9ee --- /dev/null +++ b/test/jdk/java/foreign/enablenativeaccess/panama_jni_def_module/org/openjdk/jni/def/PanamaJNIDef.java @@ -0,0 +1,32 @@ +/* + * Copyright (c) 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package org.openjdk.jni.def; + +import java.lang.foreign.FunctionDescriptor; +import java.lang.foreign.Linker; + +public class PanamaJNIDef { + + public static native void nativeLinker0(Linker linker, FunctionDescriptor desc, Linker.Option[] options); +} diff --git a/test/jdk/java/foreign/enablenativeaccess/panama_module/org/openjdk/foreigntest/libLinkerInvokerModule.cpp b/test/jdk/java/foreign/enablenativeaccess/panama_jni_def_module/org/openjdk/jni/def/libLinkerInvokerModule.cpp similarity index 94% rename from test/jdk/java/foreign/enablenativeaccess/panama_module/org/openjdk/foreigntest/libLinkerInvokerModule.cpp rename to test/jdk/java/foreign/enablenativeaccess/panama_jni_def_module/org/openjdk/jni/def/libLinkerInvokerModule.cpp index 4591d7a506ae3..c46e6e6acdba8 100644 --- a/test/jdk/java/foreign/enablenativeaccess/panama_module/org/openjdk/foreigntest/libLinkerInvokerModule.cpp +++ b/test/jdk/java/foreign/enablenativeaccess/panama_jni_def_module/org/openjdk/jni/def/libLinkerInvokerModule.cpp @@ -47,7 +47,7 @@ void call(void* arg) { extern "C" { JNIEXPORT void JNICALL - Java_org_openjdk_foreigntest_PanamaMainJNI_nativeLinker0(JNIEnv *env, jclass cls, jobject linker, jobject desc, jobjectArray opts) { + Java_org_openjdk_jni_def_PanamaJNIDef_nativeLinker0(JNIEnv *env, jclass cls, jobject linker, jobject desc, jobjectArray opts) { Context context; env->GetJavaVM(&context.jvm); context.linker = env->NewGlobalRef(linker); diff --git a/test/jdk/java/foreign/enablenativeaccess/panama_jni_load_module/module-info.java b/test/jdk/java/foreign/enablenativeaccess/panama_jni_load_module/module-info.java new file mode 100644 index 0000000000000..87e4d8dac050b --- /dev/null +++ b/test/jdk/java/foreign/enablenativeaccess/panama_jni_load_module/module-info.java @@ -0,0 +1,27 @@ +/* + * Copyright (c) 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 + * 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. + */ + +module panama_jni_load_module { + exports org.openjdk.jni; + requires panama_jni_use_module; +} diff --git a/test/jdk/java/foreign/enablenativeaccess/panama_jni_load_module/org/openjdk/jni/PanamaMainJNI.java b/test/jdk/java/foreign/enablenativeaccess/panama_jni_load_module/org/openjdk/jni/PanamaMainJNI.java new file mode 100644 index 0000000000000..e50dedf181e9b --- /dev/null +++ b/test/jdk/java/foreign/enablenativeaccess/panama_jni_load_module/org/openjdk/jni/PanamaMainJNI.java @@ -0,0 +1,34 @@ +/* + * Copyright (c) 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package org.openjdk.jni; + +import org.openjdk.jni.use.PanamaJNIUse; + +public class PanamaMainJNI { + + public static void main(String[] args) { + System.loadLibrary("LinkerInvokerModule"); + PanamaJNIUse.run(); + } +} diff --git a/test/jdk/java/foreign/enablenativeaccess/panama_jni_use_module/module-info.java b/test/jdk/java/foreign/enablenativeaccess/panama_jni_use_module/module-info.java new file mode 100644 index 0000000000000..daeca16c132fd --- /dev/null +++ b/test/jdk/java/foreign/enablenativeaccess/panama_jni_use_module/module-info.java @@ -0,0 +1,27 @@ +/* + * Copyright (c) 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 + * 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. + */ + +module panama_jni_use_module { + exports org.openjdk.jni.use; + requires panama_jni_def_module; +} diff --git a/test/jdk/java/foreign/enablenativeaccess/panama_jni_use_module/org/openjdk/jni/use/PanamaJNIUse.java b/test/jdk/java/foreign/enablenativeaccess/panama_jni_use_module/org/openjdk/jni/use/PanamaJNIUse.java new file mode 100644 index 0000000000000..2445b4951dc59 --- /dev/null +++ b/test/jdk/java/foreign/enablenativeaccess/panama_jni_use_module/org/openjdk/jni/use/PanamaJNIUse.java @@ -0,0 +1,41 @@ +/* + * Copyright (c) 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package org.openjdk.jni.use; + +import java.lang.foreign.FunctionDescriptor; +import java.lang.foreign.Linker; + +import org.openjdk.jni.def.PanamaJNIDef; + +public class PanamaJNIUse { + public static void run() { + testDirectAccessCLinker(); + } + + public static void testDirectAccessCLinker() { + System.out.println("Trying to get downcall handle"); + PanamaJNIDef.nativeLinker0(Linker.nativeLinker(), FunctionDescriptor.ofVoid(), new Linker.Option[0]); + System.out.println("Got downcall handle"); + } +} diff --git a/test/jdk/java/foreign/enablenativeaccess/panama_module/org/openjdk/foreigntest/PanamaMainJNI.java b/test/jdk/java/foreign/enablenativeaccess/panama_module/org/openjdk/foreigntest/PanamaMainJNI.java deleted file mode 100644 index 164ee5852ccfa..0000000000000 --- a/test/jdk/java/foreign/enablenativeaccess/panama_module/org/openjdk/foreigntest/PanamaMainJNI.java +++ /dev/null @@ -1,23 +0,0 @@ -package org.openjdk.foreigntest; - -import java.lang.foreign.FunctionDescriptor; -import java.lang.foreign.Linker; - -public class PanamaMainJNI { - - static { - System.loadLibrary("LinkerInvokerModule"); - } - - public static void main(String[] args) { - testDirectAccessCLinker(); - } - - public static void testDirectAccessCLinker() { - System.out.println("Trying to get downcall handle"); - nativeLinker0(Linker.nativeLinker(), FunctionDescriptor.ofVoid(), new Linker.Option[0]); - System.out.println("Got downcall handle"); - } - - static native void nativeLinker0(Linker linker, FunctionDescriptor desc, Linker.Option[] options); -} diff --git a/test/jdk/java/foreign/handles/Driver.java b/test/jdk/java/foreign/handles/Driver.java index 1abfa6963fb9a..ca0545e2fd48a 100644 --- a/test/jdk/java/foreign/handles/Driver.java +++ b/test/jdk/java/foreign/handles/Driver.java @@ -24,6 +24,6 @@ /* * @test * @build invoker_module/* lookup_module/* - * @run testng/othervm --enable-native-access=invoker_module + * @run testng/othervm --illegal-native-access=deny --enable-native-access=invoker_module * lookup_module/handle.lookup.MethodHandleLookup */ diff --git a/test/jdk/java/foreign/handles/invoker_module/handle/invoker/MethodHandleInvoker.java b/test/jdk/java/foreign/handles/invoker_module/handle/invoker/MethodHandleInvoker.java index 9b696caa82d1e..fbb85cc54dfc5 100644 --- a/test/jdk/java/foreign/handles/invoker_module/handle/invoker/MethodHandleInvoker.java +++ b/test/jdk/java/foreign/handles/invoker_module/handle/invoker/MethodHandleInvoker.java @@ -90,6 +90,7 @@ static void addDefaultMapping(Class carrier, Object value) { addDefaultMapping(Consumer.class, (Consumer)(Object o) -> {}); addDefaultMapping(FunctionDescriptor.class, FunctionDescriptor.ofVoid()); addDefaultMapping(Linker.Option[].class, null); + addDefaultMapping(Runtime.class, Runtime.getRuntime()); addDefaultMapping(byte.class, (byte)0); addDefaultMapping(boolean.class, true); addDefaultMapping(char.class, (char)0); diff --git a/test/jdk/java/foreign/handles/lookup_module/handle/lookup/MethodHandleLookup.java b/test/jdk/java/foreign/handles/lookup_module/handle/lookup/MethodHandleLookup.java index ed916c1fe2419..42e6d7a7d8403 100644 --- a/test/jdk/java/foreign/handles/lookup_module/handle/lookup/MethodHandleLookup.java +++ b/test/jdk/java/foreign/handles/lookup_module/handle/lookup/MethodHandleLookup.java @@ -71,6 +71,18 @@ static Object[][] restrictedMethods() { { MethodHandles.lookup().findStatic(SymbolLookup.class, "libraryLookup", MethodType.methodType(SymbolLookup.class, Path.class, Arena.class)), "SymbolLookup::libraryLookup(Path)" }, + { MethodHandles.lookup().findStatic(System.class, "load", + MethodType.methodType(void.class, String.class)), + "System::load" }, + { MethodHandles.lookup().findStatic(System.class, "loadLibrary", + MethodType.methodType(void.class, String.class)), + "System::loadLibrary" }, + { MethodHandles.lookup().findVirtual(Runtime.class, "load", + MethodType.methodType(void.class, String.class)), + "Runtime::load" }, + { MethodHandles.lookup().findVirtual(Runtime.class, "loadLibrary", + MethodType.methodType(void.class, String.class)), + "Runtime::loadLibrary" } }; } catch (Throwable ex) { throw new ExceptionInInitializerError((ex)); diff --git a/test/jdk/java/net/URLClassLoader/JarLoaderCloseTest.java b/test/jdk/java/net/URLClassLoader/JarLoaderCloseTest.java new file mode 100644 index 0000000000000..469a682e0392a --- /dev/null +++ b/test/jdk/java/net/URLClassLoader/JarLoaderCloseTest.java @@ -0,0 +1,148 @@ +/* + * Copyright (c) 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.io.InputStream; +import java.net.URL; +import java.net.URLClassLoader; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.Arrays; +import java.util.jar.Attributes; +import java.util.jar.Manifest; + +import jdk.test.lib.util.JarUtils; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; +import static java.nio.charset.StandardCharsets.US_ASCII; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertNull; + +/* + * @test + * @bug 8338445 + * @summary verify that the jdk.internal.loader.URLClassPath closes the JarFile + * instances that it no longer uses for loading + * @library /test/lib + * @build jdk.test.lib.util.JarUtils + * @comment This test expects MalformedURLException for some specific URLs. + * We use othervm to prevent interference from other tests which + * might have installed custom URLStreamHandler(s) + * @run junit/othervm JarLoaderCloseTest + */ +public class JarLoaderCloseTest { + + private static final String RESOURCE_NAME = "foo-bar.txt"; + private static final String RESOURCE_CONTENT = "Hello world"; + private static final Path TEST_SCRATCH_DIR = Path.of("."); + + @BeforeAll + static void beforeAll() throws Exception { + // create a file which will be added to the JAR file that gets tested + Files.writeString(TEST_SCRATCH_DIR.resolve(RESOURCE_NAME), RESOURCE_CONTENT); + } + + /* + * Creates a JAR file with a manifest which has a Class-Path entry value with malformed URLs. + * Then uses a URLClassLoader backed by the JAR file in its classpath, loads some resource, + * closes the URLClassLoader and then expects that the underlying JAR file can be deleted + * from the filesystem. + */ + @ParameterizedTest + @ValueSource(strings = { + "C:\\foo\\bar\\hello/world.jar lib2.jar", + "C:/hello/world/foo.jar", + "lib4.jar C:\\bar\\foo\\world/hello.jar" + }) + public void testMalformedClassPathEntry(final String classPathValue) throws Exception { + final Manifest manifest = createManifestWithClassPath(classPathValue); + final Path jar = Files.createTempFile(TEST_SCRATCH_DIR, "8338445", ".jar"); + // create the JAR file with the given manifest and an arbitrary file + JarUtils.createJarFile(jar, manifest, TEST_SCRATCH_DIR, Path.of(RESOURCE_NAME)); + System.out.println("created jar at " + jar + " with manifest:"); + manifest.write(System.out); + final URL[] urlClassPath = new URL[]{jar.toUri().toURL()}; + // Create a URLClassLoader backed by the JAR file and load a non-existent resource just to + // exercise the URLClassPath code of loading the jar and parsing the Class-Path entry. + // Then close the classloader. After the classloader is closed + // issue a delete on the underlying JAR file on the filesystem. The delete is expected + // to succeed. + try (final URLClassLoader cl = new URLClassLoader(urlClassPath)) { + try (final InputStream is = cl.getResourceAsStream("non-existent.txt")) { + assertNull(is, "unexpectedly found a resource in classpath " + + Arrays.toString(urlClassPath)); + } + } + // now delete the JAR file and verify the delete worked + Files.delete(jar); + assertFalse(Files.exists(jar), jar + " exists even after being deleted"); + } + + /* + * Creates a JAR file with a manifest which has a Class-Path entry value with URLs + * that are parsable but point to files that don't exist on the filesystem. + * Then uses a URLClassLoader backed by the JAR file in its classpath, loads some resource, + * closes the URLClassLoader and then expects that the underlying JAR file can be deleted + * from the filesystem. + */ + @ParameterizedTest + @ValueSource(strings = { + "/home/me/hello/world.jar lib9.jar", + "lib10.jar" + }) + public void testParsableClassPathEntry(final String classPathValue) throws Exception { + final Manifest manifest = createManifestWithClassPath(classPathValue); + final Path jar = Files.createTempFile(TEST_SCRATCH_DIR, "8338445", ".jar"); + // create the JAR file with the given manifest and an arbitrary file + JarUtils.createJarFile(jar, manifest, TEST_SCRATCH_DIR, Path.of(RESOURCE_NAME)); + System.out.println("created jar at " + jar + " with manifest:"); + manifest.write(System.out); + final URL[] urlClassPath = new URL[]{jar.toUri().toURL()}; + // Create a URLClassLoader backed by the JAR file and load a resource + // and verify the resource contents. + // Then close the classloader. After the classloader is closed + // issue a delete on the underlying JAR file on the filesystem. The delete is expected + // to succeed. + try (final URLClassLoader cl = new URLClassLoader(urlClassPath)) { + try (final InputStream is = cl.getResourceAsStream(RESOURCE_NAME)) { + assertNotNull(is, RESOURCE_NAME + " not located by classloader in classpath " + + Arrays.toString(urlClassPath)); + final String content = new String(is.readAllBytes(), US_ASCII); + assertEquals(RESOURCE_CONTENT, content, "unexpected content in " + RESOURCE_NAME); + } + } + // now delete the JAR file and verify the delete worked + Files.delete(jar); + assertFalse(Files.exists(jar), jar + " exists even after being deleted"); + } + + private static Manifest createManifestWithClassPath(final String classPathValue) { + final Manifest manifest = new Manifest(); + final Attributes mainAttributes = manifest.getMainAttributes(); + mainAttributes.putValue("Manifest-Version", "1.0"); + mainAttributes.putValue("Class-Path", classPathValue); + return manifest; + } +} diff --git a/test/jdk/java/text/Format/CompactNumberFormat/TestCompactNumber.java b/test/jdk/java/text/Format/CompactNumberFormat/TestCompactNumber.java index 40da19adfe7b4..16de224777951 100644 --- a/test/jdk/java/text/Format/CompactNumberFormat/TestCompactNumber.java +++ b/test/jdk/java/text/Format/CompactNumberFormat/TestCompactNumber.java @@ -22,7 +22,7 @@ */ /* * @test - * @bug 8177552 8217721 8222756 8295372 8306116 8319990 + * @bug 8177552 8217721 8222756 8295372 8306116 8319990 8338690 * @summary Checks the functioning of compact number format * @modules jdk.localedata * @run testng/othervm TestCompactNumber @@ -60,6 +60,9 @@ public class TestCompactNumber { private static final NumberFormat FORMAT_IT_SHORT = NumberFormat .getCompactNumberInstance(Locale.ITALIAN, NumberFormat.Style.SHORT); + private static final NumberFormat FORMAT_IT_LONG = NumberFormat + .getCompactNumberInstance(Locale.ITALIAN, NumberFormat.Style.LONG); + private static final NumberFormat FORMAT_CA_LONG = NumberFormat .getCompactNumberInstance(Locale.of("ca"), NumberFormat.Style.LONG); @@ -89,6 +92,13 @@ public class TestCompactNumber { .getCompactNumberInstance(Locale.ITALIAN, NumberFormat.Style.LONG); private static final NumberFormat FORMAT_PT_LONG_FD4 = NumberFormat .getCompactNumberInstance(Locale.of("pt"), NumberFormat.Style.LONG); + + private static final NumberFormat FORMAT_PL_LONG = NumberFormat + .getCompactNumberInstance(Locale.of("pl"), NumberFormat.Style.LONG); + + private static final NumberFormat FORMAT_FR_LONG = NumberFormat + .getCompactNumberInstance(Locale.FRENCH, NumberFormat.Style.LONG); + static { FORMAT_ES_LONG_FD1.setMaximumFractionDigits(1); FORMAT_DE_LONG_FD2.setMaximumFractionDigits(2); @@ -359,6 +369,12 @@ Object[][] compactFormatData() { {FORMAT_DE_LONG_FD2, 1_234_500, "1,23 Millionen"}, {FORMAT_IT_LONG_FD3, 1_234_500, "1,234 milioni"}, {FORMAT_PT_LONG_FD4, 1_234_500, "1,2345 milh\u00f5es"}, + + // 8338690 + {FORMAT_PL_LONG, 5_000, "5 tysi\u0119cy"}, + {FORMAT_PL_LONG, 4_949, "5 tysi\u0119cy"}, + {FORMAT_FR_LONG, 1_949, "2 mille"}, + {FORMAT_IT_LONG, 1_949, "2 mila"}, }; } @@ -466,6 +482,10 @@ Object[][] compactParseData() { {FORMAT_DE_LONG_FD2, "1,23 Millionen", 1_230_000L, Long.class}, {FORMAT_IT_LONG_FD3, "1,234 milioni", 1_234_000L, Long.class}, {FORMAT_PT_LONG_FD4, "1,2345 milh\u00f5es", 1_234_500L, Long.class}, + // 8338690 + {FORMAT_PL_LONG, "5 tysi\u0119cy", 5_000L, Long.class}, + {FORMAT_FR_LONG, "2 mille", 2_000L, Long.class}, + {FORMAT_IT_LONG, "2 mila", 2_000L, Long.class}, }; } @@ -514,6 +534,10 @@ Object[][] invalidParseData() { {FORMAT_SL_LONG, "5 milijon", 5L}, {FORMAT_SL_LONG, "5 milijona", 5L}, {FORMAT_SL_LONG, "5 milijone", 5L}, + // 8338690 + {FORMAT_PL_LONG, "5 tysiÄ…ce", 5L}, + {FORMAT_FR_LONG, "2 millier", 2L}, + {FORMAT_IT_LONG, "2 mille", 2L}, }; } diff --git a/test/jdk/java/util/zip/TestZipError.java b/test/jdk/java/util/zip/TestZipError.java deleted file mode 100644 index 5448add92da78..0000000000000 --- a/test/jdk/java/util/zip/TestZipError.java +++ /dev/null @@ -1,116 +0,0 @@ -/* - * Copyright (c) 2006, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -/** - * @test - * @bug 4615343 - * @summary Check that ZipError is thrown instead of InternalError when - * iterating entries of an invalid zip file - */ - -import java.io.*; -import java.util.*; -import java.util.zip.*; - -public class TestZipError { - public static void realMain(String[] args) throws Throwable { - // Causing a ZipError is hard, especially on non-Windows systems. See - // comments below. - String osName = System.getProperty("os.name"); - if (!System.getProperty("os.name").startsWith("Windows")) { - return; - } - - String fileName = "error4615343.zip"; - File f = new File(fileName); - f.delete(); - ZipOutputStream zos; - ZipEntry ze; - - // Create a zip file with two entries. - zos = new ZipOutputStream(new FileOutputStream(f)); - ze = new ZipEntry("one"); - zos.putNextEntry(ze); - zos.write("hello".getBytes()); - zos.closeEntry(); - ze = new ZipEntry("two"); - zos.putNextEntry(ze); - zos.write("world".getBytes()); - zos.closeEntry(); - zos.close(); - - // Open the ZipFile. This will read the zip file's central - // directory into in-memory data structures. - ZipFile zf = new ZipFile(fileName); - - // Delete the file; of course this does not change the in-memory data - // structures that represent the central directory! - f.delete(); - - // Re-create zip file, with different entries than earlier. However, - // recall that we have in-memory information about the central - // directory of the file at its previous state. - zos = new ZipOutputStream(new FileOutputStream(f)); - ze = new ZipEntry("uno"); - zos.putNextEntry(ze); - zos.write("hola".getBytes()); - zos.closeEntry(); - zos.close(); - - // Iterate zip file's contents. On Windows, this will result in a - // ZipError, because the data in the file differs from the in-memory - // central directory information we read earlier. - Enumeration entries = zf.entries(); - try { - while (entries.hasMoreElements()) { - ze = entries.nextElement(); - zf.getInputStream(ze).readAllBytes(); - } - fail("Did not get expected exception"); - } catch (ZipException e) { - pass(); - } catch (InternalError e) { - fail("Caught InternalError instead of expected ZipError"); - } catch (Throwable t) { - unexpected(t); - } finally { - zf.close(); - f.delete(); - } - } - - //--------------------- Infrastructure --------------------------- - static volatile int passed = 0, failed = 0; - static void pass() {passed++;} - static void fail() {failed++; Thread.dumpStack();} - static void fail(String msg) {System.out.println(msg); fail();} - static void unexpected(Throwable t) {failed++; t.printStackTrace();} - static void check(boolean cond) {if (cond) pass(); else fail();} - static void equal(Object x, Object y) { - if (x == null ? y == null : x.equals(y)) pass(); - else fail(x + " not equal to " + y);} - public static void main(String[] args) throws Throwable { - try {realMain(args);} catch (Throwable t) {unexpected(t);} - System.out.println("\nPassed = " + passed + " failed = " + failed); - if (failed > 0) throw new AssertionError("Some tests failed");} -} diff --git a/test/jdk/javax/net/ssl/SSLSession/CertMsgCheck.java b/test/jdk/javax/net/ssl/SSLSession/CertMsgCheck.java index 498c17672b213..2131b314ce0aa 100644 --- a/test/jdk/javax/net/ssl/SSLSession/CertMsgCheck.java +++ b/test/jdk/javax/net/ssl/SSLSession/CertMsgCheck.java @@ -39,10 +39,12 @@ public static void main(String[] args) throws Exception { build(); // Initial client session - TLSBase.Client client1 = new TLSBase.Client(true, false); + TLSBase.Client client = new TLSBase.Client(true, false); + client.connect(); - server.getSession(client1).getSessionContext(); - server.done(); + // Close must be called to gather all the exceptions thrown + client.close(); + server.close(); var eList = server.getExceptionList(); System.out.println("Exception list size is " + eList.size()); diff --git a/test/jdk/javax/net/ssl/SSLSession/CheckSessionContext.java b/test/jdk/javax/net/ssl/SSLSession/CheckSessionContext.java index 183354ed9db22..a08414b03fd46 100644 --- a/test/jdk/javax/net/ssl/SSLSession/CheckSessionContext.java +++ b/test/jdk/javax/net/ssl/SSLSession/CheckSessionContext.java @@ -47,6 +47,7 @@ public static void main(String[] args) throws Exception { // Initial client session TLSBase.Client client1 = new TLSBase.Client(); + client1.connect(); if (server.getSession(client1).getSessionContext() == null) { throw new Exception("Context was null. Handshake failure."); } else { @@ -66,6 +67,7 @@ public static void main(String[] args) throws Exception { // Resume the client session TLSBase.Client client2 = new TLSBase.Client(); + client2.connect(); if (server.getSession(client2).getSessionContext() == null) { throw new Exception("Context was null on resumption"); } else { @@ -73,6 +75,5 @@ public static void main(String[] args) throws Exception { } server.close(client2); client2.close(); - server.done(); } } diff --git a/test/jdk/javax/net/ssl/TLSCommon/interop/AbstractServer.java b/test/jdk/javax/net/ssl/TLSCommon/interop/AbstractServer.java index a5f61ce869a0d..03b3aadb0074f 100644 --- a/test/jdk/javax/net/ssl/TLSCommon/interop/AbstractServer.java +++ b/test/jdk/javax/net/ssl/TLSCommon/interop/AbstractServer.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 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 @@ -22,6 +22,8 @@ */ import java.io.IOException; +import java.net.InetAddress; +import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; @@ -52,11 +54,21 @@ public void signalStop() throws Exception { } public static abstract class Builder extends AbstractPeer.Builder { + private InetAddress listenInterface = InetAddress.getLoopbackAddress(); private int port; // Indicates if requires client authentication. private boolean clientAuth = true; + public InetAddress getListenInterface() { + return listenInterface; + } + + public Builder setListenInterface(InetAddress listenInterface) { + this.listenInterface = listenInterface; + return this; + } + public int getPort() { return port; } diff --git a/test/jdk/javax/net/ssl/TLSCommon/interop/JdkServer.java b/test/jdk/javax/net/ssl/TLSCommon/interop/JdkServer.java index 6519e89febb9e..1521325b65ac8 100644 --- a/test/jdk/javax/net/ssl/TLSCommon/interop/JdkServer.java +++ b/test/jdk/javax/net/ssl/TLSCommon/interop/JdkServer.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 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 @@ -22,6 +22,7 @@ */ import java.io.IOException; +import java.net.InetAddress; import java.net.SocketException; import java.util.ArrayList; import java.util.List; @@ -53,7 +54,8 @@ public JdkServer(Builder builder) throws Exception { context = Utilities.createSSLContext(builder.getCertTuple()); SSLServerSocketFactory serverFactory = context.getServerSocketFactory(); serverSocket - = (SSLServerSocket) serverFactory.createServerSocket(builder.getPort()); + = (SSLServerSocket) serverFactory.createServerSocket(builder.getPort(), + 0, builder.getListenInterface()); configServerSocket(builder); } diff --git a/test/jdk/javax/net/ssl/templates/TLSBase.java b/test/jdk/javax/net/ssl/templates/TLSBase.java index 5c95253e6f024..8ec4e4e3db46f 100644 --- a/test/jdk/javax/net/ssl/templates/TLSBase.java +++ b/test/jdk/javax/net/ssl/templates/TLSBase.java @@ -25,13 +25,16 @@ import java.io.*; import java.net.InetAddress; import java.net.InetSocketAddress; +import java.nio.charset.StandardCharsets; import java.security.KeyStore; import java.security.cert.PKIXBuilderParameters; import java.security.cert.X509CertSelector; import java.util.ArrayList; -import java.util.Arrays; import java.util.List; import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.TimeUnit; /** * This is a base setup for creating a server and clients. All clients will @@ -39,7 +42,7 @@ * first. The idea is for the test code to be minimal as possible without * this library class being complicated. * - * Server.done() must be called or the server will never exit and hang the test. + * Server.close() must be called so the server will exit and end threading. * * After construction, reading and writing are allowed from either side, * or a combination write/read from both sides for verifying text. @@ -52,24 +55,25 @@ */ abstract public class TLSBase { - static String pathToStores = "../etc"; + static String pathToStores = "javax/net/ssl/etc"; static String keyStoreFile = "keystore"; static String trustStoreFile = "truststore"; static String passwd = "passphrase"; + static final String TESTROOT = + System.getProperty("test.root", "../../../.."); + SSLContext sslContext; // Server's port static int serverPort; // Name shown during read and write ops - String name; + public String name; TLSBase() { - String keyFilename = - System.getProperty("test.src", "./") + "/" + pathToStores + - "/" + keyStoreFile; - String trustFilename = - System.getProperty("test.src", "./") + "/" + pathToStores + - "/" + trustStoreFile; + + String keyFilename = TESTROOT + "/" + pathToStores + "/" + keyStoreFile; + String trustFilename = TESTROOT + "/" + pathToStores + "/" + + trustStoreFile; System.setProperty("javax.net.ssl.keyStore", keyFilename); System.setProperty("javax.net.ssl.keyStorePassword", passwd); System.setProperty("javax.net.ssl.trustStore", trustFilename); @@ -78,26 +82,22 @@ abstract public class TLSBase { // Base read operation byte[] read(SSLSocket sock) throws Exception { - BufferedReader reader = new BufferedReader( - new InputStreamReader(sock.getInputStream())); - String s = reader.readLine(); - System.err.println("(read) " + name + ": " + s); - return s.getBytes(); + BufferedInputStream is = new BufferedInputStream(sock.getInputStream()); + byte[] b = is.readNBytes(5); + System.err.println("(read) " + Thread.currentThread().getName() + ": " + new String(b)); + return b; } // Base write operation public void write(SSLSocket sock, byte[] data) throws Exception { - PrintWriter out = new PrintWriter( - new OutputStreamWriter(sock.getOutputStream())); - out.println(new String(data)); - out.flush(); - System.err.println("(write)" + name + ": " + new String(data)); + sock.getOutputStream().write(data); + System.err.println("(write)" + Thread.currentThread().getName() + ": " + new String(data)); } private static KeyManager[] getKeyManager(boolean empty) throws Exception { FileInputStream fis = null; if (!empty) { - fis = new FileInputStream(System.getProperty("test.src", "./") + + fis = new FileInputStream(System.getProperty("test.root", "./") + "/" + pathToStores + "/" + keyStoreFile); } // Load the keystore @@ -113,7 +113,7 @@ private static KeyManager[] getKeyManager(boolean empty) throws Exception { private static TrustManager[] getTrustManager(boolean empty) throws Exception { FileInputStream fis = null; if (!empty) { - fis = new FileInputStream(System.getProperty("test.src", "./") + + fis = new FileInputStream(System.getProperty("test.root", "./") + "/" + pathToStores + "/" + trustStoreFile); } // Load the keystore @@ -150,6 +150,11 @@ static class Server extends TLSBase { new ConcurrentHashMap<>(); Thread t; List exceptionList = new ArrayList<>(); + ExecutorService threadPool = Executors.newFixedThreadPool(1, + r -> { + Thread t = Executors.defaultThreadFactory().newThread(r); + return t; + }); Server(ServerBuilder builder) { super(); @@ -160,8 +165,10 @@ static class Server extends TLSBase { TLSBase.getTrustManager(builder.tm), null); fac = sslContext.getServerSocketFactory(); ssock = (SSLServerSocket) fac.createServerSocket(0); + ssock.setReuseAddress(true); ssock.setNeedClientAuth(builder.clientauth); serverPort = ssock.getLocalPort(); + System.out.println("Server Port: " + serverPort); } catch (Exception e) { System.err.println("Failure during server initialization"); e.printStackTrace(); @@ -171,117 +178,67 @@ static class Server extends TLSBase { t = new Thread(() -> { try { while (true) { - System.err.println("Server ready on port " + - serverPort); - SSLSocket c = (SSLSocket)ssock.accept(); - clientMap.put(c.getPort(), c); - try { - write(c, read(c)); - } catch (Exception e) { - System.out.println("Caught " + e.getMessage()); - e.printStackTrace(); - exceptionList.add(e); - } + SSLSocket sock = (SSLSocket)ssock.accept(); + threadPool.submit(new ServerThread(sock)); } } catch (Exception ex) { System.err.println("Server Down"); ex.printStackTrace(); + } finally { + threadPool.close(); } }); t.start(); } - Server() { - this(new ServerBuilder()); - } + class ServerThread extends Thread { + SSLSocket sock; - /** - * @param km - true for an empty key manager - * @param tm - true for an empty trust manager - */ - Server(boolean km, boolean tm) { - super(); - name = "server"; - try { - sslContext = SSLContext.getInstance("TLS"); - sslContext.init(TLSBase.getKeyManager(km), - TLSBase.getTrustManager(tm), null); - fac = sslContext.getServerSocketFactory(); - ssock = (SSLServerSocket) fac.createServerSocket(0); - ssock.setNeedClientAuth(true); - serverPort = ssock.getLocalPort(); - } catch (Exception e) { - System.err.println("Failure during server initialization"); - e.printStackTrace(); - } - - // Thread to allow multiple clients to connect - t = new Thread(() -> { - try { - while (true) { - System.err.println("Server ready on port " + - serverPort); - SSLSocket c = (SSLSocket)ssock.accept(); - clientMap.put(c.getPort(), c); - try { - write(c, read(c)); - } catch (Exception e) { - System.out.println("Caught " + e.getMessage()); - e.printStackTrace(); - exceptionList.add(e); - } - } - } catch (Exception ex) { - System.err.println("Server Down"); - ex.printStackTrace(); - } - }); - t.start(); + ServerThread(SSLSocket s) { + this.sock = s; + System.err.println("ServerThread("+sock.getPort()+")"); + clientMap.put(sock.getPort(), sock); } - // Exit test to quit the test. This must be called at the end of the - // test or the test will never end. - void done() { - try { - t.join(5000); - ssock.close(); - } catch (Exception e) { - System.err.println(e.getMessage()); - e.printStackTrace(); - } - } - - // Read from the client - byte[] read(Client client) throws Exception { - SSLSocket s = clientMap.get(Integer.valueOf(client.getPort())); - if (s == null) { - System.err.println("No socket found, port " + client.getPort()); + public void run() { + try { + write(sock, read(sock)); + } catch (Exception e) { + System.out.println("Caught " + e.getMessage()); + e.printStackTrace(); + exceptionList.add(e); + } } - return read(s); } - // Write to the client - void write(Client client, byte[] data) throws Exception { - write(clientMap.get(client.getPort()), data); + Server() { + this(new ServerBuilder()); } - // Server writes to the client, then reads from the client. - // Return true if the read & write data match, false if not. - boolean writeRead(Client client, String s) throws Exception{ - write(client, s.getBytes()); - return (Arrays.compare(s.getBytes(), client.read()) == 0); + public SSLSession getSession(Client client) throws Exception { + System.err.println("getSession("+client.getPort()+")"); + SSLSocket clientSocket = clientMap.get(client.getPort()); + if (clientSocket == null) { + throw new Exception("Server can't find client socket"); + } + return clientSocket.getSession(); } - // Get the SSLSession from the server side socket - SSLSession getSession(Client c) { - SSLSocket s = clientMap.get(Integer.valueOf(c.getPort())); - return s.getSession(); + void close(Client client) { + try { + System.err.println("close("+client.getPort()+")"); + clientMap.remove(client.getPort()).close(); + } catch (Exception e) { + ; + } } - - // Close client socket - void close(Client c) throws IOException { - SSLSocket s = clientMap.get(Integer.valueOf(c.getPort())); - s.close(); + void close() throws InterruptedException { + clientMap.values().stream().forEach(s -> { + try { + s.close(); + } catch (IOException e) {} + }); + threadPool.awaitTermination(500, TimeUnit.MILLISECONDS); } List getExceptionList() { @@ -312,11 +269,11 @@ Server build() { } } /** - * Client side will establish a connection from the constructor and wait. + * Client side will establish a SSLContext instance. * It must be run after the Server constructor is called. */ static class Client extends TLSBase { - SSLSocket sock; + public SSLSocket socket; boolean km, tm; Client() { this(false, false); @@ -330,55 +287,66 @@ static class Client extends TLSBase { super(); this.km = km; this.tm = tm; - connect(); - } - - // Connect to server. Maybe runnable in the future - public SSLSocket connect() { try { sslContext = SSLContext.getInstance("TLS"); sslContext.init(TLSBase.getKeyManager(km), TLSBase.getTrustManager(tm), null); - sock = (SSLSocket)sslContext.getSocketFactory().createSocket(); - sock.connect(new InetSocketAddress(InetAddress.getLoopbackAddress(), serverPort)); - System.err.println("Client connected using port " + - sock.getLocalPort()); - name = "client(" + sock.toString() + ")"; - write("Hello"); - read(); + socket = createSocket(); } catch (Exception ex) { ex.printStackTrace(); } - return sock; } - // Read from the client socket - byte[] read() throws Exception { - return read(sock); + Client(Client cl) { + sslContext = cl.sslContext; + socket = createSocket(); } - // Write to the client socket - void write(byte[] data) throws Exception { - write(sock, data); + public SSLSocket createSocket() { + try { + return (SSLSocket) sslContext.getSocketFactory().createSocket(); + } catch (Exception ex) { + ex.printStackTrace(); + } + return null; } - void write(String s) throws Exception { - write(sock, s.getBytes()); + + public SSLSocket connect() { + try { + socket.connect(new InetSocketAddress(InetAddress.getLoopbackAddress(), serverPort)); + System.err.println("Client (" + Thread.currentThread().getName() + ") connected using port " + + socket.getLocalPort() + " to " + socket.getPort()); + writeRead(); + } catch (Exception ex) { + ex.printStackTrace(); + return null; + } + return socket; } - // Client writes to the server, then reads from the server. - // Return true if the read & write data match, false if not. - boolean writeRead(Server server, String s) throws Exception { - write(s.getBytes()); - return (Arrays.compare(s.getBytes(), server.read(this)) == 0); + public SSLSession getSession() { + return socket.getSession(); + } + public void close() { + try { + socket.close(); + } catch (Exception ex) { + ex.printStackTrace(); + } } - // Get port from the socket - int getPort() { - return sock.getLocalPort(); + public int getPort() { + return socket.getLocalPort(); } - // Close socket - void close() throws IOException { - sock.close(); + private SSLSocket writeRead() { + try { + write(socket, "Hello".getBytes(StandardCharsets.ISO_8859_1)); + read(socket); + } catch (Exception ex) { + ex.printStackTrace(); + } + return socket; } + } } diff --git a/test/jdk/javax/swing/JButton/SwingButtonResizeTestWithOpenGL.java b/test/jdk/javax/swing/JButton/SwingButtonResizeTestWithOpenGL.java new file mode 100644 index 0000000000000..96ef9edc57100 --- /dev/null +++ b/test/jdk/javax/swing/JButton/SwingButtonResizeTestWithOpenGL.java @@ -0,0 +1,352 @@ +/* + * Copyright (c) 2015, 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.awt.Color; +import java.awt.Dimension; +import java.awt.FlowLayout; +import java.awt.Point; +import java.awt.Rectangle; +import java.awt.Robot; +import java.awt.event.FocusAdapter; +import java.awt.event.FocusEvent; +import java.awt.image.BufferedImage; +import java.awt.image.ColorModel; +import java.awt.image.Raster; +import java.io.File; +import java.io.IOException; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicReference; +import javax.imageio.ImageIO; +import javax.swing.JButton; +import javax.swing.JFrame; +import javax.swing.SwingUtilities; + +/* + * @test + * @bug 8338103 + * @key headful + * @summary Verifies that the OpenGL pipeline does not create artifacts + * with swing components after window is zoomed to maximum size and then + * resized back to normal. The test case simulates this operation using + * a JButton. A file image of the component will be saved before and after + * the window resize if the test fails. The test passes if both the button + * images are the same. + * @run main/othervm -Dsun.java2d.opengl=true -Dsun.java2d.opengl.fbobject=false SwingButtonResizeTestWithOpenGL + * @run main/othervm -Dsun.java2d.opengl=true -Dsun.java2d.opengl.fbobject=true SwingButtonResizeTestWithOpenGL + * @run main/othervm -Dsun.java2d.opengl=false SwingButtonResizeTestWithOpenGL + * @run main/othervm SwingButtonResizeTestWithOpenGL + */ +/* + * @test + * @key headful + * @requires (os.family == "windows") + * @run main/othervm -Dsun.java2d.d3d=false SwingButtonResizeTestWithOpenGL + * @run main/othervm -Dsun.java2d.d3d=true SwingButtonResizeTestWithOpenGL + */ +/* + * @test + * @key headful + * @requires (os.family == "linux") + * @run main/othervm -Dsun.java2d.xrender=false SwingButtonResizeTestWithOpenGL + * @run main/othervm -Dsun.java2d.xrender=true SwingButtonResizeTestWithOpenGL + */ +/* + * @test + * @key headful + * @requires (os.family == "mac") + * @run main/othervm -Dsun.java2d.metal=false SwingButtonResizeTestWithOpenGL + * @run main/othervm -Dsun.java2d.metal=true SwingButtonResizeTestWithOpenGL + */ +public class SwingButtonResizeTestWithOpenGL { + private static Robot robot; + private static CountDownLatch focusGainedLatch; + private JFrame frame; + private JButton button; + + public SwingButtonResizeTestWithOpenGL() { + + try { + SwingUtilities.invokeAndWait(() -> createGUI()); + } catch (Exception e) { + throw new RuntimeException("Problems creating GUI"); + } + } + + private void createGUI() { + frame = new JFrame("SwingButtonResizeTestWithOpenGL"); + button = new JButton("Button A"); + frame.setLocation(200, 200); + frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE); + button.setPreferredSize(new Dimension(300, 300)); + button.addFocusListener(new FocusAdapter() { + public void focusGained(FocusEvent fe) { + focusGainedLatch.countDown(); + } + }); + frame.getContentPane().setLayout(new FlowLayout()); + frame.getContentPane().add(button); + frame.pack(); + frame.setVisible(true); + frame.toFront(); + } + + public static void main(String[] args) throws Exception { + focusGainedLatch = new CountDownLatch(1); + SwingButtonResizeTestWithOpenGL test = + new SwingButtonResizeTestWithOpenGL(); + test.runTest(); + } + + public void runTest() throws Exception { + BufferedImage bimage1; + BufferedImage bimage2; + + try { + robot = new Robot(); + robot.setAutoWaitForIdle(true); + robot.setAutoDelay(200); + + if (focusGainedLatch.await(3, TimeUnit.SECONDS)) { + System.out.println("Button focus gained..."); + } else { + System.out.println("Button focus not gained..."); + throw new RuntimeException( + "Can't gain focus on button even after waiting " + + "too long.."); + } + + System.out.println("Getting initial button image..image1"); + bimage1 = getButtonImage(); + + // some platforms may not support maximize frame + if (frame.getToolkit().isFrameStateSupported( + JFrame.MAXIMIZED_BOTH)) { + robot.waitForIdle(); + // maximize frame from normal size + frame.setExtendedState(JFrame.MAXIMIZED_BOTH); + System.out.println("Frame is maximized"); + robot.waitForIdle(); + + if (frame.getToolkit().isFrameStateSupported(JFrame.NORMAL)) { + System.out.println("Frame is back to normal"); + // resize from maximum size to normal + frame.setExtendedState(JFrame.NORMAL); + + // capture image of JButton after resize + System.out.println( + "Getting image of JButton after resize..image2"); + bimage2 = getButtonImage(); + + // compare button images from before and after frame resize + DiffImage di = new DiffImage(bimage1.getWidth(), + bimage1.getHeight()); + System.out.println( + "Taking the diff of two images, image1 and image2"); + if (!di.compare(bimage1, bimage2)) { + throw new RuntimeException( + "Button renderings are different after window " + + "resize, num of Diff Pixels=" + + di.getNumDiffPixels()); + } else { + System.out.println("Test passed..."); + } + + } else { + System.out.println( + "Test skipped: JFrame.NORMAL resize is " + + "not supported"); + } + + } else { + System.out.println( + "Test skipped: JFrame.MAXIMIZED_BOTH resize is " + + "not supported"); + } + } finally { + SwingUtilities.invokeAndWait(() -> disposeFrame()); + } + } + + // Capture button rendering as a BufferedImage + private BufferedImage getButtonImage() { + try { + robot.waitForIdle(); + robot.delay(500); + + AtomicReference buttonLocRef = new AtomicReference<>(); + SwingUtilities.invokeAndWait( + () -> buttonLocRef.set(button.getLocationOnScreen())); + Point buttonLoc = buttonLocRef.get(); + System.out.println("Button loc: " + buttonLoc); + return robot.createScreenCapture( + new Rectangle(buttonLoc.x, buttonLoc.y, button.getWidth(), + button.getHeight())); + } catch (Exception e) { + throw new RuntimeException( + "Problems capturing button image from Robot", e); + } + } + + private void disposeFrame() { + if (frame != null) { + frame.dispose(); + frame = null; + } + } + + // Save BufferedImage to PNG file + private void saveButtonImage(BufferedImage image, File file) { + if (image != null) { + try { + System.out.println( + "Saving button image to " + file.getAbsolutePath()); + ImageIO.write(image, "PNG", file); + } catch (Exception e) { + throw new RuntimeException("Could not write image file"); + } + } else { + throw new RuntimeException("BufferedImage was set to null"); + } + } + + private class DiffImage extends BufferedImage { + + public boolean diff = false; + public int nDiff = -1; + + Color bgColor; + + int threshold = 0; + + public DiffImage(int w, int h) { + super(w, h, BufferedImage.TYPE_INT_ARGB); + bgColor = Color.LIGHT_GRAY; + } + + public int getNumDiffPixels() { + return nDiff; + } + + public boolean compare(BufferedImage img1, BufferedImage img2) + throws IOException { + + int minx1 = img1.getMinX(); + int minx2 = img2.getMinX(); + int miny1 = img1.getMinY(); + int miny2 = img2.getMinY(); + + int w1 = img1.getWidth(); + int w2 = img2.getWidth(); + int h1 = img1.getHeight(); + int h2 = img2.getHeight(); + + if ((minx1 != minx2) || (miny1 != miny2) || (w1 != w2) + || (h1 != h2)) { + // image sizes are different + throw new RuntimeException( + "img1: <" + minx1 + "," + miny1 + "," + w1 + "x" + h1 + + ">" + " img2: " + minx2 + "," + miny2 + "," + w2 + "x" + + h2 + ">" + " are different sizes"); + } + // Get the actual data behind the images + Raster ras1 = img1.getData(); + Raster ras2 = img2.getData(); + + ColorModel cm1 = img1.getColorModel(); + ColorModel cm2 = img2.getColorModel(); + + int r1, r2; // red + int g1, g2; // green + int b1, b2; // blue + + Object o1 = null; + Object o2 = null; + nDiff = 0; + for (int x = minx1; x < (minx1 + w1); x++) { + for (int y = miny1; y < (miny1 + h1); y++) { + // Causes rasters to allocate data + o1 = ras1.getDataElements(x, y, o1); + // and we reuse the data on every loop + o2 = ras2.getDataElements(x, y, o2); + + r1 = cm1.getRed(o1); + r2 = cm2.getRed(o2); + g1 = cm1.getGreen(o1); + g2 = cm2.getGreen(o2); + b1 = cm1.getBlue(o1); + b2 = cm2.getBlue(o2); + + int redAbs = Math.abs(r1 - r2); + int greenAbs = Math.abs(g1 - g2); + int blueAbs = Math.abs(b1 - b2); + if ((redAbs > threshold) + || (greenAbs > threshold) + || (blueAbs > threshold)) { + // pixel is different + setDiffPixel(x, y, redAbs, greenAbs, blueAbs); + nDiff++; + } else { + setSamePixel(x, y); + } + + } + } + if (nDiff != 0) { + ImageIO.write(this, "png", + new File("diffImage.png")); + saveButtonImage(img1, new File("image1.png")); + saveButtonImage(img2, new File("image2.png")); + } + return nDiff == 0; + } + + void setDiffPixel(int x, int y, int r, int g, int b) { + diff = true; + setPixelValue(x, y, 255, r, g, b); + } + + void setSamePixel(int x, int y) { + if (bgColor != null) { + setPixelValue(x, y, 255, bgColor.getRed(), + bgColor.getGreen(), + bgColor.getBlue()); + } else { + setPixelValue(x, y, 255, Color.black.getRed(), + Color.black.getGreen(), Color.black.getBlue()); + } + } + + void setPixelValue(int x, int y, int a, int r, int g, int b) { + // setRGB uses BufferedImage.TYPE_INT_ARGB format + int pixel = + ((a & 0xff) << 24) + ((r & 0xff) << 16) + ((g & 0xff) << 8) + + ((b & 0xff)); + setRGB(x, y, pixel); + } + + } + +} + + diff --git a/test/jdk/javax/swing/JFileChooser/8080628/bug8080628.java b/test/jdk/javax/swing/JFileChooser/8080628/bug8080628.java index 21490282550e6..426ed7456484a 100644 --- a/test/jdk/javax/swing/JFileChooser/8080628/bug8080628.java +++ b/test/jdk/javax/swing/JFileChooser/8080628/bug8080628.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 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 @@ -33,7 +33,17 @@ * @test * @bug 8080628 * @summary No mnemonics on Open and Save buttons in JFileChooser. - * @author Alexey Ivanov + * @requires os.family != "linux" + * @modules java.desktop/sun.swing + * @run main bug8080628 + */ + +/* + * @test + * @bug 8080628 + * @key headful + * @summary No mnemonics on Open and Save buttons in JFileChooser. + * @requires os.family == "linux" * @modules java.desktop/sun.swing * @run main bug8080628 */ @@ -81,8 +91,10 @@ private static void runTest() { try { UIManager.setLookAndFeel(info.getClassName()); } catch (final UnsupportedLookAndFeelException ignored) { + System.out.println("Unsupported L&F: " + info.getClassName()); continue; } + System.out.println("Testing L&F: " + info.getClassName()); for (Locale locale : LOCALES) { for (String key : MNEMONIC_KEYS) { diff --git a/test/jdk/javax/swing/JTable/KeyBoardNavigation.java b/test/jdk/javax/swing/JTable/KeyBoardNavigation.java index 595547421ad16..728361a3e9022 100644 --- a/test/jdk/javax/swing/JTable/KeyBoardNavigation.java +++ b/test/jdk/javax/swing/JTable/KeyBoardNavigation.java @@ -39,7 +39,7 @@ /* * @test * @key headful - * @bug 4112270 8264102 + * @bug 4112270 8264102 8329756 * @library /java/awt/regtesthelpers * @build PassFailJFrame * @summary Test Keyboard Navigation in JTable. @@ -178,7 +178,7 @@ public static void main(String[] args) throws Exception { 1. Refer the below keyboard navigation specs (referenced from bug report 4112270). 2. Check all combinations of navigational keys mentioned below - and verifying each key combinations against the spec defined. + and verify each key combination against the spec defined. If it does, press "pass", otherwise press "fail". """; @@ -270,24 +270,19 @@ public static String getOSSpecificInstructions() { up/down Left/Right Arrow - Deselect current selection; move focus one cell left/right - FN+Up Arrow/FN+Down Arrow - Deselect current selection; + fn+Up/Down Arrow - Deselect current selection; scroll up/down one JViewport view; first visible cell in current column gets focus - Control-FN+Up Arrow/FN+Down Arrow - Deselect current selection; - move focus and view to - first/last cell in current row - F2 - Allows editing in a cell containing information without + fn - Allows editing in a cell containing information without overwriting the information Esc - Resets the cell content back to the state it was in before editing started - Ctrl+A, Ctrl+/ - Select All - Ctrl+\\ - Deselect all + Cmd+A - Select All Shift-Up/Down Arrow - Extend selection up/down one row Shift-Left/Right Arrow - Extend selection left/right one column - FN-Shift Up/Down Arrow - Extend selection to top/bottom of column - Shift-PageUp/PageDown - Extend selection up/down one view and scroll - table - """; + Ctrl-Shift Up/Down Arrow - Extend selection to top/bottom of row + Ctrl-Shift Left/Right Arrow - Extend selection to first/last of column + """; String osName = System.getProperty("os.name").toLowerCase(); if (osName.startsWith("mac")) { return MAC_SPECIFIC; diff --git a/test/jdk/javax/swing/plaf/gtk/JTableCtrlShiftRightLeftKeyTest.java b/test/jdk/javax/swing/plaf/gtk/JTableCtrlShiftRightLeftKeyTest.java new file mode 100644 index 0000000000000..1df2ed4861632 --- /dev/null +++ b/test/jdk/javax/swing/plaf/gtk/JTableCtrlShiftRightLeftKeyTest.java @@ -0,0 +1,139 @@ +/* + * Copyright (c) 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.awt.Point; +import java.awt.Rectangle; +import java.awt.Robot; +import java.awt.event.InputEvent; +import java.awt.event.KeyEvent; + +import javax.swing.JFrame; +import javax.swing.JTable; +import javax.swing.SwingUtilities; +import javax.swing.UIManager; + +/* + * @test + * @bug 8338041 + * @key headful + * @summary Verify that Ctrl Shift RIGHT/LEFT key extends columns till + * Last/First Columns in JTable + * @requires (os.family == "linux") + * @run main JTableCtrlShiftRightLeftKeyTest + */ + +public class JTableCtrlShiftRightLeftKeyTest { + private static JFrame frame; + private static JTable table; + private static volatile Point tableLoc; + private static volatile Rectangle cellRect; + private static volatile int[] selectedColumnAfterKeyPress; + private static Robot robot; + private static final int SELECTED_COLUMN = 2; + + public static void main(String[] args) throws Exception { + UIManager.setLookAndFeel("com.sun.java.swing.plaf.gtk.GTKLookAndFeel"); + robot = new Robot(); + robot.setAutoDelay(50); + try { + SwingUtilities.invokeAndWait(JTableCtrlShiftRightLeftKeyTest::createAndShowUI); + robot.waitForIdle(); + robot.delay(1000); + + SwingUtilities.invokeAndWait(() -> { + tableLoc = table.getLocationOnScreen(); + cellRect = table.getCellRect(0, SELECTED_COLUMN, true); + }); + + robot.mouseMove(tableLoc.x + cellRect.x + cellRect.width / 2, + tableLoc.y + cellRect.y + cellRect.height / 2); + robot.mousePress(InputEvent.BUTTON1_DOWN_MASK); + robot.mouseRelease(InputEvent.BUTTON1_DOWN_MASK); + robot.waitForIdle(); + robot.delay(100); + + testCtrlShift(KeyEvent.VK_RIGHT, SELECTED_COLUMN, + table.getColumnCount() - 1, "RIGHT"); + + robot.waitForIdle(); + robot.delay(100); + robot.mousePress(InputEvent.BUTTON1_DOWN_MASK); + robot.mouseRelease(InputEvent.BUTTON1_DOWN_MASK); + robot.waitForIdle(); + robot.delay(100); + + testCtrlShift(KeyEvent.VK_LEFT, 0, + SELECTED_COLUMN, "LEFT"); + robot.waitForIdle(); + robot.delay(100); + System.out.println("Test Passed!"); + + } finally { + SwingUtilities.invokeAndWait(() -> { + if (frame != null) { + frame.dispose(); + } + }); + } + } + + private static void testCtrlShift(int keySelected, int startCellCheck, + int endCellCheck, String key) throws Exception { + robot.keyPress(KeyEvent.VK_SHIFT); + robot.keyPress(KeyEvent.VK_CONTROL); + robot.keyPress(keySelected); + robot.keyRelease(keySelected); + robot.keyRelease(KeyEvent.VK_SHIFT); + robot.keyRelease(KeyEvent.VK_CONTROL); + robot.waitForIdle(); + robot.delay(100); + + SwingUtilities.invokeAndWait(() -> { + selectedColumnAfterKeyPress = table.getSelectedColumns(); + }); + + if (selectedColumnAfterKeyPress[0] != startCellCheck || + selectedColumnAfterKeyPress[selectedColumnAfterKeyPress.length - 1] != + endCellCheck) { + System.out.println("Selected Columns: "); + for (int columnsSelected : selectedColumnAfterKeyPress) { + System.out.println(columnsSelected); + } + String failureMsg = "Test Failure. Failed to select cells for Ctrl" + + " Shift " + key + " selection"; + throw new RuntimeException(failureMsg); + } + } + + private static void createAndShowUI() { + frame = new JFrame("Test Ctrl Shift RIGHT/LEFT Key Press"); + table = new JTable(2, 5); + table.setColumnSelectionAllowed(true); + frame.getContentPane().add(table); + + frame.setSize(200, 200); + frame.setLocationRelativeTo(null); + frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); + frame.setVisible(true); + } +} diff --git a/test/jdk/jdk/jfr/api/settings/TestFilterEvents.java b/test/jdk/jdk/jfr/api/settings/TestFilterEvents.java index 42bfc31767e98..67619fb10b4e9 100644 --- a/test/jdk/jdk/jfr/api/settings/TestFilterEvents.java +++ b/test/jdk/jdk/jfr/api/settings/TestFilterEvents.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 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 @@ -70,6 +70,7 @@ public static void main(String[] args) throws Exception { continuous.enable(HTTPGetEvent.class).with("threadNames", "\"unused-threadname-1\""); assertEquals(0, makeProfilingRecording("\"unused-threadname-2\"")); assertEquals(1, makeProfilingRecording("\"" + Thread.currentThread().getName() + "\"")); + assertEquals(2, makeCombineControl()); continuous.close(); } @@ -94,4 +95,32 @@ private static int makeProfilingRecording(String threadNames) throws Exception { } } + private static int makeCombineControl() throws Exception { + try (Recording r1 = new Recording()) { + r1.enable(HTTPPostEvent.class).with("uriFilter", "https://www.example.com/list"); + r1.start(); + + try (Recording r2 = new Recording()) { + r2.enable(HTTPPostEvent.class).with("uriFilter", "https://www.example.com/get"); + r2.start(); + + HTTPPostEvent e1 = new HTTPPostEvent(); + e1.uri = "https://www.example.com/list"; + e1.commit(); + + HTTPPostEvent e2 = new HTTPPostEvent(); + e2.uri = "https://www.example.com/get"; + e2.commit(); + + HTTPPostEvent e3 = new HTTPPostEvent(); + e3.uri = "https://www.example.com/put"; + e3.commit(); + } + + r1.stop(); + + return Events.fromRecording(r1).size(); + } + } + } diff --git a/test/jdk/jdk/jfr/jvm/TestLongStringsInPool.java b/test/jdk/jdk/jfr/jvm/TestLongStringsInPool.java new file mode 100644 index 0000000000000..8ce3fd3859fdb --- /dev/null +++ b/test/jdk/jdk/jfr/jvm/TestLongStringsInPool.java @@ -0,0 +1,116 @@ +/* + * Copyright (c) 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package jdk.jfr.jvm; + +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; + +import jdk.jfr.Event; +import jdk.jfr.Recording; +import jdk.jfr.consumer.RecordingFile; +import jdk.test.lib.Asserts; +import jdk.test.lib.jfr.EventNames; + +/** + * @test + * @summary Verify that duplicate longer strings doesn't take up unneccessary space + * @key jfr + * @requires vm.hasJFR + * @library /test/lib + * @run main/othervm jdk.jfr.jvm.TestLongStringsInPool + */ +public class TestLongStringsInPool { + private static class StringEvent extends Event { + String message; + } + + public static void main(String[] args) throws Exception { + // Create two recordings; first has only one large + // string, second has several occurences of the same + // string. With long strings (>128 chars) being pooled, + // the two recording should be roughly the same size. + final int numEvents = 10; + final String longString = generateString(); + final int strLen = longString.length(); + final StringEvent event = new StringEvent(); + event.message = longString; + + Recording firstRec = new Recording(); + firstRec.start(); + // commit events with empty message (both recordings + // will have the same number of events) + for (int i = 0; i < numEvents - 1; i++) { + event.message = ""; + event.commit(); + } + // commit 1 event with a long string + event.message = longString; + event.commit(); + + firstRec.stop(); + Path rec1 = Paths.get(".", "rec1.jfr"); + firstRec.dump(rec1); + firstRec.close(); + + + Recording secondRec = new Recording(); + secondRec.start(); + // commit events with the same long string + for (int i = 0; i < numEvents - 1; i++) { + event.message = longString; + event.commit(); + } + // commit 1 event with a long string + event.message = longString; + event.commit(); + + secondRec.stop(); + Path rec2 = Paths.get(".", "rec2.jfr"); + secondRec.dump(rec2); + secondRec.close(); + + // the files aren't exactly the same size, but rec2 should + // not take up space for all strings if they're pooled correctly + long maxAllowedDiff = (numEvents - 1) * strLen; + long diff = Math.abs(Files.size(rec2) - Files.size(rec1)); + + Asserts.assertTrue(diff <= maxAllowedDiff, "Size difference between recordings is too large: "+ diff +" > " + maxAllowedDiff); + Asserts.assertFalse(RecordingFile.readAllEvents(rec1).isEmpty(), "No events found in recording 1"); + Asserts.assertFalse(RecordingFile.readAllEvents(rec2).isEmpty(), "No events found in recording 2"); + Asserts.assertEquals(RecordingFile.readAllEvents(rec1).size(), RecordingFile.readAllEvents(rec2).size(), "The recordings don't have the same number of events"); + } + + /** + * Generate a string of 256 chars length. + * @return + */ + private static String generateString() { + final StringBuilder builder = new StringBuilder(); + for (int i = 0; i < 32; i++) { + builder.append("abcdefgh"); + } + return builder.toString(); + } +} diff --git a/test/jdk/jdk/jfr/threading/TestStringPoolVirtualThreadPinning.java b/test/jdk/jdk/jfr/threading/TestStringPoolVirtualThreadPinning.java new file mode 100644 index 0000000000000..0dc1ef8566139 --- /dev/null +++ b/test/jdk/jdk/jfr/threading/TestStringPoolVirtualThreadPinning.java @@ -0,0 +1,110 @@ +/* + * Copyright (c) 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ +package jdk.jfr.threading; + +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.List; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ThreadFactory; + +import jdk.jfr.Event; +import jdk.jfr.Name; +import jdk.jfr.Recording; +import jdk.jfr.consumer.RecordedEvent; +import jdk.jfr.consumer.RecordedThread; +import jdk.jfr.consumer.RecordingFile; +import jdk.test.lib.Asserts; +import jdk.test.lib.Utils; + +/** + * @test + * @bug 8338417 + * @summary Tests pinning of virtual threads when the JFR string pool monitor is contended. + * @key jfr + * @requires vm.hasJFR & vm.continuations + * @library /test/lib /test/jdk + * @run main/othervm jdk.jfr.threading.TestStringPoolVirtualThreadPinning + */ +public class TestStringPoolVirtualThreadPinning { + + private static final int VIRTUAL_THREAD_COUNT = 100_000; + private static final int STARTER_THREADS = 10; + + @Name("test.Tester") + private static class TestEvent extends Event { + private String eventString = Thread.currentThread().getName(); + } + + /* + * During event commit, the thread is in a critical section because it has loaded a carrier thread local event writer object. + * For virtual threads, a contended monitor, such as a synchronized block, is a point where a thread could become unmounted. + * A monitor guards the JFR string pool, but because of the event writer, remounting a virtual thread onto another carrier is impossible. + * + * The test provokes JFR string pool monitor contention to exercise explicit pin constructs to ensure the pinning of virtual threads. + */ + public static void main(String... args) throws Exception { + try (Recording r = new Recording()) { + r.start(); + + ThreadFactory factory = Thread.ofVirtual().factory(); + CompletableFuture[] c = new CompletableFuture[STARTER_THREADS]; + for (int j = 0; j < STARTER_THREADS; j++) { + c[j] = CompletableFuture.runAsync(() -> { + for (int i = 0; i < VIRTUAL_THREAD_COUNT / STARTER_THREADS; i++) { + try { + Thread vt = factory.newThread(TestStringPoolVirtualThreadPinning::emitEvent); + // For an event field string to be placed in the JFR string pool, it must exceed 16 characters. + // We use the virtual thread name as the event field string so we can verify the result as a 1-1 mapping. + vt.setName("VirtualTestThread-" + i); + vt.start(); + vt.join(); + } catch (InterruptedException ie) { + ie.printStackTrace(); + } + } + }); + } + for (int j = 0; j < STARTER_THREADS; j++) { + c[j].get(); + } + + r.stop(); + Path p = Utils.createTempFile("test", ".jfr"); + r.dump(p); + List events = RecordingFile.readAllEvents(p); + Asserts.assertEquals(events.size(), VIRTUAL_THREAD_COUNT, "Expected " + VIRTUAL_THREAD_COUNT + " events"); + for (RecordedEvent e : events) { + RecordedThread t = e.getThread(); + Asserts.assertNotNull(t); + Asserts.assertTrue(t.isVirtual()); + Asserts.assertEquals(e.getString("eventString"), t.getJavaName()); + } + } + } + + private static void emitEvent() { + TestEvent t = new TestEvent(); + t.commit(); + } +} diff --git a/test/jdk/sun/security/ssl/SSLSessionImpl/MultiNSTClient.java b/test/jdk/sun/security/ssl/SSLSessionImpl/MultiNSTClient.java new file mode 100644 index 0000000000000..57f61a6cd8a64 --- /dev/null +++ b/test/jdk/sun/security/ssl/SSLSessionImpl/MultiNSTClient.java @@ -0,0 +1,173 @@ +/* + * Copyright (c) 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @library /test/lib + * @library /javax/net/ssl/templates + * @bug 8242008 + * @summary Verifies multiple PSKs are used by JSSE + * @run main/othervm MultiNSTClient -Djdk.tls.client.protocols=TLSv1.3 -Djdk.tls.server.newSessionTicketCount=1 + * @run main/othervm MultiNSTClient -Djdk.tls.client.protocols=TLSv1.3 -Djdk.tls.server.newSessionTicketCount=3 + * @run main/othervm MultiNSTClient -Djdk.tls.client.protocols=TLSv1.3 -Djdk.tls.server.newSessionTicketCount=10 + * @run main/othervm MultiNSTClient -Djdk.tls.client.protocols=TLSv1.3 -Djdk.tls.server.enableSessionTicketExtension=true -Djdk.tls.client.enableSessionTicketExtension=true + * @run main/othervm MultiNSTClient -Djdk.tls.client.protocols=TLSv1.3 -Djdk.tls.server.enableSessionTicketExtension=false -Djdk.tls.client.enableSessionTicketExtension=true + * @run main/othervm MultiNSTClient -Djdk.tls.client.protocols=TLSv1.3 -Djdk.tls.server.enableSessionTicketExtension=true -Djdk.tls.client.enableSessionTicketExtension=false + * @run main/othervm MultiNSTClient -Djdk.tls.client.protocols=TLSv1.3 -Djdk.tls.server.enableSessionTicketExtension=false -Djdk.tls.client.enableSessionTicketExtension=false + * @run main/othervm MultiNSTClient -Djdk.tls.client.protocols=TLSv1.2 -Djdk.tls.server.enableSessionTicketExtension=true -Djdk.tls.client.enableSessionTicketExtension=true + */ + +import jdk.test.lib.Utils; +import jdk.test.lib.process.OutputAnalyzer; +import jdk.test.lib.process.ProcessTools; + +import javax.net.ssl.SSLSession; +import java.util.Arrays; +import java.util.HexFormat; +import java.util.List; + +/** + * This test verifies that multiple NSTs and PSKs are sent by a JSSE server. + * Then JSSE client is able to store them all and resume the connection. It + * requires specific text in the TLS debugging to verify the success. + */ + +public class MultiNSTClient { + + static HexFormat hex = HexFormat.of(); + + public static void main(String[] args) throws Exception { + + if (!args[0].equalsIgnoreCase("p")) { + StringBuilder sb = new StringBuilder(); + Arrays.stream(args).forEach(a -> { + sb.append(a); + sb.append(" "); + }); + String params = sb.toString(); + System.setProperty("test.java.opts", + "-Dtest.src=" + System.getProperty("test.src") + + " -Dtest.jdk=" + System.getProperty("test.jdk") + + " -Dtest.root=" + System.getProperty("test.root") + + " -Djavax.net.debug=ssl,handshake " + params + ); + + boolean TLS13 = args[0].contains("1.3"); + + System.out.println("test.java.opts: " + + System.getProperty("test.java.opts")); + + ProcessBuilder pb = ProcessTools.createTestJavaProcessBuilder( + Utils.addTestJavaOpts("MultiNSTClient", "p")); + + OutputAnalyzer output = ProcessTools.executeProcess(pb); + System.out.println("I'm here"); + boolean pass = true; + try { + List list = output.stderrShouldContain("MultiNST PSK"). + asLines().stream().filter(s -> + s.contains("MultiNST PSK")).toList(); + List serverPSK = list.stream().filter(s -> + s.contains("MultiNST PSK (Server)")).toList(); + List clientPSK = list.stream().filter(s -> + s.contains("MultiNST PSK (Client)")).toList(); + System.out.println("found list: " + list.size()); + System.out.println("found server: " + serverPSK.size()); + serverPSK.stream().forEach(s -> System.out.println("\t" + s)); + System.out.println("found client: " + clientPSK.size()); + clientPSK.stream().forEach(s -> System.out.println("\t" + s)); + for (int i = 0; i < 2; i++) { + String svr = serverPSK.getFirst(); + String cli = clientPSK.getFirst(); + if (svr.regionMatches(svr.length() - 16, cli, cli.length() - 16, 16)) { + System.out.println("entry " + (i + 1) + " match."); + } else { + System.out.println("entry " + (i + 1) + " server and client PSK didn't match:"); + System.out.println(" server: " + svr); + System.out.println(" client: " + cli); + pass = false; + } + } + } catch (RuntimeException e) { + System.out.println("No MultiNST PSK found."); + pass = false; + } + + if (TLS13) { + if (!pass) { + throw new Exception("Test failed: " + params); + } + } else { + if (pass) { + throw new Exception("Test failed: " + params); + } + } + System.out.println("Test Passed"); + return; + } + + TLSBase.Server server = new TLSBase.Server(); + + System.out.println("------ Start connection"); + TLSBase.Client initial = new TLSBase.Client(); + SSLSession initialSession = initial.connect().getSession(); + System.out.println("id = " + hex.formatHex(initialSession.getId())); + System.out.println("session = " + initialSession); + + System.out.println("------ getNewSession from original client"); + TLSBase.Client resumClient = new TLSBase.Client(initial); + SSLSession resumption = resumClient.connect().getSession(); + System.out.println("id = " + hex.formatHex(resumption.getId())); + System.out.println("session = " + resumption); + if (!initialSession.toString().equalsIgnoreCase(resumption.toString())) { + throw new Exception("Resumed session did not match"); + } + + System.out.println("------ Second getNewSession from original client"); + TLSBase.Client resumClient2 = new TLSBase.Client(initial); + resumption = resumClient2.connect().getSession(); + System.out.println("id = " + hex.formatHex(resumption.getId())); + System.out.println("session = " + resumption); + if (!initialSession.toString().equalsIgnoreCase(resumption.toString())) { + throw new Exception("Resumed session did not match"); + } + + System.out.println("------ New client connection"); + TLSBase.Client newConnection = new TLSBase.Client(); + SSLSession newSession = newConnection.connect().getSession(); + System.out.println("id = " + hex.formatHex(newSession.getId())); + System.out.println("session = " + newSession); + if (initialSession.toString().equalsIgnoreCase(newSession.toString())) { + throw new Exception("new session is the same as the initial."); + } + + System.out.println("------ Closing connections"); + initial.close(); + resumClient.close(); + resumClient2.close(); + newConnection.close(); + server.close(); + System.out.println("------ End"); + System.exit(0); + } +} diff --git a/test/jdk/sun/security/ssl/SSLSessionImpl/MultiNSTNoSessionCreation.java b/test/jdk/sun/security/ssl/SSLSessionImpl/MultiNSTNoSessionCreation.java new file mode 100644 index 0000000000000..f80270afd37dd --- /dev/null +++ b/test/jdk/sun/security/ssl/SSLSessionImpl/MultiNSTNoSessionCreation.java @@ -0,0 +1,96 @@ +/* + * Copyright (c) 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @library /test/lib + * @library /javax/net/ssl/templates + * @bug 8242008 + * @summary Verifies resumption fails with 0 NSTs and session creation off + * @run main/othervm MultiNSTNoSessionCreation -Djdk.tls.client.protocols=TLSv1.3 -Djdk.tls.server.newSessionTicketCount=0 + * @run main/othervm MultiNSTNoSessionCreation -Djdk.tls.client.protocols=TLSv1.2 -Djdk.tls.server.newSessionTicketCount=0 + */ + +import jdk.test.lib.Utils; +import jdk.test.lib.process.OutputAnalyzer; +import jdk.test.lib.process.ProcessTools; + +import java.util.Arrays; + +/** + * With no NSTs sent by the server, try to resume the session with + * setEnabledSessionCreation(false). The test should get an exception and + * fail to connect. + */ + +public class MultiNSTNoSessionCreation { + + public static void main(String[] args) throws Exception { + + if (!args[0].equalsIgnoreCase("p")) { + StringBuilder sb = new StringBuilder(); + Arrays.stream(args).forEach(a -> sb.append(a).append(" ")); + String params = sb.toString(); + System.setProperty("test.java.opts", + "-Dtest.src=" + System.getProperty("test.src") + + " -Dtest.jdk=" + System.getProperty("test.jdk") + + " -Dtest.root=" + System.getProperty("test.root") + + " -Djavax.net.debug=ssl,handshake " + params); + + System.out.println("test.java.opts: " + + System.getProperty("test.java.opts")); + + ProcessBuilder pb = ProcessTools.createTestJavaProcessBuilder( + Utils.addTestJavaOpts("MultiNSTNoSessionCreation", "p")); + + OutputAnalyzer output = ProcessTools.executeProcess(pb); + try { + if (output.stderrContains( + "(PROTOCOL_VERSION): New session creation is disabled")) { + return; + } + } catch (RuntimeException e) { + throw new Exception("Error collecting data", e); + } + throw new Exception("Disabled creation msg not found"); + } + + TLSBase.Server server = new TLSBase.Server(); + + System.out.println("------ Initial connection"); + TLSBase.Client initial = new TLSBase.Client(); + initial.connect(); + System.out.println( + "------ Resume client w/ setEnableSessionCreation set to false"); + TLSBase.Client resumClient = new TLSBase.Client(initial); + resumClient.socket.setEnableSessionCreation(false); + resumClient.connect(); + + System.out.println("------ Closing connections"); + initial.close(); + resumClient.close(); + server.close(); + System.out.println("------ End"); + System.exit(0); + } +} diff --git a/test/jdk/sun/security/ssl/SSLSessionImpl/MultiNSTParallel.java b/test/jdk/sun/security/ssl/SSLSessionImpl/MultiNSTParallel.java new file mode 100644 index 0000000000000..bff14113ea582 --- /dev/null +++ b/test/jdk/sun/security/ssl/SSLSessionImpl/MultiNSTParallel.java @@ -0,0 +1,205 @@ +/* + * Copyright (c) 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @library /test/lib + * @library /javax/net/ssl/templates + * @bug 8242008 + * @summary Verifies multiple PSKs are used by TLSv1.3 + * @run main/othervm MultiNSTParallel 10 -Djdk.tls.client.protocols=TLSv1.3 + */ + +import jdk.test.lib.Utils; +import jdk.test.lib.process.OutputAnalyzer; +import jdk.test.lib.process.ProcessTools; + +import javax.net.ssl.SSLSession; +import java.util.ArrayList; +import java.util.HexFormat; +import java.util.List; +import java.util.concurrent.CountDownLatch; + +/** + * This test verifies that parallel resumption connections successfully get + * a PSK entry and not initiate a full handshake. + * + * Note: THe first argument after 'MultiNSTParallel' is the ticket count + * The test will set 'jdk.tls.server.NewSessionTicketCount` to that number and + * will start the same number of resumption client attempts. The ticket count + * must be the same or larger than resumption attempts otherwise the queue runs + * empty and the test will fail. + * + * Because this test runs parallel connections, the thread order finish is not + * guaranteed. Each client NST id is checked with all server NSTs ids until + * a match is found. When a match is found, it is removed from the list to + * verify no NST was used more than once. + * + * TLS 1.2 spec does not specify multiple NST behavior. + */ + +public class MultiNSTParallel { + + static HexFormat hex = HexFormat.of(); + final static CountDownLatch wait = new CountDownLatch(1); + + static class ClientThread extends Thread { + TLSBase.Client client; + + ClientThread(TLSBase.Client c) { + client = c; + } + + public void run() { + String name = Thread.currentThread().getName(); + SSLSession r; + System.err.println("waiting " + Thread.currentThread().getName()); + try { + wait.await(); + r = new TLSBase.Client(client).connect().getSession(); + } catch (Exception e) { + throw new RuntimeException(name + ": " +e); + } + StringBuffer sb = new StringBuffer(100); + sb.append("(").append(name).append(") id = "); + sb.append(hex.formatHex(r.getId())); + sb.append("\n(").append(name).append(") session = ").append(r); + if (!client.getSession().toString().equalsIgnoreCase(r.toString())) { + throw new RuntimeException("(" + name + + ") Resumed session did not match"); + } + } + } + + static boolean pass = true; + + public static void main(String[] args) throws Exception { + + if (!args[0].equalsIgnoreCase("p")) { + int ticketCount = Integer.parseInt(args[0]); + StringBuilder sb = new StringBuilder(); + for (int i = 1; i < args.length; i++) { + sb.append(" ").append(args[i]); + } + String params = sb.toString(); + System.setProperty("test.java.opts", + "-Dtest.src=" + System.getProperty("test.src") + + " -Dtest.jdk=" + System.getProperty("test.jdk") + + " -Dtest.root=" + System.getProperty("test.root") + + " -Djavax.net.debug=ssl,handshake " + + " -Djdk.tls.server.newSessionTicketCount=" + ticketCount + + params); + + boolean TLS13 = args[1].contains("1.3"); + + System.out.println("test.java.opts: " + + System.getProperty("test.java.opts")); + + ProcessBuilder pb = ProcessTools.createTestJavaProcessBuilder( + Utils.addTestJavaOpts("MultiNSTParallel", "p")); + + OutputAnalyzer output = ProcessTools.executeProcess(pb); + try { + List list = output.stderrShouldContain("MultiNST PSK"). + asLines().stream().filter(s -> + s.contains("MultiNST PSK")).toList(); + List sp = list.stream().filter(s -> + s.contains("MultiNST PSK (Server)")).toList(); + List serverPSK = new ArrayList<>(sp.stream().toList()); + List clientPSK = list.stream().filter(s -> + s.contains("MultiNST PSK (Client)")).toList(); + System.out.println("found list: " + list.size()); + System.out.println("found server: " + serverPSK.size()); + serverPSK.stream().forEach(s -> System.out.println("\t" + s)); + System.out.println("found client: " + clientPSK.size()); + clientPSK.stream().forEach(s -> System.out.println("\t" + s)); + + // Must search all results as order is not guaranteed. + clientPSK.stream().forEach(cli -> { + for (int i = 0; i < serverPSK.size(); i++) { + String svr = serverPSK.get(i); + if (svr.regionMatches(svr.length() - 16, cli, + cli.length() - 16, 16)) { + System.out.println("entry " + (i + 1) + " match."); + serverPSK.remove(i); + return; + } + } + System.out.println("client entry (" + cli.substring(0, 16) + + ") not found in server list"); + pass = false; + }); + } catch (RuntimeException e) { + System.out.println("Error looking at PSK results."); + throw new Exception(e); + } + + if (TLS13) { + if (!pass) { + throw new Exception("Test failed: " + params); + } + } else { + if (pass) { + throw new Exception("Test failed: " + params); + } + } + System.out.println("Test Passed"); + return; + } + + int ticketCount = Integer.parseInt( + System.getProperty("jdk.tls.server.newSessionTicketCount")); + + TLSBase.Server server = new TLSBase.Server(); + + System.out.println("------ Start connection"); + TLSBase.Client initial = new TLSBase.Client(); + SSLSession initialSession = initial.getSession(); + System.out.println("id = " + hex.formatHex(initialSession.getId())); + System.out.println("session = " + initialSession); + + System.out.println("------ getNewSession from original client"); + + ArrayList slist = new ArrayList<>(ticketCount); + + System.out.println("tx " + ticketCount); + for (int i = 0; ticketCount > i; i++) { + Thread t = new ClientThread(initial); + t.setName("Iteration " + i); + slist.add(t); + t.start(); + } + + wait.countDown(); + for (Thread t : slist) { + t.join(1000); + System.err.println("released: " + t.getName()); + } + + System.out.println("------ Closing connections"); + initial.close(); + server.close(); + System.out.println("------ End"); + System.exit(0); + } +} diff --git a/test/jdk/sun/security/ssl/SSLSessionImpl/MultiNSTSequence.java b/test/jdk/sun/security/ssl/SSLSessionImpl/MultiNSTSequence.java new file mode 100644 index 0000000000000..888dba56a5023 --- /dev/null +++ b/test/jdk/sun/security/ssl/SSLSessionImpl/MultiNSTSequence.java @@ -0,0 +1,145 @@ +/* + * Copyright (c) 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test + * @library /test/lib + * @library /javax/net/ssl/templates + * @bug 8242008 + * @summary Verifies sequence of used NST entries from the cache queue. + * @run main/othervm MultiNSTSequence -Djdk.tls.server.newSessionTicketCount=2 + */ + +import jdk.test.lib.Utils; +import jdk.test.lib.process.OutputAnalyzer; +import jdk.test.lib.process.ProcessTools; + +import javax.net.ssl.SSLSession; +import java.util.Arrays; +import java.util.HexFormat; +import java.util.List; + +/** + * This test verifies that multiple NSTs take the oldest PSK from the + * QueueCacheEntry stored in the TLS Session Cache. + * + * Note: Beyond 9 iterations the PSK id verification code becomes complicated + * with a QueueCacheEntry limit set to retain only the 10 newest entries. + * + * TLS 1.2 spec does not specify multiple NST behavior. + */ + +public class MultiNSTSequence { + + static HexFormat hex = HexFormat.of(); + static final int ITERATIONS = 9; + + public static void main(String[] args) throws Exception { + + if (!args[0].equalsIgnoreCase("p")) { + StringBuilder sb = new StringBuilder(); + Arrays.stream(args).forEach(a -> sb.append(a).append(" ")); + String params = sb.toString(); + System.setProperty("test.java.opts", + "-Dtest.src=" + System.getProperty("test.src") + + " -Dtest.jdk=" + System.getProperty("test.jdk") + + " -Dtest.root=" + System.getProperty("test.root") + + " -Djavax.net.debug=ssl,handshake " + params + ); + + System.out.println("test.java.opts: " + + System.getProperty("test.java.opts")); + + ProcessBuilder pb = ProcessTools.createTestJavaProcessBuilder( + Utils.addTestJavaOpts("MultiNSTSequence", "p")); + + OutputAnalyzer output = ProcessTools.executeProcess(pb); + boolean pass = true; + try { + List list = output.stderrShouldContain("MultiNST PSK"). + asLines().stream().filter(s -> + s.contains("MultiNST PSK")).toList(); + List serverPSK = list.stream().filter(s -> + s.contains("MultiNST PSK (Server)")).toList(); + List clientPSK = list.stream().filter(s -> + s.contains("MultiNST PSK (Client)")).toList(); + System.out.println("found list: " + list.size()); + System.out.println("found server: " + serverPSK.size()); + serverPSK.stream().forEach(s -> System.out.println("\t" + s)); + System.out.println("found client: " + clientPSK.size()); + clientPSK.stream().forEach(s -> System.out.println("\t" + s)); + int i; + for (i = 0; i < ITERATIONS; i++) { + String svr = serverPSK.get(i); + String cli = clientPSK.get(i); + if (svr.regionMatches(svr.length() - 16, cli, cli.length() - 16, 16)) { + System.out.println("entry " + (i + 1) + " match."); + } else { + System.out.println("entry " + (i + 1) + " server and client PSK didn't match:"); + System.out.println(" server: " + svr); + System.out.println(" client: " + cli); + pass = false; + } + } + } catch (RuntimeException e) { + System.out.println("Server and Client PSK usage order is not" + + " the same."); + pass = false; + } + + if (!pass) { + throw new Exception("Test failed: " + params); + } + System.out.println("Test Passed"); + return; + } + + TLSBase.Server server = new TLSBase.Server(); + + System.out.println("------ Initial connection"); + TLSBase.Client initial = new TLSBase.Client(); + + SSLSession initialSession = initial.connect().getSession(); + System.out.println("id = " + hex.formatHex(initialSession.getId())); + System.out.println("session = " + initialSession); + + System.out.println("------ Resume client"); + for (int i = 0; i < ITERATIONS; i++) { + SSLSession r = new TLSBase.Client(initial).connect().getSession(); + StringBuilder sb = new StringBuilder(100); + sb.append("Iteration: ").append(i); + sb.append("\tid = ").append(hex.formatHex(r.getId())); + sb.append("\tsession = ").append(r); + System.out.println(sb); + if (!initialSession.toString().equalsIgnoreCase(r.toString())) { + throw new Exception("Resumed session did not match"); + } + } + + System.out.println("------ Closing connections"); + initial.close(); + server.close(); + System.out.println("------ End"); + System.exit(0); + } +} diff --git a/test/langtools/tools/javac/parser/JavacParserTest.java b/test/langtools/tools/javac/parser/JavacParserTest.java index 547de1088b460..40ab577a5d135 100644 --- a/test/langtools/tools/javac/parser/JavacParserTest.java +++ b/test/langtools/tools/javac/parser/JavacParserTest.java @@ -23,7 +23,7 @@ /* * @test - * @bug 7073631 7159445 7156633 8028235 8065753 8205418 8205913 8228451 8237041 8253584 8246774 8256411 8256149 8259050 8266436 8267221 8271928 8275097 8293897 8295401 8304671 8310326 8312093 8312204 8315452 8337976 + * @bug 7073631 7159445 7156633 8028235 8065753 8205418 8205913 8228451 8237041 8253584 8246774 8256411 8256149 8259050 8266436 8267221 8271928 8275097 8293897 8295401 8304671 8310326 8312093 8312204 8315452 8337976 8324859 * @summary tests error and diagnostics positions * @author Jan Lahoda * @modules jdk.compiler/com.sun.tools.javac.api @@ -2483,6 +2483,537 @@ public class Test { codes); } + @Test //JDK-8324859 + void testImplicitlyDeclaredClassesConfusion1() throws IOException { + String code = """ + package tests; + public class TestB { + public static boolean test() // missing open brace + return true; + } + public static boolean test2() { + return true; + } + }"""; + DiagnosticCollector coll = + new DiagnosticCollector<>(); + JavacTaskImpl ct = (JavacTaskImpl) tool.getTask(null, fm, coll, + List.of("--enable-preview", "--source", SOURCE_VERSION), + null, Arrays.asList(new MyFileObject(code))); + CompilationUnitTree cut = ct.parse().iterator().next(); + + List codes = new LinkedList<>(); + + for (Diagnostic d : coll.getDiagnostics()) { + codes.add(d.getLineNumber() + ":" + d.getColumnNumber() + ":" + d.getCode()); + } + + assertEquals("testImplicitlyDeclaredClassesConfusion1: " + codes, + List.of("3:33:compiler.err.expected2"), + codes); + String result = toStringWithErrors(cut).replaceAll("\\R", "\n"); + System.out.println("RESULT\n" + result); + assertEquals("incorrect AST", + result, + """ + package tests; + \n\ + public class TestB { + \n\ + public static boolean test() { + return true; + } + \n\ + public static boolean test2() { + return true; + } + }"""); + } + + @Test //JDK-8324859 + void testImplicitlyDeclaredClassesConfusion2() throws IOException { + String code = """ + package tests; + public class TestB { + public static boolean test() // missing open brace + + public static boolean test2() { + return true; + } + } """; + DiagnosticCollector coll = + new DiagnosticCollector<>(); + JavacTaskImpl ct = (JavacTaskImpl) tool.getTask(null, fm, coll, + List.of("--enable-preview", "--source", SOURCE_VERSION), + null, Arrays.asList(new MyFileObject(code))); + CompilationUnitTree cut = ct.parse().iterator().next(); + + List codes = new LinkedList<>(); + + for (Diagnostic d : coll.getDiagnostics()) { + codes.add(d.getLineNumber() + ":" + d.getColumnNumber() + ":" + d.getCode()); + } + + assertEquals("testImplicitlyDeclaredClassesConfusion2: " + codes, + List.of("3:33:compiler.err.expected2"), + codes); + String result = toStringWithErrors(cut).replaceAll("\\R", "\n"); + System.out.println("RESULT\n" + result); + assertEquals("incorrect AST", + result, + """ + package tests; + \n\ + public class TestB { + \n\ + public static boolean test(); + \n\ + public static boolean test2() { + return true; + } + }"""); + } + + @Test //JDK-8324859 + void testImplicitlyDeclaredClassesConfusion3() throws IOException { + String code = """ + package tests; + public class TestB { + public static boolean test() // missing open brace + } + """; + DiagnosticCollector coll = + new DiagnosticCollector<>(); + JavacTaskImpl ct = (JavacTaskImpl) tool.getTask(null, fm, coll, + List.of("--enable-preview", "--source", SOURCE_VERSION), + null, Arrays.asList(new MyFileObject(code))); + CompilationUnitTree cut = ct.parse().iterator().next(); + + List codes = new LinkedList<>(); + + for (Diagnostic d : coll.getDiagnostics()) { + codes.add(d.getLineNumber() + ":" + d.getColumnNumber() + ":" + d.getCode()); + } + + assertEquals("testImplicitlyDeclaredClassesConfusion3: " + codes, + List.of("3:33:compiler.err.expected2"), + codes); + String result = toStringWithErrors(cut).replaceAll("\\R", "\n"); + System.out.println("RESULT\n" + result); + assertEquals("incorrect AST", + result, + """ + package tests; + \n\ + public class TestB { + \n\ + public static boolean test(); + }"""); + } + + @Test //JDK-8324859 + void testImplicitlyDeclaredClassesConfusion4() throws IOException { + String code = """ + package tests; + public class TestB { + public static boolean test() // missing open brace + } + } + """; + DiagnosticCollector coll = + new DiagnosticCollector<>(); + JavacTaskImpl ct = (JavacTaskImpl) tool.getTask(null, fm, coll, + List.of("--enable-preview", "--source", SOURCE_VERSION), + null, Arrays.asList(new MyFileObject(code))); + CompilationUnitTree cut = ct.parse().iterator().next(); + + List codes = new LinkedList<>(); + + for (Diagnostic d : coll.getDiagnostics()) { + codes.add(d.getLineNumber() + ":" + d.getColumnNumber() + ":" + d.getCode()); + } + + assertEquals("testImplicitlyDeclaredClassesConfusion4: " + codes, + List.of("3:33:compiler.err.expected2"), + codes); + String result = toStringWithErrors(cut).replaceAll("\\R", "\n"); + System.out.println("RESULT\n" + result); + assertEquals("incorrect AST", + result, + """ + package tests; + \n\ + public class TestB { + \n\ + public static boolean test() { + } + }"""); + } + + @Test //JDK-8324859 + void testImplicitlyDeclaredClassesConfusion5() throws IOException { + String code = """ + package tests; + public class TestB { + public static boolean test(String, + } + class T {} + """; + DiagnosticCollector coll = + new DiagnosticCollector<>(); + JavacTaskImpl ct = (JavacTaskImpl) tool.getTask(null, fm, coll, + List.of("--enable-preview", "--source", SOURCE_VERSION), + null, Arrays.asList(new MyFileObject(code))); + CompilationUnitTree cut = ct.parse().iterator().next(); + + List codes = new LinkedList<>(); + + for (Diagnostic d : coll.getDiagnostics()) { + codes.add(d.getLineNumber() + ":" + d.getColumnNumber() + ":" + d.getCode()); + } + + assertEquals("testImplicitlyDeclaredClassesConfusion5: " + codes, + List.of("3:38:compiler.err.expected", + "4:1:compiler.err.illegal.start.of.type"), + codes); + String result = toStringWithErrors(cut).replaceAll("\\R", "\n"); + System.out.println("RESULT\n" + result); + assertEquals("incorrect AST", + result, + """ + package tests; + \n\ + public class TestB { + \n\ + public static boolean test(String , (ERROR: ) ); + } + class T { + }"""); + } + + @Test //JDK-8324859 + void testImplicitlyDeclaredClassesConfusion6() throws IOException { + String code = """ + package tests; + public class TestB { + private Object testMethod(final String arg1 final String arg2) { + return null; + } + } + """; + DiagnosticCollector coll = + new DiagnosticCollector<>(); + JavacTaskImpl ct = (JavacTaskImpl) tool.getTask(null, fm, coll, + List.of("--enable-preview", "--source", SOURCE_VERSION), + null, Arrays.asList(new MyFileObject(code))); + CompilationUnitTree cut = ct.parse().iterator().next(); + + List codes = new LinkedList<>(); + + for (Diagnostic d : coll.getDiagnostics()) { + codes.add(d.getLineNumber() + ":" + d.getColumnNumber() + ":" + d.getCode()); + } + + assertEquals("testImplicitlyDeclaredClassesConfusion5: " + codes, + List.of("3:48:compiler.err.expected3", + "3:66:compiler.err.expected"), + codes); + String result = toStringWithErrors(cut).replaceAll("\\R", "\n"); + System.out.println("RESULT\n" + result); + assertEquals("incorrect AST", + result, + """ + package tests; + \n\ + public class TestB { + \n\ + private Object testMethod(final String arg1); + final String arg2; + { + return null; + } + }"""); + } + + @Test //JDK-8324859 + void testImplicitlyDeclaredClassesConfusion7() throws IOException { + //after 'default' attribute value, only semicolon (';') is expected, + //not left brace ('{'): + String code = """ + package tests; + public @interface A { + public String value() default "" + } + """; + DiagnosticCollector coll = + new DiagnosticCollector<>(); + JavacTaskImpl ct = (JavacTaskImpl) tool.getTask(null, fm, coll, + List.of("--enable-preview", "--source", SOURCE_VERSION), + null, Arrays.asList(new MyFileObject(code))); + CompilationUnitTree cut = ct.parse().iterator().next(); + + List codes = new LinkedList<>(); + + for (Diagnostic d : coll.getDiagnostics()) { + codes.add(d.getLineNumber() + ":" + d.getColumnNumber() + ":" + d.getCode()); + } + + assertEquals("testImplicitlyDeclaredClassesConfusion5: " + codes, + List.of("3:37:compiler.err.expected"), + codes); + String result = toStringWithErrors(cut).replaceAll("\\R", "\n"); + System.out.println("RESULT\n" + result); + assertEquals("incorrect AST", + result, + """ + package tests; + \n\ + public @interface A { + \n\ + public String value() default ""; + }"""); + } + + @Test //JDK-8324859 + void testImplicitlyDeclaredClassesConfusion10() throws IOException { + String code = """ + package tests; + public class TestB { + public static boolean test() // missing open brace + String s = ""; + return s.isEmpty(); + } + public static boolean test2() { + return true; + } + }"""; + DiagnosticCollector coll = + new DiagnosticCollector<>(); + JavacTaskImpl ct = (JavacTaskImpl) tool.getTask(null, fm, coll, + List.of("--enable-preview", "--source", SOURCE_VERSION), + null, Arrays.asList(new MyFileObject(code))); + CompilationUnitTree cut = ct.parse().iterator().next(); + + List codes = new LinkedList<>(); + + for (Diagnostic d : coll.getDiagnostics()) { + codes.add(d.getLineNumber() + ":" + d.getColumnNumber() + ":" + d.getCode()); + } + + assertEquals("testImplicitlyDeclaredClassesConfusion1: " + codes, + List.of("3:33:compiler.err.expected2"), + codes); + String result = toStringWithErrors(cut).replaceAll("\\R", "\n"); + System.out.println("RESULT\n" + result); + assertEquals("incorrect AST", + result, + """ + package tests; + + public class TestB { + \n\ + public static boolean test() { + String s = ""; + return s.isEmpty(); + } + \n\ + public static boolean test2() { + return true; + } + }"""); + } + + @Test //JDK-8324859 + void testImplicitlyDeclaredClassesConfusion11() throws IOException { + String code = """ + package tests; + public class TestB { + public static boolean test() // missing open brace + String s = ""; //field declaration + public static boolean test2() { + return true; + } + }"""; + DiagnosticCollector coll = + new DiagnosticCollector<>(); + JavacTaskImpl ct = (JavacTaskImpl) tool.getTask(null, fm, coll, + List.of("--enable-preview", "--source", SOURCE_VERSION), + null, Arrays.asList(new MyFileObject(code))); + CompilationUnitTree cut = ct.parse().iterator().next(); + + List codes = new LinkedList<>(); + + for (Diagnostic d : coll.getDiagnostics()) { + codes.add(d.getLineNumber() + ":" + d.getColumnNumber() + ":" + d.getCode()); + } + + assertEquals("testImplicitlyDeclaredClassesConfusion1: " + codes, + List.of("3:33:compiler.err.expected2"), + codes); + String result = toStringWithErrors(cut).replaceAll("\\R", "\n"); + System.out.println("RESULT\n" + result); + assertEquals("incorrect AST", + result, + """ + package tests; + \n\ + public class TestB { + \n\ + public static boolean test(); + String s = ""; + \n\ + public static boolean test2() { + return true; + } + }"""); + } + + @Test //JDK-8324859 + void testImplicitlyDeclaredClassesConfusion12() throws IOException { + String code = """ + package tests; + public class TestB { + public static boolean test() // missing open brace + final String s = ""; + return s.isEmpty(); + } + public static boolean test2() { + return true; + } + }"""; + DiagnosticCollector coll = + new DiagnosticCollector<>(); + JavacTaskImpl ct = (JavacTaskImpl) tool.getTask(null, fm, coll, + List.of("--enable-preview", "--source", SOURCE_VERSION), + null, Arrays.asList(new MyFileObject(code))); + CompilationUnitTree cut = ct.parse().iterator().next(); + + List codes = new LinkedList<>(); + + for (Diagnostic d : coll.getDiagnostics()) { + codes.add(d.getLineNumber() + ":" + d.getColumnNumber() + ":" + d.getCode()); + } + + assertEquals("testImplicitlyDeclaredClassesConfusion1: " + codes, + List.of("3:33:compiler.err.expected2"), + codes); + String result = toStringWithErrors(cut).replaceAll("\\R", "\n"); + System.out.println("RESULT\n" + result); + assertEquals("incorrect AST", + result, + """ + package tests; + \n\ + public class TestB { + \n\ + public static boolean test() { + final String s = ""; + return s.isEmpty(); + } + \n\ + public static boolean test2() { + return true; + } + }"""); + } + + @Test //JDK-8324859 + void testImplicitlyDeclaredClassesConfusion13() throws IOException { + String code = """ + package tests; + public class TestB { + public static boolean test() // missing open brace + final String s = ""; //field declaration? + public static boolean test2() { + return true; + } + }"""; + DiagnosticCollector coll = + new DiagnosticCollector<>(); + JavacTaskImpl ct = (JavacTaskImpl) tool.getTask(null, fm, coll, + List.of("--enable-preview", "--source", SOURCE_VERSION), + null, Arrays.asList(new MyFileObject(code))); + CompilationUnitTree cut = ct.parse().iterator().next(); + + List codes = new LinkedList<>(); + + for (Diagnostic d : coll.getDiagnostics()) { + codes.add(d.getLineNumber() + ":" + d.getColumnNumber() + ":" + d.getCode()); + } + + assertEquals("testImplicitlyDeclaredClassesConfusion1: " + codes, + List.of("3:33:compiler.err.expected2"), + codes); + String result = toStringWithErrors(cut).replaceAll("\\R", "\n"); + System.out.println("RESULT\n" + result); + assertEquals("incorrect AST", + result, + """ + package tests; + \n\ + public class TestB { + \n\ + public static boolean test(); + final String s = ""; + \n\ + public static boolean test2() { + return true; + } + }"""); + } + + @Test //JDK-8324859 + void testImplicitlyDeclaredClassesConfusion14() throws IOException { + String code = """ + package tests; + public class TestB { + public static boolean test() // missing open brace + String s = ""; + s.length(); + if (true); //force parse as block + public static boolean test2() { + return true; + } + }"""; + DiagnosticCollector coll = + new DiagnosticCollector<>(); + JavacTaskImpl ct = (JavacTaskImpl) tool.getTask(null, fm, coll, + List.of("--enable-preview", "--source", SOURCE_VERSION), + null, Arrays.asList(new MyFileObject(code))); + CompilationUnitTree cut = ct.parse().iterator().next(); + + List codes = new LinkedList<>(); + + for (Diagnostic d : coll.getDiagnostics()) { + codes.add(d.getLineNumber() + ":" + d.getColumnNumber() + ":" + d.getCode()); + } + + assertEquals("testImplicitlyDeclaredClassesConfusion1: " + codes, + List.of("3:33:compiler.err.expected2", + "7:5:compiler.err.illegal.start.of.expr"), + codes); + String result = toStringWithErrors(cut).replaceAll("\\R", "\n"); + System.out.println("RESULT\n" + result); + assertEquals("incorrect AST", + result, + """ + package tests; + \n\ + public class TestB { + \n\ + public static boolean test() { + String s = ""; + s.length(); + if (true) ; + (ERROR: ); + } + \n\ + public static boolean test2() { + return true; + } + }"""); + } + void run(String[] args) throws Exception { int passed = 0, failed = 0; final Pattern p = (args != null && args.length > 0) diff --git a/test/langtools/tools/javac/recovery/AttrRecovery.java b/test/langtools/tools/javac/recovery/AttrRecovery.java index 629cef45c6270..19325420af7f9 100644 --- a/test/langtools/tools/javac/recovery/AttrRecovery.java +++ b/test/langtools/tools/javac/recovery/AttrRecovery.java @@ -23,7 +23,7 @@ /* * @test - * @bug 8301580 8322159 8333107 8332230 + * @bug 8301580 8322159 8333107 8332230 8338678 * @summary Verify error recovery w.r.t. Attr * @library /tools/lib * @enablePreview @@ -34,9 +34,23 @@ * @run main AttrRecovery */ +import com.sun.source.tree.VariableTree; +import com.sun.source.util.TaskEvent; +import com.sun.source.util.TaskListener; +import com.sun.source.util.TreePathScanner; +import com.sun.source.util.Trees; import java.nio.file.Path; +import java.util.IdentityHashMap; import java.util.List; +import java.util.Map; import java.util.Objects; +import java.util.stream.Collectors; +import javax.lang.model.element.Element; +import javax.lang.model.element.VariableElement; +import javax.lang.model.type.DeclaredType; +import javax.lang.model.type.TypeKind; +import javax.lang.model.type.TypeMirror; +import javax.tools.Diagnostic; import toolbox.JavacTask; import toolbox.Task.Expect; @@ -234,4 +248,80 @@ public Undefined g(Undefined u) { } } + @Test + public void testParameterizedErroneousType() throws Exception { + String code = """ + public class C { + Undefined1 variable1; + } + """; + Path curPath = Path.of("."); + List actual = new JavacTask(tb) + .options("-XDrawDiagnostics") + .sources(code) + .outdir(curPath) + .callback(task -> { + task.addTaskListener(new TaskListener() { + @Override + public void finished(TaskEvent e) { + Trees trees = Trees.instance(task); + + if (e.getKind() == TaskEvent.Kind.ANALYZE) { + new TreePathScanner() { + @Override + public Void visitVariable(VariableTree tree, Void p) { + VariableElement var = (VariableElement) trees.getElement(getCurrentPath()); + + trees.printMessage(Diagnostic.Kind.NOTE, type2String(var.asType()), tree, e.getCompilationUnit()); + + return super.visitVariable(tree, p); + } + }.scan(e.getCompilationUnit(), null); + } + } + Map identityRename = new IdentityHashMap<>(); + String type2String(TypeMirror type) { + StringBuilder result = new StringBuilder(); + + result.append(type.getKind()); + result.append(":"); + result.append(type.toString()); + + if (type.getKind() == TypeKind.DECLARED || + type.getKind() == TypeKind.ERROR) { + DeclaredType dt = (DeclaredType) type; + Element el = task.getTypes().asElement(dt); + result.append(":"); + result.append(el.toString()); + if (!dt.getTypeArguments().isEmpty()) { + result.append(dt.getTypeArguments() + .stream() + .map(tm -> type2String(tm)) + .collect(Collectors.joining(", ", "<", ">"))); + } + } else { + throw new AssertionError(type.getKind().name()); + } + + return result.toString(); + } + }); + }) + .run(Expect.FAIL) + .writeAll() + .getOutputLines(OutputKind.DIRECT); + + List expected = List.of( + "C.java:2:5: compiler.err.cant.resolve.location: kindname.class, Undefined1, , , (compiler.misc.location: kindname.class, C, null)", + "C.java:2:16: compiler.err.cant.resolve.location: kindname.class, Undefined2, , , (compiler.misc.location: kindname.class, C, null)", + "C.java:2:28: compiler.err.cant.resolve.location: kindname.class, Undefined3, , , (compiler.misc.location: kindname.class, C, null)", + "C.java:2:40: compiler.note.proc.messager: ERROR:Undefined1:Undefined1", + "3 errors" + ); + + if (!Objects.equals(actual, expected)) { + error("Expected: " + expected + ", but got: " + actual); + } + } + } diff --git a/test/lib/jdk/test/lib/NetworkConfiguration.java b/test/lib/jdk/test/lib/NetworkConfiguration.java index 8ea10ede6a4a2..3532bb1a3ee20 100644 --- a/test/lib/jdk/test/lib/NetworkConfiguration.java +++ b/test/lib/jdk/test/lib/NetworkConfiguration.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2023, 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 @@ -127,8 +127,8 @@ public static boolean isSameInterface(NetworkInterface ni1, NetworkInterface ni2 public static boolean isTestable(NetworkInterface nif) { if (Platform.isOSX()) { - if (nif.getName().contains("awdl")) { - return false; // exclude awdl + if (nif.getName().contains("awdl") || nif.getName().contains("docker")) { + return false; // exclude awdl or docker } // filter out interfaces that only have link-local IPv6 addresses // on macOS interfaces like 'en6' fall in this category and @@ -145,6 +145,13 @@ public static boolean isTestable(NetworkInterface nif) { return false; } } + + if (Platform.isLinux()) { + String dName = nif.getDisplayName(); + if (dName != null && dName.contains("docker")) { + return false; + } + } return true; } diff --git a/test/micro/org/openjdk/bench/java/util/concurrent/Maps.java b/test/micro/org/openjdk/bench/java/util/concurrent/Maps.java index bd68e582e6a2f..62883efb8bb89 100644 --- a/test/micro/org/openjdk/bench/java/util/concurrent/Maps.java +++ b/test/micro/org/openjdk/bench/java/util/concurrent/Maps.java @@ -1,5 +1,6 @@ /* * Copyright (c) 2014, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2024, Alibaba Group Holding Limited. 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,6 +36,7 @@ import org.openjdk.jmh.annotations.Threads; import org.openjdk.jmh.annotations.Warmup; +import java.util.Enumeration; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.TimeUnit; @@ -127,6 +129,21 @@ public ConcurrentHashMap testConcurrentHashMapPutAll() { return map; } + @Benchmark + public int testConcurrentHashMapIterators() { + ConcurrentHashMap map = (ConcurrentHashMap) staticMap; + int sum = 0; + Enumeration it = map.elements(); + while (it.hasMoreElements()) { + sum += (int) it.nextElement(); + } + it = map.keys(); + while (it.hasMoreElements()) { + sum += (int) it.nextElement(); + } + return sum; + } + private static class SimpleRandom { private final static long multiplier = 0x5DEECE66DL; private final static long addend = 0xBL;