diff --git a/make/CompileDemos.gmk b/make/CompileDemos.gmk index dfe30c70173..3aee428602d 100644 --- a/make/CompileDemos.gmk +++ b/make/CompileDemos.gmk @@ -1,5 +1,5 @@ # -# Copyright (c) 2011, 2023, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2011, 2024, Oracle and/or its affiliates. All rights reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it @@ -32,7 +32,6 @@ default: all include $(SPEC) include MakeBase.gmk include JavaCompilation.gmk -include NativeCompilation.gmk include TextFileProcessing.gmk include ZipArchive.gmk diff --git a/make/Hsdis.gmk b/make/Hsdis.gmk index 87e135e1154..13d84f964bc 100644 --- a/make/Hsdis.gmk +++ b/make/Hsdis.gmk @@ -136,11 +136,17 @@ ifeq ($(HSDIS_BACKEND), binutils) endif endif +################################################################################ +## Build libhsdis +################################################################################ + $(eval $(call SetupJdkLibrary, BUILD_HSDIS, \ NAME := hsdis, \ LINK_TYPE := $(HSDIS_LINK_TYPE), \ SRC := $(TOPDIR)/src/utils/hsdis/$(HSDIS_BACKEND), \ - EXTRA_HEADER_DIRS := $(TOPDIR)/src/utils/hsdis, \ + EXTRA_HEADER_DIRS := \ + java.base:include \ + $(TOPDIR)/src/utils/hsdis, \ OUTPUT_DIR := $(HSDIS_OUTPUT_DIR), \ OBJECT_DIR := $(HSDIS_OUTPUT_DIR), \ DISABLED_WARNINGS_gcc := undef format-nonliteral sign-compare, \ diff --git a/make/UpdateX11Wrappers.gmk b/make/UpdateX11Wrappers.gmk index 3201b5f883f..f6f43ac2b53 100644 --- a/make/UpdateX11Wrappers.gmk +++ b/make/UpdateX11Wrappers.gmk @@ -1,5 +1,5 @@ # -# Copyright (c) 2012, 2022, 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 @@ -30,7 +30,7 @@ default: all include $(SPEC) include MakeBase.gmk include Execute.gmk -include NativeCompilation.gmk +include JdkNativeCompilation.gmk include ToolsJdk.gmk ################################################################################ @@ -47,14 +47,14 @@ ifeq ($(COMPILE_TYPE), cross) $(error It is not possible to update the x11wrappers when cross-compiling) endif +BITS := $(OPENJDK_TARGET_CPU_BITS) + X11WRAPPERS_OUTPUT := $(SUPPORT_OUTPUTDIR)/x11wrappers GENERATOR_SOURCE_FILE := $(X11WRAPPERS_OUTPUT)/src/data_generator.c GENSRC_X11WRAPPERS_DATADIR := $(TOPDIR)/src/java.desktop/unix/data/x11wrappergen WRAPPER_OUTPUT_FILE := $(GENSRC_X11WRAPPERS_DATADIR)/sizes-$(BITS).txt -BITS := $(OPENJDK_TARGET_CPU_BITS) - # Generate the C code for the program that will output the offset file. $(eval $(call SetupExecute, gensrc_generator, \ INFO := Generating X11 wrapper data generator source code, \ @@ -76,14 +76,17 @@ DATA_GENERATOR_INCLUDES := \ -I$(TOPDIR)/src/java.desktop/share/native/libawt/awt/image/cvutils \ # +################################################################################ +## Build data_generator +################################################################################ + # Compile the generated C code into an executable. -$(eval $(call SetupNativeCompilation, BUILD_DATA_GENERATOR, \ - PROGRAM := data_generator, \ - OUTPUT_DIR := $(X11WRAPPERS_OUTPUT)/bin, \ +$(eval $(call SetupJdkExecutable, BUILD_DATA_GENERATOR, \ + NAME := data_generator, \ EXTRA_FILES := $(GENERATOR_SOURCE_FILE), \ - CFLAGS := $(X_CFLAGS) $(DATA_GENERATOR_INCLUDES) $(CFLAGS_JDKEXE), \ - LDFLAGS := $(LDFLAGS_JDKEXE), \ + CFLAGS := $(X_CFLAGS) $(DATA_GENERATOR_INCLUDES), \ LIBS := $(X_LIBS), \ + OUTPUT_DIR := $(X11WRAPPERS_OUTPUT)/bin, \ OBJECT_DIR := $(X11WRAPPERS_OUTPUT)/objs, \ )) @@ -92,6 +95,7 @@ $(eval $(call SetupExecute, run_wrappergen, \ INFO := Generating X11 wrapper data files, \ DEPS := $(BUILD_DATA_GENERATOR), \ OUTPUT_FILE := $(WRAPPER_OUTPUT_FILE), \ + SUPPORT_DIR := $(X11WRAPPERS_OUTPUT)/run-wrapper, \ COMMAND := $(BUILD_DATA_GENERATOR_TARGET) | $(SORT) > $(WRAPPER_OUTPUT_FILE), \ )) diff --git a/make/autoconf/flags-cflags.m4 b/make/autoconf/flags-cflags.m4 index 658d6299b4d..bcfda0cf51a 100644 --- a/make/autoconf/flags-cflags.m4 +++ b/make/autoconf/flags-cflags.m4 @@ -577,8 +577,8 @@ AC_DEFUN([FLAGS_SETUP_CFLAGS_HELPER], elif test "x$TOOLCHAIN_TYPE" = xmicrosoft; then # The -utf-8 option sets source and execution character sets to UTF-8 to enable correct # compilation of all source files regardless of the active code page on Windows. - TOOLCHAIN_CFLAGS_JVM="-nologo -MD -Zc:preprocessor -Zc:strictStrings -Zc:inline -permissive- -utf-8 -MP" - TOOLCHAIN_CFLAGS_JDK="-nologo -MD -Zc:preprocessor -Zc:strictStrings -Zc:inline -utf-8 -Zc:wchar_t-" + TOOLCHAIN_CFLAGS_JVM="-nologo -MD -Zc:preprocessor -Zc:inline -permissive- -utf-8 -MP" + TOOLCHAIN_CFLAGS_JDK="-nologo -MD -Zc:preprocessor -Zc:inline -permissive- -utf-8 -Zc:wchar_t-" fi # CFLAGS C language level for JDK sources (hotspot only uses C++) diff --git a/make/common/JdkNativeCompilation.gmk b/make/common/JdkNativeCompilation.gmk index 2eecd9c1932..49a1eb033a1 100644 --- a/make/common/JdkNativeCompilation.gmk +++ b/make/common/JdkNativeCompilation.gmk @@ -122,13 +122,17 @@ JDK_RCFLAGS=$(RCFLAGS) \ # JDK_LIBS -- libraries generated by the JDK build system to link against # JDK_LIBS_ or JDK_LIBS_ -- additional JDK_LIBS for the given OS # or OS type only +# DEFAULT_LIBCXX -- if false, do not add LIBCXX to LIBS for C++ compilations # DEFAULT_CFLAGS -- if false, do not add default CFLAGS and CXXFLAGS +# DEFAULT_LDFLAGS -- if false, do not add default LDFLAGS # CFLAGS_FILTER_OUT -- flags to filter out from default CFLAGS # CXXFLAGS_FILTER_OUT -- flags to filter out from default CXXFLAGS # LDFLAGS_FILTER_OUT -- flags to filter out from default LDFLAGS # LD_SET_ORIGIN -- if false, do not add SET_*_ORIGIN flags to LDFLAGS # APPEND_LDFLAGS -- a quirk to have additional LDFLAGS that will be set after # the origin flags +# DEFAULT_VERSIONINFO_RESOURCE -- if false, do not set the default +# VERSIONINFO_RESOURCE # SetupJdkNativeCompilation = $(NamedParamsMacroTemplate) define SetupJdkNativeCompilationBody @@ -164,15 +168,19 @@ define SetupJdkNativeCompilationBody endif endif - ifeq ($$($1_LINK_TYPE), C++) - $1_LIBS += $(LIBCXX) + ifneq ($$($1_DEFAULT_LIBCXX), false) + ifeq ($$($1_LINK_TYPE), C++) + $1_LIBS += $(LIBCXX) + endif endif ifeq ($$($1_SRC), ) ifneq ($$(MODULE), ) $1_SRC := $$(call FindSrcDirsForComponent, $$(MODULE), $$($1_NATIVE_DIR_PREFIX)$$($1_NAME)) else - $$(error Must specify SRC in a MODULE free context) + ifeq ($$($1_EXTRA_FILES), ) + $$(error Must specify SRC or EXTRA_FILES in a MODULE free context) + endif endif else $1_SRC := $$(foreach dir, $$($1_SRC), $$(call ProcessDir, $$(dir))) @@ -188,8 +196,10 @@ define SetupJdkNativeCompilationBody $1_SRC := $$(filter-out $$($1_EXCLUDE_SRC), $$($1_SRC)) endif - ifeq ($$($1_VERSIONINFO_RESOURCE), ) - $1_VERSIONINFO_RESOURCE := $$(GLOBAL_VERSION_INFO_RESOURCE) + ifneq ($$($1_DEFAULT_VERSIONINFO_RESOURCE), false) + ifeq ($$($1_VERSIONINFO_RESOURCE), ) + $1_VERSIONINFO_RESOURCE := $$(GLOBAL_VERSION_INFO_RESOURCE) + endif endif ifeq ($$($1_RC_FILEDESC), ) @@ -208,7 +218,9 @@ define SetupJdkNativeCompilationBody endif # Add the module specific java header dir - $1_SRC_HEADER_FLAGS += $$(addprefix -I, $$(call GetJavaHeaderDir, $$(MODULE))) + ifneq ($$(MODULE), ) + $1_SRC_HEADER_FLAGS += $$(addprefix -I, $$(call GetJavaHeaderDir, $$(MODULE))) + endif $1_JDK_LIBS += $$($1_JDK_LIBS_$$(OPENJDK_TARGET_OS)) $1_JDK_LIBS += $$($1_JDK_LIBS_$$(OPENJDK_TARGET_OS_TYPE)) diff --git a/make/common/TestFilesCompilation.gmk b/make/common/TestFilesCompilation.gmk index fd2954cbec6..5fc850d1d8b 100644 --- a/make/common/TestFilesCompilation.gmk +++ b/make/common/TestFilesCompilation.gmk @@ -31,7 +31,7 @@ ifeq (,$(_MAKEBASE_GMK)) endif -include NativeCompilation.gmk +include JdkNativeCompilation.gmk # Setup make rules for creating a set of native test files (libraries or # executables). This will locate native files matching a certain pattern, @@ -56,27 +56,20 @@ define SetupTestFilesCompilationBody $$(error There are duplicate test file names for $1: $$($1_DUPLICATED_NAMES)) endif - # Always include common test functionality - TEST_CFLAGS := -I$(TOPDIR)/test/lib/native - # The list to depend on starts out empty $1 := ifeq ($$($1_TYPE), LIBRARY) $1_PREFIX = lib $1_OUTPUT_SUBDIR := lib - $1_BASE_CFLAGS := $(CFLAGS_JDKLIB) $$(TEST_CFLAGS) - $1_BASE_CXXFLAGS := $(CXXFLAGS_JDKLIB) $$(TEST_CFLAGS) - $1_LDFLAGS := $(LDFLAGS_JDKLIB) $$(call SET_SHARED_LIBRARY_ORIGIN) $1_COMPILATION_TYPE := LIBRARY $1_LOG_TYPE := library else ifeq ($$($1_TYPE), PROGRAM) $1_PREFIX = exe $1_OUTPUT_SUBDIR := bin - $1_BASE_CFLAGS := $(CFLAGS_JDKEXE) $$(TEST_CFLAGS) - $1_BASE_CXXFLAGS := $(CXXFLAGS_JDKEXE) $$(TEST_CFLAGS) - $1_LDFLAGS := $(LDFLAGS_JDKEXE) $(LDFLAGS_TESTEXE) $1_COMPILATION_TYPE := EXECUTABLE $1_LOG_TYPE := executable + $1_LD_SET_ORIGIN := false + $1_LDFLAGS := $(LDFLAGS_TESTEXE) else $$(error Unknown type: $$($1_TYPE)) endif @@ -99,24 +92,30 @@ define SetupTestFilesCompilationBody $1_COPY_DEBUG_SYMBOLS := true endif + # Always include common test functionality + TEST_CFLAGS := -I$(TOPDIR)/test/lib/native + # Setup a compilation for each and every one of them $$(foreach file, $$($1_FILTERED_FILE_LIST),\ $$(eval name := $$(strip $$(basename $$(notdir $$(file))))) \ $$(eval unprefixed_name := $$(patsubst $$($1_PREFIX)%, %, $$(name))) \ - $$(eval $$(call SetupNativeCompilation, BUILD_TEST_$$(name), \ + $$(eval $$(call SetupJdkNativeCompilation, BUILD_TEST_$$(name), \ NAME := $$(unprefixed_name), \ TYPE := $$($1_COMPILATION_TYPE), \ LINK_TYPE := $(if $$(filter %.cpp, $$(file)), C++, C), \ EXTRA_FILES := $$(file) $$($1_EXTRA_FILES), \ OBJECT_DIR := $$($1_OUTPUT_DIR)/support/$$(name), \ OUTPUT_DIR := $$($1_OUTPUT_DIR)/$$($1_OUTPUT_SUBDIR), \ - CFLAGS := $$($1_BASE_CFLAGS) $$($1_CFLAGS) $$($1_CFLAGS_$$(name)), \ - CXXFLAGS := $$($1_BASE_CXXFLAGS) $$($1_CFLAGS) $$($1_CFLAGS_$$(name)), \ + CFLAGS := $$(TEST_CFLAGS) $$($1_CFLAGS) $$($1_CFLAGS_$$(name)), \ + CXXFLAGS := $$(TEST_CFLAGS) $$($1_CFLAGS) $$($1_CFLAGS_$$(name)), \ + LD_SET_ORIGIN := $$($1_LD_SET_ORIGIN), \ LDFLAGS := $$($1_LDFLAGS) $$($1_LDFLAGS_$$(name)), \ DISABLED_WARNINGS_gcc := format undef unused-function unused-value, \ DISABLED_WARNINGS_clang := undef format-nonliteral \ missing-field-initializers sometimes-uninitialized, \ + DEFAULT_LIBCXX := false, \ LIBS := $$($1_LIBS_$$(name)), \ + DEFAULT_VERSIONINFO_RESOURCE := false, \ OPTIMIZATION := $$(if $$($1_OPTIMIZATION_$$(name)),$$($1_OPTIMIZATION_$$(name)),LOW), \ COPY_DEBUG_SYMBOLS := $$($1_COPY_DEBUG_SYMBOLS), \ STRIP_SYMBOLS := $$(if $$($1_STRIP_SYMBOLS_$$(name)),$$($1_STRIP_SYMBOLS_$$(name)),false), \ @@ -129,7 +128,7 @@ define SetupTestFilesCompilationBody # Setup rule for printing a summary of all the tests being compiled. On Warn # log level, this replaces the individual build info logging done by - # SetupNativeCompilation. + # SetupJdkNativeCompilation. $$($1_BUILD_INFO): $$($1_BUILD_INFO_DEPS) $$(call LogWarn, $$(strip Creating $$(words $$(filter-out %.vardeps, $$?)) \ test $$($1_LOG_TYPE) file(s) for $1)) diff --git a/make/common/modules/LauncherCommon.gmk b/make/common/modules/LauncherCommon.gmk index 3bc5eb4eb83..df8b4c36ffe 100644 --- a/make/common/modules/LauncherCommon.gmk +++ b/make/common/modules/LauncherCommon.gmk @@ -134,6 +134,10 @@ define SetupBuildLauncherBody $1_EXTRA_FILES += $(TOPDIR)/make/data/lsan/lsan_default_options.c endif + ############################################################################## + ## Build launcher "$1" + ############################################################################## + $$(eval $$(call SetupJdkExecutable, BUILD_LAUNCHER_$1, \ NAME := $1, \ EXTRA_FILES := $$($1_EXTRA_FILES), \ diff --git a/make/hotspot/gensrc/GenerateSources.gmk b/make/hotspot/gensrc/GenerateSources.gmk index c92408b7d54..48fe7e25507 100644 --- a/make/hotspot/gensrc/GenerateSources.gmk +++ b/make/hotspot/gensrc/GenerateSources.gmk @@ -1,5 +1,5 @@ # -# Copyright (c) 2013, 2020, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2013, 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,7 @@ include $(SPEC) include MakeBase.gmk include Execute.gmk include JavaCompilation.gmk -include NativeCompilation.gmk +include JdkNativeCompilation.gmk include TextFileProcessing.gmk include HotspotCommon.gmk diff --git a/make/hotspot/gensrc/GensrcAdlc.gmk b/make/hotspot/gensrc/GensrcAdlc.gmk index f9e09706141..4c37fd1ebe6 100644 --- a/make/hotspot/gensrc/GensrcAdlc.gmk +++ b/make/hotspot/gensrc/GensrcAdlc.gmk @@ -68,16 +68,22 @@ ifeq ($(call check-jvm-feature, compiler2), true) ADLC_LDFLAGS += $(UBSAN_LDFLAGS) endif - $(eval $(call SetupNativeCompilation, BUILD_ADLC, \ + ############################################################################## + ## Build adlc + ############################################################################## + + $(eval $(call SetupJdkExecutable, BUILD_ADLC, \ NAME := adlc, \ - TYPE := EXECUTABLE, \ TARGET_TYPE := BUILD, \ LINK_TYPE := C++, \ SRC := $(TOPDIR)/src/hotspot/share/adlc, \ EXTRA_FILES := $(TOPDIR)/src/hotspot/share/opto/opcodes.cpp, \ + DEFAULT_CFLAGS := false, \ CFLAGS := $(ADLC_CFLAGS) $(ADLC_CFLAGS_WARNINGS), \ + DEFAULT_LDFLAGS := false, \ LDFLAGS := $(ADLC_LDFLAGS), \ LIBS := $(ADLC_LIBS), \ + DEFAULT_VERSIONINFO_RESOURCE := false, \ OBJECT_DIR := $(JVM_VARIANT_OUTPUTDIR)/tools/adlc/objs, \ OUTPUT_DIR := $(JVM_VARIANT_OUTPUTDIR)/tools/adlc, \ DEBUG_SYMBOLS := false, \ diff --git a/make/hotspot/lib/CompileGtest.gmk b/make/hotspot/lib/CompileGtest.gmk index 67badb71660..58e6f1bb2ef 100644 --- a/make/hotspot/lib/CompileGtest.gmk +++ b/make/hotspot/lib/CompileGtest.gmk @@ -44,7 +44,8 @@ else endif ################################################################################ - +## Build libgtest +################################################################################ $(eval $(call SetupJdkLibrary, BUILD_GTEST_LIBGTEST, \ NAME := gtest, \ @@ -75,8 +76,10 @@ $(eval $(call SetupJdkLibrary, BUILD_GTEST_LIBGTEST, \ TARGETS += $(BUILD_GTEST_LIBGTEST) ################################################################################ -# Additional disabled warnings are due to code in the test source. +## Build libjvm (for gtest) +################################################################################ +# Additional disabled warnings are due to code in the test source. $(eval $(call SetupJdkLibrary, BUILD_GTEST_LIBJVM, \ NAME := jvm, \ LINK_TYPE := C++, \ @@ -128,6 +131,8 @@ endif TARGETS += $(BUILD_GTEST_LIBJVM) +################################################################################ +## Build gtestLauncher ################################################################################ $(eval $(call SetupJdkExecutable, BUILD_GTEST_LAUNCHER, \ diff --git a/make/hotspot/lib/CompileJvm.gmk b/make/hotspot/lib/CompileJvm.gmk index eebbd65f155..e887885db2c 100644 --- a/make/hotspot/lib/CompileJvm.gmk +++ b/make/hotspot/lib/CompileJvm.gmk @@ -128,7 +128,7 @@ endif JVM_OPTIMIZATION ?= HIGHEST_JVM # Need to set JVM_STRIPFLAGS to the default value from SPEC since the STRIPFLAGS -# parameter to SetupNativeCompilation allows an empty value to override the +# parameter to SetupJdkLibrary allows an empty value to override the # default. JVM_STRIPFLAGS ?= $(STRIPFLAGS) @@ -159,7 +159,8 @@ ifeq ($(call isTargetOs, linux), true) endif ################################################################################ -# Now set up the actual compilation of the main hotspot native library +## Build libjvm +################################################################################ $(eval $(call SetupJdkLibrary, BUILD_LIBJVM, \ NAME := jvm, \ diff --git a/make/hotspot/lib/JvmOverrideFiles.gmk b/make/hotspot/lib/JvmOverrideFiles.gmk index ffb98b9bb9a..92e0f9e861e 100644 --- a/make/hotspot/lib/JvmOverrideFiles.gmk +++ b/make/hotspot/lib/JvmOverrideFiles.gmk @@ -1,5 +1,5 @@ # -# Copyright (c) 2013, 2023, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2013, 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 @@ -73,7 +73,7 @@ ifeq ($(call isTargetOs, linux), true) NONPIC_SRC := $(filter $(NONPIC_FILTER), $(ALL_SRC)) globals.cpp location.cpp # Declare variables for each source file that needs the pic flag like this: # BUILD_JVM__CXXFLAGS := -fno-PIC - # This will get implicitly picked up by SetupNativeCompilation below. + # This will get implicitly picked up by SetupJdkLibrary below. $(foreach s, $(NONPIC_SRC), $(eval BUILD_LIBJVM_$(notdir $s)_CXXFLAGS := -fno-PIC)) endif diff --git a/make/jdk/src/classes/build/tools/cldrconverter/CLDRConverter.java b/make/jdk/src/classes/build/tools/cldrconverter/CLDRConverter.java index 2fb45bec1d3..8d39ef4c1d5 100644 --- a/make/jdk/src/classes/build/tools/cldrconverter/CLDRConverter.java +++ b/make/jdk/src/classes/build/tools/cldrconverter/CLDRConverter.java @@ -97,7 +97,7 @@ public class CLDRConverter { private static final String DST = "dst"; private static final String NO_SUBST = "-"; - private static SupplementDataParseHandler handlerSuppl; + private static SupplementalDataParseHandler handlerSuppl; private static LikelySubtagsParseHandler handlerLikelySubtags; private static WinZonesParseHandler handlerWinZones; static PluralsParseHandler handlerPlurals; @@ -471,7 +471,7 @@ private static void parseSupplemental() throws Exception { // SupplementalData file also provides the "parent" locales which // are othrwise not to be fallen back. Process them here as well. // - handlerSuppl = new SupplementDataParseHandler(); + handlerSuppl = new SupplementalDataParseHandler(); parseLDMLFile(new File(SPPL_SOURCE_FILE), handlerSuppl); Map parentData = handlerSuppl.getData("root"); parentData.keySet().stream() diff --git a/make/jdk/src/classes/build/tools/cldrconverter/SupplementDataParseHandler.java b/make/jdk/src/classes/build/tools/cldrconverter/SupplementalDataParseHandler.java similarity index 88% rename from make/jdk/src/classes/build/tools/cldrconverter/SupplementDataParseHandler.java rename to make/jdk/src/classes/build/tools/cldrconverter/SupplementalDataParseHandler.java index a2b5bd39ae2..f4d20160ffb 100644 --- a/make/jdk/src/classes/build/tools/cldrconverter/SupplementDataParseHandler.java +++ b/make/jdk/src/classes/build/tools/cldrconverter/SupplementalDataParseHandler.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 @@ -38,11 +38,11 @@ import org.xml.sax.SAXException; /** - * Handles parsing of files in Locale Data Markup Language for SupplementData.xml + * Handles parsing of files in Locale Data Markup Language for supplementalData.xml * and produces a map that uses the keys and values of JRE locale data. */ -class SupplementDataParseHandler extends AbstractLDMLHandler { +class SupplementalDataParseHandler extends AbstractLDMLHandler { //UNM49 region and composition code used in supplementalData.xml private static final String WORLD = "001"; @@ -73,7 +73,7 @@ class SupplementDataParseHandler extends AbstractLDMLHandler { // "component" specific to this parent locale chain private String currentParentLocaleComponent; - SupplementDataParseHandler() { + SupplementalDataParseHandler() { firstDayMap = new HashMap<>(); minDaysMap = new HashMap<>(); parentLocalesMap = new HashMap<>(); @@ -132,32 +132,15 @@ public void startElement(String uri, String localName, String qName, Attributes switch (qName) { case "firstDay": if (!isIgnored(attributes)) { - String fd; - - switch (attributes.getValue("day")) { - case "sun": - fd = "1"; - break; - default: - case "mon": - fd = "2"; - break; - case "tue": - fd = "3"; - break; - case "wed": - fd = "4"; - break; - case "thu": - fd = "5"; - break; - case "fri": - fd = "6"; - break; - case "sat": - fd = "7"; - break; - } + String fd = switch (attributes.getValue("day")) { + case "sun" -> "1"; + case "tue" -> "3"; + case "wed" -> "4"; + case "thu" -> "5"; + case "fri" -> "6"; + case "sat" -> "7"; + default -> "2"; // Mon + }; firstDayMap.put(attributes.getValue("territories"), fd); } break; diff --git a/make/jdk/src/classes/build/tools/cldrconverter/SupplementalMetadataParseHandler.java b/make/jdk/src/classes/build/tools/cldrconverter/SupplementalMetadataParseHandler.java index 43016f424c6..101ee81b256 100644 --- a/make/jdk/src/classes/build/tools/cldrconverter/SupplementalMetadataParseHandler.java +++ b/make/jdk/src/classes/build/tools/cldrconverter/SupplementalMetadataParseHandler.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 @@ -36,7 +36,7 @@ /** * Handles parsing of files in Locale Data Markup Language for - * SupplementalMetadata.xml + * supplementalMetadata.xml */ class SupplementalMetadataParseHandler extends AbstractLDMLHandler { diff --git a/make/langtools/tools/javacserver/server/CompilerThreadPool.java b/make/langtools/tools/javacserver/server/CompilerThreadPool.java index 3f3dea52c84..0a40a27ad87 100644 --- a/make/langtools/tools/javacserver/server/CompilerThreadPool.java +++ b/make/langtools/tools/javacserver/server/CompilerThreadPool.java @@ -43,14 +43,8 @@ public CompilerThreadPool() { this.pool = Executors.newFixedThreadPool(POOLSIZE); } - public int dispatchCompilation(String[] args) { - Log log = Log.get(); - try { - return pool.submit(() -> Server.runCompiler(log, args)).get(); - } catch (Exception e) { - e.printStackTrace(); - throw new RuntimeException("Error during compile", e); - } + public void execute(Runnable runnable) { + this.pool.execute(runnable); } public void shutdown() { diff --git a/make/langtools/tools/javacserver/server/Server.java b/make/langtools/tools/javacserver/server/Server.java index b213c992667..8d8bac76ad7 100644 --- a/make/langtools/tools/javacserver/server/Server.java +++ b/make/langtools/tools/javacserver/server/Server.java @@ -168,10 +168,8 @@ private boolean start() throws IOException, InterruptedException { do { try { Socket socket = serverSocket.accept(); - // Handle each incoming request in a separate thread. This is just for socket communication, - // the actual compilation will be done by the threadpool. - Thread requestHandler = new Thread(() -> handleRequest(socket)); - requestHandler.start(); + // Handle each incoming request in a threapool thread + compilerThreadPool.execute(() -> handleRequest(socket)); } catch (SocketException se) { // Caused by serverSocket.close() and indicates shutdown } @@ -206,9 +204,9 @@ private void handleRequest(Socket socket) { // If there has been any internal errors, notify client checkInternalErrorLog(); - // Perform compilation. This will call runCompiler() on a - // thread in the thread pool - int exitCode = compilerThreadPool.dispatchCompilation(args); + // Perform compilation + int exitCode = runCompiler(args); + Protocol.sendExitCode(out, exitCode); // Check for internal errors again. @@ -220,15 +218,14 @@ private void handleRequest(Socket socket) { // Not much to be done at this point. The client side request // code will most likely throw an IOException and the // compilation will fail. + ex.printStackTrace(); Log.error(ex); } finally { Log.setLogForCurrentThread(null); } } - public static int runCompiler(Log log, String[] args) { - Log.setLogForCurrentThread(log); - + public static int runCompiler(String[] args) { // Direct logging to our byte array stream. StringWriter strWriter = new StringWriter(); PrintWriter printWriter = new PrintWriter(strWriter); diff --git a/make/modules/java.base/Lib.gmk b/make/modules/java.base/Lib.gmk index 6af339a3dd8..bd0c8cc666b 100644 --- a/make/modules/java.base/Lib.gmk +++ b/make/modules/java.base/Lib.gmk @@ -99,21 +99,21 @@ ifeq ($(call isTargetOs, macosx), true) ## Build libosxsecurity ############################################################################## - $(eval $(call SetupJdkLibrary, BUILD_LIBOSXSECURITY, \ - NAME := osxsecurity, \ - OPTIMIZATION := LOW, \ - DISABLED_WARNINGS_clang_KeystoreImpl.m := deprecated-declarations, \ - LDFLAGS := -L$(SUPPORT_OUTPUTDIR)/modules_libs/java.base,\ - JDK_LIBS := $(JDKLIB_LIBS), \ - LIBS_macosx := -lobjc \ - -framework CoreServices \ - -framework Foundation \ - -framework Security, \ - )) - - $(BUILD_LIBOSXSECURITY): $(BUILD_LIBJAVA) - - TARGETS += $(BUILD_LIBOSXSECURITY) + $(eval $(call SetupJdkLibrary, BUILD_LIBOSXSECURITY, \ + NAME := osxsecurity, \ + OPTIMIZATION := LOW, \ + DISABLED_WARNINGS_clang_KeystoreImpl.m := deprecated-declarations, \ + LDFLAGS := -L$(SUPPORT_OUTPUTDIR)/modules_libs/java.base,\ + JDK_LIBS := $(JDKLIB_LIBS), \ + LIBS_macosx := -lobjc \ + -framework CoreServices \ + -framework Foundation \ + -framework Security, \ + )) + + $(BUILD_LIBOSXSECURITY): $(BUILD_LIBJAVA) + + TARGETS += $(BUILD_LIBOSXSECURITY) endif ifeq ($(call isTargetOsType, unix)+$(STATIC_BUILD), true+false) diff --git a/make/modules/jdk.sctp/Lib.gmk b/make/modules/jdk.sctp/Lib.gmk index ab68fe93bb0..57b52b3cb11 100644 --- a/make/modules/jdk.sctp/Lib.gmk +++ b/make/modules/jdk.sctp/Lib.gmk @@ -25,11 +25,11 @@ include LibCommon.gmk -################################################################################ -## Build libsctp -################################################################################ - ifeq ($(call isTargetOs, linux), true) + ############################################################################## + ## Build libsctp + ############################################################################## + $(eval $(call SetupJdkLibrary, BUILD_LIBSCTP, \ NAME := sctp, \ OPTIMIZATION := LOW, \ diff --git a/make/test/BuildFailureHandler.gmk b/make/test/BuildFailureHandler.gmk index 78eb3692e8a..6c9876f80c7 100644 --- a/make/test/BuildFailureHandler.gmk +++ b/make/test/BuildFailureHandler.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 @@ -28,7 +28,6 @@ default: build include $(SPEC) include MakeBase.gmk include JavaCompilation.gmk -include NativeCompilation.gmk TARGETS := diff --git a/make/test/JtregNativeHotspot.gmk b/make/test/JtregNativeHotspot.gmk index ca46d0af591..eb45601748d 100644 --- a/make/test/JtregNativeHotspot.gmk +++ b/make/test/JtregNativeHotspot.gmk @@ -140,9 +140,6 @@ BUILD_HOTSPOT_JTREG_LIBRARIES_OPTIMIZATION_libNoFramePointer := HIGH JVMTI_COMMON_INCLUDES=-I$(TOPDIR)/test/lib/jdk/test/lib/jvmti -BUILD_HOTSPOT_JTREG_LIBRARIES_CFLAGS := -D__STDC_FORMAT_MACROS -D__STDC_LIMIT_MACROS -D__STDC_CONSTANT_MACROS $(JVMTI_COMMON_INCLUDES) -BUILD_HOTSPOT_JTREG_EXECUTABLES_CFLAGS := -D__STDC_FORMAT_MACROS -D__STDC_LIMIT_MACROS -D__STDC_CONSTANT_MACROS $(JVMTI_COMMON_INCLUDES) - BUILD_HOTSPOT_JTREG_LIBRARIES_CFLAGS_libProcessUtils := $(VM_SHARE_INCLUDES) BUILD_HOTSPOT_JTREG_LIBRARIES_CFLAGS_libThreadController := $(NSK_MONITORING_INCLUDES) @@ -1530,6 +1527,10 @@ ifeq ($(LSAN_ENABLED), true) BUILD_HOTSPOT_JTREG_EXTRA_FILES += $(TOPDIR)/make/data/lsan/lsan_default_options.c endif +# These apply to all tests +BUILD_HOTSPOT_JTREG_LIBRARIES_CFLAGS := -D__STDC_FORMAT_MACROS -D__STDC_LIMIT_MACROS -D__STDC_CONSTANT_MACROS $(JVMTI_COMMON_INCLUDES) +BUILD_HOTSPOT_JTREG_EXECUTABLES_CFLAGS := -D__STDC_FORMAT_MACROS -D__STDC_LIMIT_MACROS -D__STDC_CONSTANT_MACROS $(JVMTI_COMMON_INCLUDES) + # This evaluation is expensive and should only be done if this target was # explicitly called. ifneq ($(filter build-test-hotspot-jtreg-native, $(MAKECMDGOALS)), ) diff --git a/src/demo/share/jfc/SwingSet2/resources/images/food/apple.jpeg b/src/demo/share/jfc/SwingSet2/resources/images/food/apple.jpeg deleted file mode 100644 index c847ba99f4c..00000000000 Binary files a/src/demo/share/jfc/SwingSet2/resources/images/food/apple.jpeg and /dev/null differ diff --git a/src/hotspot/cpu/aarch64/compressedKlass_aarch64.cpp b/src/hotspot/cpu/aarch64/compressedKlass_aarch64.cpp index 47b6f1f2f38..54af69ffaba 100644 --- a/src/hotspot/cpu/aarch64/compressedKlass_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/compressedKlass_aarch64.cpp @@ -57,15 +57,15 @@ static char* reserve_at_eor_compatible_address(size_t size, bool aslr) { 0x7800, 0x7c00, 0x7e00, 0x7f00, 0x7f80, 0x7fc0, 0x7fe0, 0x7ff0, 0x7ff8, 0x7ffc, 0x7ffe, 0x7fff }; - static constexpr int num_immediates = sizeof(immediates) / sizeof(immediates[0]); - const int start_index = aslr ? os::next_random((int)os::javaTimeNanos()) : 0; + static constexpr unsigned num_immediates = sizeof(immediates) / sizeof(immediates[0]); + const unsigned start_index = aslr ? os::next_random((int)os::javaTimeNanos()) : 0; constexpr int max_tries = 64; for (int ntry = 0; result == nullptr && ntry < max_tries; ntry ++) { // As in os::attempt_reserve_memory_between, we alternate between higher and lower // addresses; this maximizes the chance of early success if part of the address space // is not accessible (e.g. 39-bit address space). - const int alt_index = (ntry & 1) ? 0 : num_immediates / 2; - const int index = (start_index + ntry + alt_index) % num_immediates; + const unsigned alt_index = (ntry & 1) ? 0 : num_immediates / 2; + const unsigned index = (start_index + ntry + alt_index) % num_immediates; const uint64_t immediate = ((uint64_t)immediates[index]) << 32; assert(immediate > 0 && Assembler::operand_valid_for_logical_immediate(/*is32*/false, immediate), "Invalid immediate %d " UINT64_FORMAT, index, immediate); diff --git a/src/hotspot/cpu/aarch64/continuationEntry_aarch64.inline.hpp b/src/hotspot/cpu/aarch64/continuationEntry_aarch64.inline.hpp index c70b4fdcfcc..df4d3957239 100644 --- a/src/hotspot/cpu/aarch64/continuationEntry_aarch64.inline.hpp +++ b/src/hotspot/cpu/aarch64/continuationEntry_aarch64.inline.hpp @@ -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 @@ -35,7 +35,7 @@ inline frame ContinuationEntry::to_frame() const { static CodeBlob* cb = CodeCache::find_blob_fast(entry_pc()); assert(cb != nullptr, ""); - assert(cb->as_compiled_method()->method()->is_continuation_enter_intrinsic(), ""); + assert(cb->as_nmethod()->method()->is_continuation_enter_intrinsic(), ""); return frame(entry_sp(), entry_sp(), entry_fp(), entry_pc(), cb); } diff --git a/src/hotspot/cpu/aarch64/frame_aarch64.cpp b/src/hotspot/cpu/aarch64/frame_aarch64.cpp index 8d0fa8895d1..0387f763bbd 100644 --- a/src/hotspot/cpu/aarch64/frame_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/frame_aarch64.cpp @@ -222,7 +222,7 @@ bool frame::safe_for_sender(JavaThread *thread) { return false; } - CompiledMethod* nm = sender_blob->as_compiled_method_or_null(); + nmethod* nm = sender_blob->as_nmethod_or_null(); if (nm != nullptr) { if (nm->is_deopt_mh_entry(sender_pc) || nm->is_deopt_entry(sender_pc) || nm->method()->is_method_handle_intrinsic()) { @@ -234,7 +234,7 @@ bool frame::safe_for_sender(JavaThread *thread) { // because the return address counts against the callee's frame. if (sender_blob->frame_size() <= 0) { - assert(!sender_blob->is_compiled(), "should count return address at least"); + assert(!sender_blob->is_nmethod(), "should count return address at least"); return false; } @@ -243,7 +243,7 @@ bool frame::safe_for_sender(JavaThread *thread) { // should not be anything but the call stub (already covered), the interpreter (already covered) // or an nmethod. - if (!sender_blob->is_compiled()) { + if (!sender_blob->is_nmethod()) { return false; } @@ -297,7 +297,7 @@ void frame::patch_pc(Thread* thread, address pc) { DEBUG_ONLY(address old_pc = _pc;) *pc_addr = signed_pc; _pc = pc; // must be set before call to get_deopt_original_pc - address original_pc = CompiledMethod::get_deopt_original_pc(this); + address original_pc = get_deopt_original_pc(); if (original_pc != nullptr) { assert(original_pc == old_pc, "expected original PC to be stored before patching"); _deopt_state = is_deoptimized; @@ -426,7 +426,7 @@ frame frame::sender_for_upcall_stub_frame(RegisterMap* map) const { // Verifies the calculated original PC of a deoptimization PC for the // given unextended SP. #ifdef ASSERT -void frame::verify_deopt_original_pc(CompiledMethod* nm, intptr_t* unextended_sp) { +void frame::verify_deopt_original_pc(nmethod* nm, intptr_t* unextended_sp) { frame fr; // This is ugly but it's better than to change {get,set}_original_pc @@ -449,12 +449,12 @@ void frame::adjust_unextended_sp() { // returning to any of these call sites. if (_cb != nullptr) { - CompiledMethod* sender_cm = _cb->as_compiled_method_or_null(); - if (sender_cm != nullptr) { + nmethod* sender_nm = _cb->as_nmethod_or_null(); + if (sender_nm != nullptr) { // If the sender PC is a deoptimization point, get the original PC. - if (sender_cm->is_deopt_entry(_pc) || - sender_cm->is_deopt_mh_entry(_pc)) { - verify_deopt_original_pc(sender_cm, _unextended_sp); + if (sender_nm->is_deopt_entry(_pc) || + sender_nm->is_deopt_mh_entry(_pc)) { + verify_deopt_original_pc(sender_nm, _unextended_sp); } } } diff --git a/src/hotspot/cpu/aarch64/frame_aarch64.hpp b/src/hotspot/cpu/aarch64/frame_aarch64.hpp index 099dcdb4f2b..401e2c6ae97 100644 --- a/src/hotspot/cpu/aarch64/frame_aarch64.hpp +++ b/src/hotspot/cpu/aarch64/frame_aarch64.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2024, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2014, Red Hat Inc. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -153,7 +153,7 @@ #ifdef ASSERT // Used in frame::sender_for_{interpreter,compiled}_frame - static void verify_deopt_original_pc( CompiledMethod* nm, intptr_t* unextended_sp); + static void verify_deopt_original_pc(nmethod* nm, intptr_t* unextended_sp); #endif public: diff --git a/src/hotspot/cpu/aarch64/frame_aarch64.inline.hpp b/src/hotspot/cpu/aarch64/frame_aarch64.inline.hpp index d3ae7871f61..f7b33931f8d 100644 --- a/src/hotspot/cpu/aarch64/frame_aarch64.inline.hpp +++ b/src/hotspot/cpu/aarch64/frame_aarch64.inline.hpp @@ -71,11 +71,11 @@ inline void frame::init(intptr_t* sp, intptr_t* fp, address pc) { inline void frame::setup(address pc) { adjust_unextended_sp(); - address original_pc = CompiledMethod::get_deopt_original_pc(this); + address original_pc = get_deopt_original_pc(); if (original_pc != nullptr) { _pc = original_pc; _deopt_state = is_deoptimized; - assert(_cb == nullptr || _cb->as_compiled_method()->insts_contains_inclusive(_pc), + assert(_cb == nullptr || _cb->as_nmethod()->insts_contains_inclusive(_pc), "original PC must be in the main code section of the compiled method (or must be immediately following it)"); } else { if (_cb == SharedRuntime::deopt_blob()) { @@ -178,7 +178,7 @@ inline frame::frame(intptr_t* sp, intptr_t* fp) { _cb = CodeCache::find_blob(_pc); adjust_unextended_sp(); - address original_pc = CompiledMethod::get_deopt_original_pc(this); + address original_pc = get_deopt_original_pc(); if (original_pc != nullptr) { _pc = original_pc; _deopt_state = is_deoptimized; @@ -240,8 +240,8 @@ inline int frame::frame_size() const { } inline int frame::compiled_frame_stack_argsize() const { - assert(cb()->is_compiled(), ""); - return (cb()->as_compiled_method()->method()->num_stack_arg_slots() * VMRegImpl::stack_slot_size) >> LogBytesPerWord; + assert(cb()->is_nmethod(), ""); + return (cb()->as_nmethod()->method()->num_stack_arg_slots() * VMRegImpl::stack_slot_size) >> LogBytesPerWord; } inline void frame::interpreted_frame_oop_map(InterpreterOopMap* mask) const { @@ -417,7 +417,7 @@ inline frame frame::sender_for_compiled_frame(RegisterMap* map) const { // Tell GC to use argument oopmaps for some runtime stubs that need it. // For C1, the runtime stub might not have oop maps, so set this flag // outside of update_register_map. - if (!_cb->is_compiled()) { // compiled frames do not use callee-saved registers + if (!_cb->is_nmethod()) { // compiled frames do not use callee-saved registers map->set_include_argument_oops(_cb->caller_must_gc_arguments(map->thread())); if (oop_map() != nullptr) { _oop_map->update_register_map(this, map); diff --git a/src/hotspot/cpu/aarch64/globals_aarch64.hpp b/src/hotspot/cpu/aarch64/globals_aarch64.hpp index 760aada0270..2f83838fc0f 100644 --- a/src/hotspot/cpu/aarch64/globals_aarch64.hpp +++ b/src/hotspot/cpu/aarch64/globals_aarch64.hpp @@ -85,8 +85,6 @@ define_pd_global(intx, InlineSmallCode, 1000); \ product(bool, NearCpool, true, \ "constant pool is close to instructions") \ - product(bool, UseNeon, false, \ - "Use Neon for CRC32 computation") \ product(bool, UseCRC32, false, \ "Use CRC32 instructions for CRC32 computation") \ product(bool, UseCryptoPmullForCRC32, false, \ diff --git a/src/hotspot/cpu/aarch64/macroAssembler_aarch64.cpp b/src/hotspot/cpu/aarch64/macroAssembler_aarch64.cpp index 5dd6b534f14..0e807e8d83a 100644 --- a/src/hotspot/cpu/aarch64/macroAssembler_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/macroAssembler_aarch64.cpp @@ -867,7 +867,7 @@ static bool is_always_within_branch_range(Address entry) { // Non-compiled methods stay forever in CodeCache. // We check whether the longest possible branch is within the branch range. assert(CodeCache::find_blob(target) != nullptr && - !CodeCache::find_blob(target)->is_compiled(), + !CodeCache::find_blob(target)->is_nmethod(), "runtime call of compiled method"); const address right_longest_branch_start = CodeCache::high_bound() - NativeInstruction::instruction_size; const address left_longest_branch_start = CodeCache::low_bound(); @@ -1199,7 +1199,7 @@ void MacroAssembler::lookup_interface_method(Register recv_klass, ldrw(scan_temp, Address(recv_klass, Klass::vtable_length_offset())); - // %%% Could store the aligned, prescaled offset in the klassoop. + // Could store the aligned, prescaled offset in the klass. // lea(scan_temp, Address(recv_klass, scan_temp, times_vte_scale, vtable_base)); lea(scan_temp, Address(recv_klass, scan_temp, Address::lsl(3))); add(scan_temp, scan_temp, vtable_base); diff --git a/src/hotspot/cpu/aarch64/relocInfo_aarch64.cpp b/src/hotspot/cpu/aarch64/relocInfo_aarch64.cpp index 4b7930c94a8..5424f0d9c75 100644 --- a/src/hotspot/cpu/aarch64/relocInfo_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/relocInfo_aarch64.cpp @@ -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. * Copyright (c) 2014, Red Hat Inc. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -25,7 +25,7 @@ #include "precompiled.hpp" #include "asm/macroAssembler.hpp" -#include "code/compiledMethod.hpp" +#include "code/nmethod.hpp" #include "code/relocInfo.hpp" #include "nativeInst_aarch64.hpp" #include "oops/oop.inline.hpp" diff --git a/src/hotspot/cpu/aarch64/stackChunkFrameStream_aarch64.inline.hpp b/src/hotspot/cpu/aarch64/stackChunkFrameStream_aarch64.inline.hpp index 0305d434052..aa4eff19766 100644 --- a/src/hotspot/cpu/aarch64/stackChunkFrameStream_aarch64.inline.hpp +++ b/src/hotspot/cpu/aarch64/stackChunkFrameStream_aarch64.inline.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 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 @@ -35,7 +35,7 @@ template inline bool StackChunkFrameStream::is_in_frame(void* p0) const { assert(!is_done(), ""); intptr_t* p = (intptr_t*)p0; - int argsize = is_compiled() ? (_cb->as_compiled_method()->method()->num_stack_arg_slots() * VMRegImpl::stack_slot_size) >> LogBytesPerWord : 0; + int argsize = is_compiled() ? (_cb->as_nmethod()->method()->num_stack_arg_slots() * VMRegImpl::stack_slot_size) >> LogBytesPerWord : 0; int frame_size = _cb->frame_size() + argsize; return p == sp() - frame::sender_sp_offset || ((p - unextended_sp()) >= 0 && (p - unextended_sp()) < frame_size); } diff --git a/src/hotspot/cpu/arm/frame_arm.cpp b/src/hotspot/cpu/arm/frame_arm.cpp index d923e1f43ad..6221191e926 100644 --- a/src/hotspot/cpu/arm/frame_arm.cpp +++ b/src/hotspot/cpu/arm/frame_arm.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 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 @@ -80,7 +80,7 @@ bool frame::safe_for_sender(JavaThread *thread) { // ok. adapter blobs never have a frame complete and are never ok. if (!_cb->is_frame_complete_at(_pc)) { - if (_cb->is_compiled() || _cb->is_adapter_blob() || _cb->is_runtime_stub()) { + if (_cb->is_nmethod() || _cb->is_adapter_blob() || _cb->is_runtime_stub()) { return false; } } @@ -179,7 +179,7 @@ bool frame::safe_for_sender(JavaThread *thread) { // because the return address counts against the callee's frame. if (sender_blob->frame_size() <= 0) { - assert(!sender_blob->is_compiled(), "should count return address at least"); + assert(!sender_blob->is_nmethod(), "should count return address at least"); return false; } @@ -188,7 +188,7 @@ bool frame::safe_for_sender(JavaThread *thread) { // should not be anything but the call stub (already covered), the interpreter (already covered) // or an nmethod. - if (!sender_blob->is_compiled()) { + if (!sender_blob->is_nmethod()) { return false; } @@ -229,7 +229,7 @@ void frame::patch_pc(Thread* thread, address pc) { DEBUG_ONLY(address old_pc = _pc;) *pc_addr = pc; _pc = pc; // must be set before call to get_deopt_original_pc - address original_pc = CompiledMethod::get_deopt_original_pc(this); + address original_pc = get_deopt_original_pc(); if (original_pc != nullptr) { assert(original_pc == old_pc, "expected original PC to be stored before patching"); _deopt_state = is_deoptimized; @@ -332,7 +332,7 @@ bool frame::upcall_stub_frame_is_first() const { // given unextended SP. The unextended SP might also be the saved SP // for MethodHandle call sites. #ifdef ASSERT -void frame::verify_deopt_original_pc(CompiledMethod* nm, intptr_t* unextended_sp, bool is_method_handle_return) { +void frame::verify_deopt_original_pc(nmethod* nm, intptr_t* unextended_sp, bool is_method_handle_return) { frame fr; // This is ugly but it's better than to change {get,set}_original_pc @@ -357,19 +357,19 @@ void frame::adjust_unextended_sp() { // simplest way to tell whether we are returning to such a call site // is as follows: - CompiledMethod* sender_cm = (_cb == nullptr) ? nullptr : _cb->as_compiled_method_or_null(); - if (sender_cm != nullptr) { + nmethod* sender_nm = (_cb == nullptr) ? nullptr : _cb->as_nmethod_or_null(); + if (sender_nm != nullptr) { // If the sender PC is a deoptimization point, get the original // PC. For MethodHandle call site the unextended_sp is stored in // saved_fp. - if (sender_cm->is_deopt_mh_entry(_pc)) { - DEBUG_ONLY(verify_deopt_mh_original_pc(sender_cm, _fp)); + if (sender_nm->is_deopt_mh_entry(_pc)) { + DEBUG_ONLY(verify_deopt_mh_original_pc(sender_nm, _fp)); _unextended_sp = _fp; } - else if (sender_cm->is_deopt_entry(_pc)) { - DEBUG_ONLY(verify_deopt_original_pc(sender_cm, _unextended_sp)); + else if (sender_nm->is_deopt_entry(_pc)) { + DEBUG_ONLY(verify_deopt_original_pc(sender_nm, _unextended_sp)); } - else if (sender_cm->is_method_handle_return(_pc)) { + else if (sender_nm->is_method_handle_return(_pc)) { _unextended_sp = _fp; } } diff --git a/src/hotspot/cpu/arm/frame_arm.hpp b/src/hotspot/cpu/arm/frame_arm.hpp index 56f8fc9932e..dee005b8d75 100644 --- a/src/hotspot/cpu/arm/frame_arm.hpp +++ b/src/hotspot/cpu/arm/frame_arm.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 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 @@ -93,8 +93,8 @@ #ifdef ASSERT // Used in frame::sender_for_{interpreter,compiled}_frame - static void verify_deopt_original_pc( CompiledMethod* nm, intptr_t* unextended_sp, bool is_method_handle_return = false); - static void verify_deopt_mh_original_pc(CompiledMethod* nm, intptr_t* unextended_sp) { + static void verify_deopt_original_pc(nmethod* nm, intptr_t* unextended_sp, bool is_method_handle_return = false); + static void verify_deopt_mh_original_pc(nmethod* nm, intptr_t* unextended_sp) { verify_deopt_original_pc(nm, unextended_sp, true); } #endif diff --git a/src/hotspot/cpu/arm/frame_arm.inline.hpp b/src/hotspot/cpu/arm/frame_arm.inline.hpp index 8a08c0d0e9c..801b2f6177c 100644 --- a/src/hotspot/cpu/arm/frame_arm.inline.hpp +++ b/src/hotspot/cpu/arm/frame_arm.inline.hpp @@ -58,10 +58,10 @@ inline void frame::init(intptr_t* sp, intptr_t* unextended_sp, intptr_t* fp, add adjust_unextended_sp(); DEBUG_ONLY(_frame_index = -1;) - address original_pc = CompiledMethod::get_deopt_original_pc(this); + address original_pc = get_deopt_original_pc(); if (original_pc != nullptr) { _pc = original_pc; - assert(_cb->as_compiled_method()->insts_contains_inclusive(_pc), + assert(_cb->as_nmethod()->insts_contains_inclusive(_pc), "original PC must be in the main code section of the the compiled method (or must be immediately following it)"); _deopt_state = is_deoptimized; } else { diff --git a/src/hotspot/cpu/ppc/continuationEntry_ppc.inline.hpp b/src/hotspot/cpu/ppc/continuationEntry_ppc.inline.hpp index 1d2749724c5..4af637b2988 100644 --- a/src/hotspot/cpu/ppc/continuationEntry_ppc.inline.hpp +++ b/src/hotspot/cpu/ppc/continuationEntry_ppc.inline.hpp @@ -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 @@ -35,7 +35,7 @@ inline frame ContinuationEntry::to_frame() const { static CodeBlob* cb = CodeCache::find_blob_fast(entry_pc()); assert(cb != nullptr, ""); - assert(cb->as_compiled_method()->method()->is_continuation_enter_intrinsic(), ""); + assert(cb->as_nmethod()->method()->is_continuation_enter_intrinsic(), ""); return frame(entry_sp(), entry_pc(), entry_sp(), entry_fp(), cb); } diff --git a/src/hotspot/cpu/ppc/frame_ppc.cpp b/src/hotspot/cpu/ppc/frame_ppc.cpp index b63789f320d..4c1ffeb0d76 100644 --- a/src/hotspot/cpu/ppc/frame_ppc.cpp +++ b/src/hotspot/cpu/ppc/frame_ppc.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2024, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2012, 2023 SAP SE. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -90,7 +90,7 @@ bool frame::safe_for_sender(JavaThread *thread) { // so we just assume they are OK. // Adapter blobs never have a complete frame and are never OK if (!_cb->is_frame_complete_at(_pc)) { - if (_cb->is_compiled() || _cb->is_adapter_blob() || _cb->is_runtime_stub()) { + if (_cb->is_nmethod() || _cb->is_adapter_blob() || _cb->is_runtime_stub()) { return false; } } @@ -280,7 +280,7 @@ void frame::patch_pc(Thread* thread, address pc) { DEBUG_ONLY(address old_pc = _pc;) own_abi()->lr = (uint64_t)pc; _pc = pc; // must be set before call to get_deopt_original_pc - address original_pc = CompiledMethod::get_deopt_original_pc(this); + address original_pc = get_deopt_original_pc(); if (original_pc != nullptr) { assert(original_pc == old_pc, "expected original PC to be stored before patching"); _deopt_state = is_deoptimized; @@ -288,7 +288,7 @@ void frame::patch_pc(Thread* thread, address pc) { } else { _deopt_state = not_deoptimized; } - assert(!is_compiled_frame() || !_cb->as_compiled_method()->is_deopt_entry(_pc), "must be"); + assert(!is_compiled_frame() || !_cb->as_nmethod()->is_deopt_entry(_pc), "must be"); #ifdef ASSERT { diff --git a/src/hotspot/cpu/ppc/frame_ppc.inline.hpp b/src/hotspot/cpu/ppc/frame_ppc.inline.hpp index 7b1f37a342f..9966ae3f478 100644 --- a/src/hotspot/cpu/ppc/frame_ppc.inline.hpp +++ b/src/hotspot/cpu/ppc/frame_ppc.inline.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2024, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2012, 2023 SAP SE. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -61,11 +61,11 @@ inline void frame::setup(kind knd) { } } - address original_pc = CompiledMethod::get_deopt_original_pc(this); + address original_pc = get_deopt_original_pc(); if (original_pc != nullptr) { _pc = original_pc; _deopt_state = is_deoptimized; - assert(_cb == nullptr || _cb->as_compiled_method()->insts_contains_inclusive(_pc), + assert(_cb == nullptr || _cb->as_nmethod()->insts_contains_inclusive(_pc), "original PC must be in the main code section of the compiled method (or must be immediately following it)"); } else { if (_cb == SharedRuntime::deopt_blob()) { @@ -329,7 +329,7 @@ inline frame frame::sender_for_compiled_frame(RegisterMap *map) const { // Tell GC to use argument oopmaps for some runtime stubs that need it. // For C1, the runtime stub might not have oop maps, so set this flag // outside of update_register_map. - if (!_cb->is_compiled()) { // compiled frames do not use callee-saved registers + if (!_cb->is_nmethod()) { // compiled frames do not use callee-saved registers map->set_include_argument_oops(_cb->caller_must_gc_arguments(map->thread())); if (oop_map() != nullptr) { _oop_map->update_register_map(this, map); @@ -368,8 +368,8 @@ inline void frame::set_saved_oop_result(RegisterMap* map, oop obj) { } inline int frame::compiled_frame_stack_argsize() const { - assert(cb()->is_compiled(), ""); - return (cb()->as_compiled_method()->method()->num_stack_arg_slots() * VMRegImpl::stack_slot_size) >> LogBytesPerWord; + assert(cb()->is_nmethod(), ""); + return (cb()->as_nmethod()->method()->num_stack_arg_slots() * VMRegImpl::stack_slot_size) >> LogBytesPerWord; } inline void frame::interpreted_frame_oop_map(InterpreterOopMap* mask) const { diff --git a/src/hotspot/cpu/ppc/macroAssembler_ppc.cpp b/src/hotspot/cpu/ppc/macroAssembler_ppc.cpp index b7b5936a58d..701cd5cf637 100644 --- a/src/hotspot/cpu/ppc/macroAssembler_ppc.cpp +++ b/src/hotspot/cpu/ppc/macroAssembler_ppc.cpp @@ -1879,7 +1879,7 @@ void MacroAssembler::lookup_interface_method(Register recv_klass, int log_vte_size= exact_log2(vtableEntry::size_in_bytes()); lwz(scan_temp, in_bytes(Klass::vtable_length_offset()), recv_klass); - // %%% We should store the aligned, prescaled offset in the klassoop. + // We should store the aligned, prescaled offset in the klass. // Then the next several instructions would fold away. sldi(scan_temp, scan_temp, log_vte_size); @@ -2010,7 +2010,7 @@ void MacroAssembler::check_klass_subtype_fast_path(Register sub_klass, // super_check_offset is register. assert_different_registers(sub_klass, super_klass, cached_super, super_check_offset.as_register()); } - // The loaded value is the offset from KlassOopDesc. + // The loaded value is the offset from Klass. ld(cached_super, super_check_offset, sub_klass); cmpd(CCR0, cached_super, super_klass); diff --git a/src/hotspot/cpu/ppc/nativeInst_ppc.cpp b/src/hotspot/cpu/ppc/nativeInst_ppc.cpp index e1a41a17d93..9520f6a94f2 100644 --- a/src/hotspot/cpu/ppc/nativeInst_ppc.cpp +++ b/src/hotspot/cpu/ppc/nativeInst_ppc.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. * Copyright (c) 2012, 2020 SAP SE. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -460,7 +460,7 @@ void NativeDeoptInstruction::verify() { bool NativeDeoptInstruction::is_deopt_at(address code_pos) { if (!Assembler::is_illtrap(code_pos)) return false; CodeBlob* cb = CodeCache::find_blob(code_pos); - if (cb == nullptr || !cb->is_compiled()) return false; + if (cb == nullptr || !cb->is_nmethod()) return false; nmethod *nm = (nmethod *)cb; // see NativeInstruction::is_sigill_not_entrant_at() return nm->verified_entry_point() != code_pos; diff --git a/src/hotspot/cpu/ppc/stackChunkFrameStream_ppc.inline.hpp b/src/hotspot/cpu/ppc/stackChunkFrameStream_ppc.inline.hpp index f8d60ed9f93..2fb15d60c8f 100644 --- a/src/hotspot/cpu/ppc/stackChunkFrameStream_ppc.inline.hpp +++ b/src/hotspot/cpu/ppc/stackChunkFrameStream_ppc.inline.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 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 @@ -35,7 +35,7 @@ inline bool StackChunkFrameStream::is_in_frame(void* p0) const { assert(!is_done(), ""); assert(is_compiled(), ""); intptr_t* p = (intptr_t*)p0; - int argsize = (_cb->as_compiled_method()->method()->num_stack_arg_slots() * VMRegImpl::stack_slot_size) >> LogBytesPerWord; + int argsize = (_cb->as_nmethod()->method()->num_stack_arg_slots() * VMRegImpl::stack_slot_size) >> LogBytesPerWord; int frame_size = _cb->frame_size() + (argsize > 0 ? argsize + frame::metadata_words_at_top : 0); return (p - unextended_sp()) >= 0 && (p - unextended_sp()) < frame_size; } diff --git a/src/hotspot/cpu/riscv/continuationEntry_riscv.inline.hpp b/src/hotspot/cpu/riscv/continuationEntry_riscv.inline.hpp index e53f3681144..5173316c704 100644 --- a/src/hotspot/cpu/riscv/continuationEntry_riscv.inline.hpp +++ b/src/hotspot/cpu/riscv/continuationEntry_riscv.inline.hpp @@ -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 @@ -35,7 +35,7 @@ inline frame ContinuationEntry::to_frame() const { static CodeBlob* cb = CodeCache::find_blob_fast(entry_pc()); assert(cb != nullptr, ""); - assert(cb->as_compiled_method()->method()->is_continuation_enter_intrinsic(), ""); + assert(cb->as_nmethod()->method()->is_continuation_enter_intrinsic(), ""); return frame(entry_sp(), entry_sp(), entry_fp(), entry_pc(), cb); } diff --git a/src/hotspot/cpu/riscv/frame_riscv.cpp b/src/hotspot/cpu/riscv/frame_riscv.cpp index 194342b6d7d..32825a02c5e 100644 --- a/src/hotspot/cpu/riscv/frame_riscv.cpp +++ b/src/hotspot/cpu/riscv/frame_riscv.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. * Copyright (c) 2014, 2020, Red Hat Inc. All rights reserved. * Copyright (c) 2020, 2023, Huawei Technologies Co., Ltd. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. @@ -211,7 +211,7 @@ bool frame::safe_for_sender(JavaThread *thread) { return thread->is_in_stack_range_excl(jcw, (address)sender.fp()); } - CompiledMethod* nm = sender_blob->as_compiled_method_or_null(); + nmethod* nm = sender_blob->as_nmethod_or_null(); if (nm != nullptr) { if (nm->is_deopt_mh_entry(sender_pc) || nm->is_deopt_entry(sender_pc) || nm->method()->is_method_handle_intrinsic()) { @@ -222,7 +222,7 @@ bool frame::safe_for_sender(JavaThread *thread) { // If the frame size is 0 something (or less) is bad because every nmethod has a non-zero frame size // because the return address counts against the callee's frame. if (sender_blob->frame_size() <= 0) { - assert(!sender_blob->is_compiled(), "should count return address at least"); + assert(!sender_blob->is_nmethod(), "should count return address at least"); return false; } @@ -230,7 +230,7 @@ bool frame::safe_for_sender(JavaThread *thread) { // code cache (current frame) is called by an entity within the code cache that entity // should not be anything but the call stub (already covered), the interpreter (already covered) // or an nmethod. - if (!sender_blob->is_compiled()) { + if (!sender_blob->is_nmethod()) { return false; } @@ -273,7 +273,7 @@ void frame::patch_pc(Thread* thread, address pc) { DEBUG_ONLY(address old_pc = _pc;) *pc_addr = pc; _pc = pc; // must be set before call to get_deopt_original_pc - address original_pc = CompiledMethod::get_deopt_original_pc(this); + address original_pc = get_deopt_original_pc(); if (original_pc != nullptr) { assert(original_pc == old_pc, "expected original PC to be stored before patching"); _deopt_state = is_deoptimized; @@ -399,7 +399,7 @@ frame frame::sender_for_upcall_stub_frame(RegisterMap* map) const { // Verifies the calculated original PC of a deoptimization PC for the // given unextended SP. #ifdef ASSERT -void frame::verify_deopt_original_pc(CompiledMethod* nm, intptr_t* unextended_sp) { +void frame::verify_deopt_original_pc(nmethod* nm, intptr_t* unextended_sp) { frame fr; // This is ugly but it's better than to change {get,set}_original_pc @@ -423,12 +423,12 @@ void frame::adjust_unextended_sp() { // returning to any of these call sites. if (_cb != nullptr) { - CompiledMethod* sender_cm = _cb->as_compiled_method_or_null(); - if (sender_cm != nullptr) { + nmethod* sender_nm = _cb->as_nmethod_or_null(); + if (sender_nm != nullptr) { // If the sender PC is a deoptimization point, get the original PC. - if (sender_cm->is_deopt_entry(_pc) || - sender_cm->is_deopt_mh_entry(_pc)) { - verify_deopt_original_pc(sender_cm, _unextended_sp); + if (sender_nm->is_deopt_entry(_pc) || + sender_nm->is_deopt_mh_entry(_pc)) { + verify_deopt_original_pc(sender_nm, _unextended_sp); } } } diff --git a/src/hotspot/cpu/riscv/frame_riscv.hpp b/src/hotspot/cpu/riscv/frame_riscv.hpp index 0c0659d1eee..15fe0e8f1f8 100644 --- a/src/hotspot/cpu/riscv/frame_riscv.hpp +++ b/src/hotspot/cpu/riscv/frame_riscv.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2024, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2020, 2022, Huawei Technologies Co., Ltd. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -186,7 +186,7 @@ #ifdef ASSERT // Used in frame::sender_for_{interpreter,compiled}_frame - static void verify_deopt_original_pc(CompiledMethod* nm, intptr_t* unextended_sp); + static void verify_deopt_original_pc(nmethod* nm, intptr_t* unextended_sp); #endif public: diff --git a/src/hotspot/cpu/riscv/frame_riscv.inline.hpp b/src/hotspot/cpu/riscv/frame_riscv.inline.hpp index 33727a8c6d0..06c5c9f1cdb 100644 --- a/src/hotspot/cpu/riscv/frame_riscv.inline.hpp +++ b/src/hotspot/cpu/riscv/frame_riscv.inline.hpp @@ -69,11 +69,11 @@ inline void frame::init(intptr_t* ptr_sp, intptr_t* ptr_fp, address pc) { inline void frame::setup(address pc) { adjust_unextended_sp(); - address original_pc = CompiledMethod::get_deopt_original_pc(this); + address original_pc = get_deopt_original_pc(); if (original_pc != nullptr) { _pc = original_pc; _deopt_state = is_deoptimized; - assert(_cb == nullptr || _cb->as_compiled_method()->insts_contains_inclusive(_pc), + assert(_cb == nullptr || _cb->as_nmethod()->insts_contains_inclusive(_pc), "original PC must be in the main code section of the compiled method (or must be immediately following it)"); } else { if (_cb == SharedRuntime::deopt_blob()) { @@ -170,7 +170,7 @@ inline frame::frame(intptr_t* ptr_sp, intptr_t* ptr_fp) { _cb = CodeCache::find_blob(_pc); adjust_unextended_sp(); - address original_pc = CompiledMethod::get_deopt_original_pc(this); + address original_pc = get_deopt_original_pc(); if (original_pc != nullptr) { _pc = original_pc; _deopt_state = is_deoptimized; @@ -231,8 +231,8 @@ inline int frame::frame_size() const { } inline int frame::compiled_frame_stack_argsize() const { - assert(cb()->is_compiled(), ""); - return (cb()->as_compiled_method()->method()->num_stack_arg_slots() * VMRegImpl::stack_slot_size) >> LogBytesPerWord; + assert(cb()->is_nmethod(), ""); + return (cb()->as_nmethod()->method()->num_stack_arg_slots() * VMRegImpl::stack_slot_size) >> LogBytesPerWord; } inline void frame::interpreted_frame_oop_map(InterpreterOopMap* mask) const { @@ -413,7 +413,7 @@ frame frame::sender_for_compiled_frame(RegisterMap* map) const { // Tell GC to use argument oopmaps for some runtime stubs that need it. // For C1, the runtime stub might not have oop maps, so set this flag // outside of update_register_map. - if (!_cb->is_compiled()) { // compiled frames do not use callee-saved registers + if (!_cb->is_nmethod()) { // compiled frames do not use callee-saved registers map->set_include_argument_oops(_cb->caller_must_gc_arguments(map->thread())); if (oop_map() != nullptr) { _oop_map->update_register_map(this, map); diff --git a/src/hotspot/cpu/riscv/globals_riscv.hpp b/src/hotspot/cpu/riscv/globals_riscv.hpp index 8f39dea47ee..e22456cacc6 100644 --- a/src/hotspot/cpu/riscv/globals_riscv.hpp +++ b/src/hotspot/cpu/riscv/globals_riscv.hpp @@ -98,8 +98,9 @@ define_pd_global(intx, InlineSmallCode, 1000); product(bool, AvoidUnalignedAccesses, true, \ "Avoid generating unaligned memory accesses") \ product(bool, UseRVA20U64, true, "Use RVA20U64 profile") \ - product(bool, UseRVC, false, "Use RVC instructions") \ product(bool, UseRVA22U64, false, EXPERIMENTAL, "Use RVA22U64 profile") \ + product(bool, UseRVA23U64, false, EXPERIMENTAL, "Use RVA23U64 profile") \ + product(bool, UseRVC, false, "Use RVC instructions") \ product(bool, UseRVV, false, "Use RVV instructions") \ product(bool, UseZba, false, "Use Zba instructions") \ product(bool, UseZbb, false, "Use Zbb instructions") \ diff --git a/src/hotspot/cpu/riscv/macroAssembler_riscv.cpp b/src/hotspot/cpu/riscv/macroAssembler_riscv.cpp index 4459356d3b1..4704fbcaf75 100644 --- a/src/hotspot/cpu/riscv/macroAssembler_riscv.cpp +++ b/src/hotspot/cpu/riscv/macroAssembler_riscv.cpp @@ -2502,7 +2502,7 @@ void MacroAssembler::lookup_interface_method(Register recv_klass, lwu(scan_tmp, Address(recv_klass, Klass::vtable_length_offset())); - // %%% Could store the aligned, prescaled offset in the klassoop. + // Could store the aligned, prescaled offset in the klass. shadd(scan_tmp, scan_tmp, recv_klass, scan_tmp, 3); add(scan_tmp, scan_tmp, vtable_base); diff --git a/src/hotspot/cpu/riscv/stackChunkFrameStream_riscv.inline.hpp b/src/hotspot/cpu/riscv/stackChunkFrameStream_riscv.inline.hpp index d43b556dad1..7a7ee6d0040 100644 --- a/src/hotspot/cpu/riscv/stackChunkFrameStream_riscv.inline.hpp +++ b/src/hotspot/cpu/riscv/stackChunkFrameStream_riscv.inline.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 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,7 +34,7 @@ template inline bool StackChunkFrameStream::is_in_frame(void* p0) const { assert(!is_done(), ""); intptr_t* p = (intptr_t*)p0; - int argsize = is_compiled() ? (_cb->as_compiled_method()->method()->num_stack_arg_slots() * VMRegImpl::stack_slot_size) >> LogBytesPerWord : 0; + int argsize = is_compiled() ? (_cb->as_nmethod()->method()->num_stack_arg_slots() * VMRegImpl::stack_slot_size) >> LogBytesPerWord : 0; int frame_size = _cb->frame_size() + argsize; return p == sp() - 2 || ((p - unextended_sp()) >= 0 && (p - unextended_sp()) < frame_size); } diff --git a/src/hotspot/cpu/riscv/vm_version_riscv.cpp b/src/hotspot/cpu/riscv/vm_version_riscv.cpp index e1711dc5592..848ffe709d8 100644 --- a/src/hotspot/cpu/riscv/vm_version_riscv.cpp +++ b/src/hotspot/cpu/riscv/vm_version_riscv.cpp @@ -45,6 +45,18 @@ VM_Version::RVFeatureValue* VM_Version::_feature_list[] = { RV_FEATURE_FLAGS(ADD_RV_FEATURE_IN_LIST) nullptr}; +void VM_Version::useRVA20U64Profile() { + RV_USE_RVA20U64; +} + +void VM_Version::useRVA22U64Profile() { + RV_USE_RVA22U64; +} + +void VM_Version::useRVA23U64Profile() { + RV_USE_RVA23U64; +} + void VM_Version::initialize() { _supports_atomic_getset4 = true; _supports_atomic_getadd4 = true; @@ -61,44 +73,14 @@ void VM_Version::initialize() { (int)satp_mode.value())); } - // https://github.com/riscv/riscv-profiles/blob/main/profiles.adoc#rva20-profiles if (UseRVA20U64) { - if (FLAG_IS_DEFAULT(UseRVC)) { - FLAG_SET_DEFAULT(UseRVC, true); - } + useRVA20U64Profile(); } - // https://github.com/riscv/riscv-profiles/blob/main/profiles.adoc#rva22-profiles if (UseRVA22U64) { - if (FLAG_IS_DEFAULT(UseRVC)) { - FLAG_SET_DEFAULT(UseRVC, true); - } - if (FLAG_IS_DEFAULT(UseZba)) { - FLAG_SET_DEFAULT(UseZba, true); - } - if (FLAG_IS_DEFAULT(UseZbb)) { - FLAG_SET_DEFAULT(UseZbb, true); - } - if (FLAG_IS_DEFAULT(UseZbs)) { - FLAG_SET_DEFAULT(UseZbs, true); - } - if (FLAG_IS_DEFAULT(UseZfh)) { - FLAG_SET_DEFAULT(UseZfh, true); - } - if (FLAG_IS_DEFAULT(UseZic64b)) { - FLAG_SET_DEFAULT(UseZic64b, true); - } - if (FLAG_IS_DEFAULT(UseZicbom)) { - FLAG_SET_DEFAULT(UseZicbom, true); - } - if (FLAG_IS_DEFAULT(UseZicbop)) { - FLAG_SET_DEFAULT(UseZicbop, true); - } - if (FLAG_IS_DEFAULT(UseZicboz)) { - FLAG_SET_DEFAULT(UseZicboz, true); - } - if (FLAG_IS_DEFAULT(UseZihintpause)) { - FLAG_SET_DEFAULT(UseZihintpause, true); - } + useRVA22U64Profile(); + } + if (UseRVA23U64) { + useRVA23U64Profile(); } // Enable vendor specific features diff --git a/src/hotspot/cpu/riscv/vm_version_riscv.hpp b/src/hotspot/cpu/riscv/vm_version_riscv.hpp index 3619ac3e527..d26b16941db 100644 --- a/src/hotspot/cpu/riscv/vm_version_riscv.hpp +++ b/src/hotspot/cpu/riscv/vm_version_riscv.hpp @@ -61,6 +61,10 @@ class VM_Version : public Abstract_VM_Version { _enabled = true; _value = value; } + void disable_feature() { + _enabled = false; + _value = -1; + } const char* pretty() { return _pretty; } uint64_t feature_bit() { return _feature_bit; } bool feature_string() { return _feature_string; } @@ -69,16 +73,21 @@ class VM_Version : public Abstract_VM_Version { virtual void update_flag() = 0; }; - #define UPDATE_DEFAULT(flag) \ - void update_flag() { \ - assert(enabled(), "Must be."); \ - if (FLAG_IS_DEFAULT(flag)) { \ - FLAG_SET_DEFAULT(flag, true); \ - } \ - } \ + #define UPDATE_DEFAULT(flag) \ + void update_flag() { \ + assert(enabled(), "Must be."); \ + if (FLAG_IS_DEFAULT(flag)) { \ + FLAG_SET_DEFAULT(flag, true); \ + } else { \ + /* Sync CPU features with flags */ \ + if (!flag) { \ + disable_feature(); \ + } \ + } \ + } \ - #define NO_UPDATE_DEFAULT \ - void update_flag() {} \ + #define NO_UPDATE_DEFAULT \ + void update_flag() {} \ // Frozen standard extensions // I RV64I @@ -153,6 +162,7 @@ class VM_Version : public Abstract_VM_Version { decl(ext_Zihintpause , "Zihintpause" , RV_NO_FLAG_BIT, true , UPDATE_DEFAULT(UseZihintpause)) \ decl(ext_Zacas , "Zacas" , RV_NO_FLAG_BIT, true , UPDATE_DEFAULT(UseZacas)) \ decl(ext_Zvfh , "Zvfh" , RV_NO_FLAG_BIT, true , UPDATE_DEFAULT(UseZvfh)) \ + decl(ext_Zvkn , "Zvkn" , RV_NO_FLAG_BIT, true , UPDATE_DEFAULT(UseZvkn)) \ decl(mvendorid , "VendorId" , RV_NO_FLAG_BIT, false, NO_UPDATE_DEFAULT) \ decl(marchid , "ArchId" , RV_NO_FLAG_BIT, false, NO_UPDATE_DEFAULT) \ decl(mimpid , "ImpId" , RV_NO_FLAG_BIT, false, NO_UPDATE_DEFAULT) \ @@ -170,6 +180,52 @@ class VM_Version : public Abstract_VM_Version { RV_FEATURE_FLAGS(DECLARE_RV_FEATURE) #undef DECLARE_RV_FEATURE + // enable extensions based on profile, current supported profiles: + // RVA20U64 + // RVA22U64 + // RVA23U64 + // NOTE: we only enable the mandatory extensions, not optional extension. + #define RV_ENABLE_EXTENSION(UseExtension) \ + if (FLAG_IS_DEFAULT(UseExtension)) { \ + FLAG_SET_DEFAULT(UseExtension, true); \ + } \ + + // https://github.com/riscv/riscv-profiles/blob/main/profiles.adoc#rva20-profiles + #define RV_USE_RVA20U64 \ + RV_ENABLE_EXTENSION(UseRVC) \ + + static void useRVA20U64Profile(); + + // https://github.com/riscv/riscv-profiles/blob/main/profiles.adoc#rva22-profiles + #define RV_USE_RVA22U64 \ + RV_ENABLE_EXTENSION(UseRVC) \ + RV_ENABLE_EXTENSION(UseZba) \ + RV_ENABLE_EXTENSION(UseZbb) \ + RV_ENABLE_EXTENSION(UseZbs) \ + RV_ENABLE_EXTENSION(UseZic64b) \ + RV_ENABLE_EXTENSION(UseZicbom) \ + RV_ENABLE_EXTENSION(UseZicbop) \ + RV_ENABLE_EXTENSION(UseZicboz) \ + RV_ENABLE_EXTENSION(UseZihintpause) \ + + static void useRVA22U64Profile(); + + // https://github.com/riscv/riscv-profiles/blob/main/rva23-profile.adoc#rva23u64-profile + #define RV_USE_RVA23U64 \ + RV_ENABLE_EXTENSION(UseRVC) \ + RV_ENABLE_EXTENSION(UseRVV) \ + RV_ENABLE_EXTENSION(UseZba) \ + RV_ENABLE_EXTENSION(UseZbb) \ + RV_ENABLE_EXTENSION(UseZbs) \ + RV_ENABLE_EXTENSION(UseZcb) \ + RV_ENABLE_EXTENSION(UseZic64b) \ + RV_ENABLE_EXTENSION(UseZicbom) \ + RV_ENABLE_EXTENSION(UseZicbop) \ + RV_ENABLE_EXTENSION(UseZicboz) \ + RV_ENABLE_EXTENSION(UseZihintpause) \ + + static void useRVA23U64Profile(); + // VM modes (satp.mode) privileged ISA 1.10 enum VM_MODE : int { VM_NOTSET = -1, diff --git a/src/hotspot/cpu/s390/foreignGlobals_s390.cpp b/src/hotspot/cpu/s390/foreignGlobals_s390.cpp index 6f4697625cb..b716b9126f2 100644 --- a/src/hotspot/cpu/s390/foreignGlobals_s390.cpp +++ b/src/hotspot/cpu/s390/foreignGlobals_s390.cpp @@ -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. * Copyright (c) 2020, Red Hat, Inc. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -166,7 +166,7 @@ static void move_stack(MacroAssembler* masm, Register tmp_reg, int in_stk_bias, case StorageType::INTEGER: switch (from_reg.stack_size()) { case 8: __ mem2reg_opt(as_Register(to_reg), from_addr, true);break; - case 4: __ mem2reg_opt(as_Register(to_reg), from_addr, false);break; + case 4: __ mem2reg_signed_opt(as_Register(to_reg), from_addr);break; default: ShouldNotReachHere(); } break; diff --git a/src/hotspot/cpu/s390/frame_s390.cpp b/src/hotspot/cpu/s390/frame_s390.cpp index dbaa243eb1c..11c7386dfd7 100644 --- a/src/hotspot/cpu/s390/frame_s390.cpp +++ b/src/hotspot/cpu/s390/frame_s390.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. * Copyright (c) 2016, 2023 SAP SE. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -267,7 +267,7 @@ void frame::patch_pc(Thread* thread, address pc) { DEBUG_ONLY(address old_pc = _pc;) own_abi()->return_pc = (uint64_t)pc; _pc = pc; // must be set before call to get_deopt_original_pc - address original_pc = CompiledMethod::get_deopt_original_pc(this); + address original_pc = get_deopt_original_pc(); if (original_pc != nullptr) { // assert(original_pc == _pc, "expected original to be stored before patching"); _deopt_state = is_deoptimized; @@ -275,7 +275,7 @@ void frame::patch_pc(Thread* thread, address pc) { } else { _deopt_state = not_deoptimized; } - assert(!is_compiled_frame() || !_cb->as_compiled_method()->is_deopt_entry(_pc), "must be"); + assert(!is_compiled_frame() || !_cb->as_nmethod()->is_deopt_entry(_pc), "must be"); #ifdef ASSERT { diff --git a/src/hotspot/cpu/s390/frame_s390.inline.hpp b/src/hotspot/cpu/s390/frame_s390.inline.hpp index 178f7f90849..62e202337fe 100644 --- a/src/hotspot/cpu/s390/frame_s390.inline.hpp +++ b/src/hotspot/cpu/s390/frame_s390.inline.hpp @@ -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. * Copyright (c) 2016 SAP SE. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -56,11 +56,11 @@ inline void frame::setup() { assert(_on_heap || (is_aligned(_sp, alignment_in_bytes) && is_aligned(_fp, alignment_in_bytes)), "invalid alignment sp:" PTR_FORMAT " unextended_sp:" PTR_FORMAT " fp:" PTR_FORMAT, p2i(_sp), p2i(_unextended_sp), p2i(_fp)); - address original_pc = CompiledMethod::get_deopt_original_pc(this); + address original_pc = get_deopt_original_pc(); if (original_pc != nullptr) { _pc = original_pc; _deopt_state = is_deoptimized; - assert(_cb == nullptr || _cb->as_compiled_method()->insts_contains_inclusive(_pc), + assert(_cb == nullptr || _cb->as_nmethod()->insts_contains_inclusive(_pc), "original PC must be in the main code section of the compiled method (or must be immediately following it)"); } else { if (_cb == SharedRuntime::deopt_blob()) { diff --git a/src/hotspot/cpu/s390/macroAssembler_s390.cpp b/src/hotspot/cpu/s390/macroAssembler_s390.cpp index 0226d494c89..fd04a66a843 100644 --- a/src/hotspot/cpu/s390/macroAssembler_s390.cpp +++ b/src/hotspot/cpu/s390/macroAssembler_s390.cpp @@ -1,6 +1,6 @@ /* * Copyright (c) 2016, 2024, Oracle and/or its affiliates. All rights reserved. - * Copyright (c) 2016, 2023 SAP SE. All rights reserved. + * Copyright (c) 2016, 2024 SAP SE. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -3196,28 +3196,32 @@ void MacroAssembler::compiler_fast_lock_object(Register oop, Register box, Regis Register temp = temp2; NearLabel done, object_has_monitor; + const int hdr_offset = oopDesc::mark_offset_in_bytes(); + + assert_different_registers(temp1, temp2, oop, box); + BLOCK_COMMENT("compiler_fast_lock_object {"); // Load markWord from oop into mark. - z_lg(displacedHeader, 0, oop); + z_lg(displacedHeader, hdr_offset, oop); if (DiagnoseSyncOnValueBasedClasses != 0) { - load_klass(Z_R1_scratch, oop); - z_l(Z_R1_scratch, Address(Z_R1_scratch, Klass::access_flags_offset())); + load_klass(temp, oop); + z_l(temp, Address(temp, Klass::access_flags_offset())); assert((JVM_ACC_IS_VALUE_BASED_CLASS & 0xFFFF) == 0, "or change following instruction"); - z_nilh(Z_R1_scratch, JVM_ACC_IS_VALUE_BASED_CLASS >> 16); + z_nilh(temp, JVM_ACC_IS_VALUE_BASED_CLASS >> 16); z_brne(done); } // Handle existing monitor. // The object has an existing monitor iff (mark & monitor_value) != 0. guarantee(Immediate::is_uimm16(markWord::monitor_value), "must be half-word"); - z_lgr(temp, displacedHeader); - z_nill(temp, markWord::monitor_value); - z_brne(object_has_monitor); + z_tmll(displacedHeader, markWord::monitor_value); + z_brnaz(object_has_monitor); if (LockingMode == LM_MONITOR) { // Set NE to indicate 'failure' -> take slow-path + // From loading the markWord, we know that oop != nullptr z_ltgr(oop, oop); z_bru(done); } else if (LockingMode == LM_LEGACY) { @@ -3229,23 +3233,24 @@ void MacroAssembler::compiler_fast_lock_object(Register oop, Register box, Regis // Initialize the box (must happen before we update the object mark). z_stg(displacedHeader, BasicLock::displaced_header_offset_in_bytes(), box); - // Memory Fence (in cmpxchgd) - // Compare object markWord with mark and if equal exchange scratch1 with object markWord. - - // If the compare-and-swap succeeded, then we found an unlocked object and we - // have now locked it. - z_csg(displacedHeader, box, 0, oop); + // Compare object markWord with mark and if equal, exchange box with object markWork. + // If the compare-and-swap succeeds, then we found an unlocked object and have now locked it. + z_csg(displacedHeader, box, hdr_offset, oop); assert(currentHeader == displacedHeader, "must be same register"); // Identified two registers from z/Architecture. z_bre(done); - // We did not see an unlocked object so try the fast recursive case. - + // We did not see an unlocked object + // currentHeader contains what is currently stored in the oop's markWord. + // We might have a recursive case. Verify by checking if the owner is self. + // To do so, compare the value in the markWord (currentHeader) with the stack pointer. z_sgr(currentHeader, Z_SP); load_const_optimized(temp, (~(os::vm_page_size() - 1) | markWord::lock_mask_in_place)); z_ngr(currentHeader, temp); - // z_brne(done); - // z_release(); + + // result zero: owner is self -> recursive lock. Indicate that by storing 0 in the box. + // result not-zero: attempt failed. We don't hold the lock -> go for slow case. + z_stg(currentHeader/*==0 or not 0*/, BasicLock::displaced_header_offset_in_bytes(), box); z_bru(done); @@ -3255,28 +3260,34 @@ void MacroAssembler::compiler_fast_lock_object(Register oop, Register box, Regis z_bru(done); } + bind(object_has_monitor); + Register zero = temp; Register monitor_tagged = displacedHeader; // Tagged with markWord::monitor_value. - bind(object_has_monitor); // The object's monitor m is unlocked iff m->owner is null, // otherwise m->owner may contain a thread or a stack address. - // + // Try to CAS m->owner from null to current thread. - z_lghi(zero, 0); // If m->owner is null, then csg succeeds and sets m->owner=THREAD and CR=EQ. + // Otherwise, register zero is filled with the current owner. + z_lghi(zero, 0); z_csg(zero, Z_thread, OM_OFFSET_NO_MONITOR_VALUE_TAG(owner), monitor_tagged); if (LockingMode != LM_LIGHTWEIGHT) { // Store a non-null value into the box. z_stg(box, BasicLock::displaced_header_offset_in_bytes(), box); } -#ifdef ASSERT - z_brne(done); - // We've acquired the monitor, check some invariants. - // Invariant 1: _recursions should be 0. - asm_assert_mem8_is_zero(OM_OFFSET_NO_MONITOR_VALUE_TAG(recursions), monitor_tagged, - "monitor->_recursions should be 0", -1); - z_ltgr(zero, zero); // Set CR=EQ. -#endif + + z_bre(done); // acquired the lock for the first time. + + BLOCK_COMMENT("fast_path_recursive_lock {"); + // Check if we are already the owner (recursive lock) + z_cgr(Z_thread, zero); // owner is stored in zero by "z_csg" above + z_brne(done); // not a recursive lock + + // Current thread already owns the lock. Just increment recursion count. + z_agsi(Address(monitor_tagged, OM_OFFSET_NO_MONITOR_VALUE_TAG(recursions)), 1ll); + z_cgr(zero, zero); // set the CC to EQUAL + BLOCK_COMMENT("} fast_path_recursive_lock"); bind(done); BLOCK_COMMENT("} compiler_fast_lock_object"); @@ -3289,11 +3300,12 @@ void MacroAssembler::compiler_fast_unlock_object(Register oop, Register box, Reg Register displacedHeader = temp1; Register currentHeader = temp2; Register temp = temp1; - Register monitor = temp2; const int hdr_offset = oopDesc::mark_offset_in_bytes(); - Label done, object_has_monitor; + assert_different_registers(temp1, temp2, oop, box); + + Label done, object_has_monitor, not_recursive; BLOCK_COMMENT("compiler_fast_unlock_object {"); @@ -3308,30 +3320,25 @@ void MacroAssembler::compiler_fast_unlock_object(Register oop, Register box, Reg // The object has an existing monitor iff (mark & monitor_value) != 0. z_lg(currentHeader, hdr_offset, oop); guarantee(Immediate::is_uimm16(markWord::monitor_value), "must be half-word"); - if (LockingMode == LM_LIGHTWEIGHT) { - z_lgr(temp, currentHeader); - } - z_nill(currentHeader, markWord::monitor_value); - z_brne(object_has_monitor); + + z_tmll(currentHeader, markWord::monitor_value); + z_brnaz(object_has_monitor); if (LockingMode == LM_MONITOR) { // Set NE to indicate 'failure' -> take slow-path z_ltgr(oop, oop); z_bru(done); } else if (LockingMode == LM_LEGACY) { - // Check if it is still a light weight lock, this is true if we see + // Check if it is still a lightweight lock, this is true if we see // the stack address of the basicLock in the markWord of the object // copy box to currentHeader such that csg does not kill it. z_lgr(currentHeader, box); - z_csg(currentHeader, displacedHeader, 0, oop); + z_csg(currentHeader, displacedHeader, hdr_offset, oop); z_bru(done); // csg sets CR as desired. } else { assert(LockingMode == LM_LIGHTWEIGHT, "must be"); - // don't load currentHead again from stack-top after monitor check, as it is possible - // some other thread modified it. - // currentHeader is altered, but it's contents are copied in temp as well - lightweight_unlock(oop, temp, currentHeader, done); + lightweight_unlock(oop, currentHeader, displacedHeader, done); z_bru(done); } @@ -3340,11 +3347,22 @@ void MacroAssembler::compiler_fast_unlock_object(Register oop, Register box, Reg // Handle existing monitor. bind(object_has_monitor); - z_lg(currentHeader, hdr_offset, oop); // CurrentHeader is tagged with monitor_value set. - load_and_test_long(temp, Address(currentHeader, OM_OFFSET_NO_MONITOR_VALUE_TAG(recursions))); - z_brne(done); - load_and_test_long(temp, Address(currentHeader, OM_OFFSET_NO_MONITOR_VALUE_TAG(owner))); + + z_cg(Z_thread, Address(currentHeader, OM_OFFSET_NO_MONITOR_VALUE_TAG(owner))); z_brne(done); + + BLOCK_COMMENT("fast_path_recursive_unlock {"); + load_and_test_long(temp, Address(currentHeader, OM_OFFSET_NO_MONITOR_VALUE_TAG(recursions))); + z_bre(not_recursive); // if 0 then jump, it's not recursive locking + + // Recursive inflated unlock + z_agsi(Address(currentHeader, OM_OFFSET_NO_MONITOR_VALUE_TAG(recursions)), -1ll); + z_cgr(currentHeader, currentHeader); // set the CC to EQUAL + BLOCK_COMMENT("} fast_path_recursive_unlock"); + z_bru(done); + + bind(not_recursive); + load_and_test_long(temp, Address(currentHeader, OM_OFFSET_NO_MONITOR_VALUE_TAG(EntryList))); z_brne(done); load_and_test_long(temp, Address(currentHeader, OM_OFFSET_NO_MONITOR_VALUE_TAG(cxq))); diff --git a/src/hotspot/cpu/s390/nativeInst_s390.cpp b/src/hotspot/cpu/s390/nativeInst_s390.cpp index 95178e9ae74..9f083fa8904 100644 --- a/src/hotspot/cpu/s390/nativeInst_s390.cpp +++ b/src/hotspot/cpu/s390/nativeInst_s390.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. * Copyright (c) 2016 SAP SE. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -540,7 +540,7 @@ void NativeMovConstReg::set_narrow_klass(intptr_t data) { ICache::invalidate_range(start, range); } -void NativeMovConstReg::set_pcrel_addr(intptr_t newTarget, CompiledMethod *passed_nm /* = nullptr */) { +void NativeMovConstReg::set_pcrel_addr(intptr_t newTarget, nmethod *passed_nm /* = nullptr */) { address next_address; address loc = addr_at(0); @@ -565,7 +565,7 @@ void NativeMovConstReg::set_pcrel_addr(intptr_t newTarget, CompiledMethod *passe } } -void NativeMovConstReg::set_pcrel_data(intptr_t newData, CompiledMethod *passed_nm /* = nullptr */) { +void NativeMovConstReg::set_pcrel_data(intptr_t newData, nmethod *passed_nm /* = nullptr */) { address next_address; address loc = addr_at(0); diff --git a/src/hotspot/cpu/s390/nativeInst_s390.hpp b/src/hotspot/cpu/s390/nativeInst_s390.hpp index abad50da8b4..13f15224f8b 100644 --- a/src/hotspot/cpu/s390/nativeInst_s390.hpp +++ b/src/hotspot/cpu/s390/nativeInst_s390.hpp @@ -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. * Copyright (c) 2016 SAP SE. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -486,8 +486,8 @@ class NativeMovConstReg: public NativeInstruction { // Patch narrow oop constant in code stream. void set_narrow_oop(intptr_t data); void set_narrow_klass(intptr_t data); - void set_pcrel_addr(intptr_t addr, CompiledMethod *nm = nullptr); - void set_pcrel_data(intptr_t data, CompiledMethod *nm = nullptr); + void set_pcrel_addr(intptr_t addr, nmethod *nm = nullptr); + void set_pcrel_data(intptr_t data, nmethod *nm = nullptr); void verify(); diff --git a/src/hotspot/cpu/x86/assembler_x86.cpp b/src/hotspot/cpu/x86/assembler_x86.cpp index a5b2e6e5972..bb04ae12fa8 100644 --- a/src/hotspot/cpu/x86/assembler_x86.cpp +++ b/src/hotspot/cpu/x86/assembler_x86.cpp @@ -2031,7 +2031,7 @@ void Assembler::cvtsd2ss(XMMRegister dst, XMMRegister src) { NOT_LP64(assert(VM_Version::supports_sse2(), "")); InstructionAttr attributes(AVX_128bit, /* rex_w */ VM_Version::supports_evex(), /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); attributes.set_rex_vex_w_reverted(); - int encode = simd_prefix_and_encode(dst, dst, src, VEX_SIMD_F2, VEX_OPCODE_0F, &attributes); + int encode = simd_prefix_and_encode(dst, src, src, VEX_SIMD_F2, VEX_OPCODE_0F, &attributes); emit_int16(0x5A, (0xC0 | encode)); } @@ -2090,7 +2090,7 @@ void Assembler::cvtsi2ssq(XMMRegister dst, Register src) { void Assembler::cvtss2sd(XMMRegister dst, XMMRegister src) { NOT_LP64(assert(VM_Version::supports_sse2(), "")); InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); - int encode = simd_prefix_and_encode(dst, dst, src, VEX_SIMD_F3, VEX_OPCODE_0F, &attributes); + int encode = simd_prefix_and_encode(dst, src, src, VEX_SIMD_F3, VEX_OPCODE_0F, &attributes); emit_int16(0x5A, (0xC0 | encode)); } diff --git a/src/hotspot/cpu/x86/c2_MacroAssembler_x86.cpp b/src/hotspot/cpu/x86/c2_MacroAssembler_x86.cpp index b6ecde62af6..c79753618c0 100644 --- a/src/hotspot/cpu/x86/c2_MacroAssembler_x86.cpp +++ b/src/hotspot/cpu/x86/c2_MacroAssembler_x86.cpp @@ -1022,15 +1022,18 @@ void C2_MacroAssembler::fast_lock_lightweight(Register obj, Register box, Regist #ifdef ASSERT // Check that locked label is reached with ZF set. Label zf_correct; - jccb(Assembler::zero, zf_correct); - stop("Fast Lock ZF != 1"); + Label zf_bad_zero; + jcc(Assembler::zero, zf_correct); + jmp(zf_bad_zero); #endif bind(slow_path); #ifdef ASSERT // Check that slow_path label is reached with ZF not set. - jccb(Assembler::notZero, zf_correct); + jcc(Assembler::notZero, zf_correct); stop("Fast Lock ZF != 0"); + bind(zf_bad_zero); + stop("Fast Lock ZF != 1"); bind(zf_correct); #endif // C2 uses the value of ZF to determine the continuation. @@ -1161,7 +1164,7 @@ void C2_MacroAssembler::fast_unlock_lightweight(Register obj, Register reg_rax, #ifdef ASSERT // Check that unlocked label is reached with ZF set. Label zf_correct; - jccb(Assembler::zero, zf_correct); + jcc(Assembler::zero, zf_correct); stop("Fast Unlock ZF != 1"); #endif diff --git a/src/hotspot/cpu/x86/continuationEntry_x86.inline.hpp b/src/hotspot/cpu/x86/continuationEntry_x86.inline.hpp index cd173ce95f4..7d13a5200ea 100644 --- a/src/hotspot/cpu/x86/continuationEntry_x86.inline.hpp +++ b/src/hotspot/cpu/x86/continuationEntry_x86.inline.hpp @@ -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 @@ -35,7 +35,7 @@ inline frame ContinuationEntry::to_frame() const { static CodeBlob* cb = CodeCache::find_blob_fast(entry_pc()); assert(cb != nullptr, ""); - assert(cb->as_compiled_method()->method()->is_continuation_enter_intrinsic(), ""); + assert(cb->as_nmethod()->method()->is_continuation_enter_intrinsic(), ""); return frame(entry_sp(), entry_sp(), entry_fp(), entry_pc(), cb); } diff --git a/src/hotspot/cpu/x86/frame_x86.cpp b/src/hotspot/cpu/x86/frame_x86.cpp index bef2443a60a..2366d31992d 100644 --- a/src/hotspot/cpu/x86/frame_x86.cpp +++ b/src/hotspot/cpu/x86/frame_x86.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 @@ -95,7 +95,7 @@ bool frame::safe_for_sender(JavaThread *thread) { // ok. adapter blobs never have a frame complete and are never ok. if (!_cb->is_frame_complete_at(_pc)) { - if (_cb->is_compiled() || _cb->is_adapter_blob() || _cb->is_runtime_stub()) { + if (_cb->is_nmethod() || _cb->is_adapter_blob() || _cb->is_runtime_stub()) { return false; } } @@ -213,7 +213,7 @@ bool frame::safe_for_sender(JavaThread *thread) { return false; } - CompiledMethod* nm = sender_blob->as_compiled_method_or_null(); + nmethod* nm = sender_blob->as_nmethod_or_null(); if (nm != nullptr) { if (nm->is_deopt_mh_entry(sender_pc) || nm->is_deopt_entry(sender_pc) || nm->method()->is_method_handle_intrinsic()) { @@ -225,7 +225,7 @@ bool frame::safe_for_sender(JavaThread *thread) { // because the return address counts against the callee's frame. if (sender_blob->frame_size() <= 0) { - assert(!sender_blob->is_compiled(), "should count return address at least"); + assert(!sender_blob->is_nmethod(), "should count return address at least"); return false; } @@ -234,7 +234,7 @@ bool frame::safe_for_sender(JavaThread *thread) { // should not be anything but the call stub (already covered), the interpreter (already covered) // or an nmethod. - if (!sender_blob->is_compiled()) { + if (!sender_blob->is_nmethod()) { return false; } @@ -283,7 +283,7 @@ void frame::patch_pc(Thread* thread, address pc) { DEBUG_ONLY(address old_pc = _pc;) *pc_addr = pc; _pc = pc; // must be set before call to get_deopt_original_pc - address original_pc = CompiledMethod::get_deopt_original_pc(this); + address original_pc = get_deopt_original_pc(); if (original_pc != nullptr) { assert(original_pc == old_pc, "expected original PC to be stored before patching"); _deopt_state = is_deoptimized; @@ -291,7 +291,7 @@ void frame::patch_pc(Thread* thread, address pc) { } else { _deopt_state = not_deoptimized; } - assert(!is_compiled_frame() || !_cb->as_compiled_method()->is_deopt_entry(_pc), "must be"); + assert(!is_compiled_frame() || !_cb->as_nmethod()->is_deopt_entry(_pc), "must be"); #ifdef ASSERT { @@ -415,7 +415,7 @@ frame frame::sender_for_upcall_stub_frame(RegisterMap* map) const { // Verifies the calculated original PC of a deoptimization PC for the // given unextended SP. #ifdef ASSERT -void frame::verify_deopt_original_pc(CompiledMethod* nm, intptr_t* unextended_sp) { +void frame::verify_deopt_original_pc(nmethod* nm, intptr_t* unextended_sp) { frame fr; // This is ugly but it's better than to change {get,set}_original_pc @@ -438,12 +438,12 @@ void frame::adjust_unextended_sp() { // returning to any of these call sites. if (_cb != nullptr) { - CompiledMethod* sender_cm = _cb->as_compiled_method_or_null(); - if (sender_cm != nullptr) { + nmethod* sender_nm = _cb->as_nmethod_or_null(); + if (sender_nm != nullptr) { // If the sender PC is a deoptimization point, get the original PC. - if (sender_cm->is_deopt_entry(_pc) || - sender_cm->is_deopt_mh_entry(_pc)) { - verify_deopt_original_pc(sender_cm, _unextended_sp); + if (sender_nm->is_deopt_entry(_pc) || + sender_nm->is_deopt_mh_entry(_pc)) { + verify_deopt_original_pc(sender_nm, _unextended_sp); } } } diff --git a/src/hotspot/cpu/x86/frame_x86.hpp b/src/hotspot/cpu/x86/frame_x86.hpp index 44c8574c540..f3034ee9263 100644 --- a/src/hotspot/cpu/x86/frame_x86.hpp +++ b/src/hotspot/cpu/x86/frame_x86.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 @@ -146,7 +146,7 @@ #ifdef ASSERT // Used in frame::sender_for_{interpreter,compiled}_frame - static void verify_deopt_original_pc(CompiledMethod* nm, intptr_t* unextended_sp); + static void verify_deopt_original_pc(nmethod* nm, intptr_t* unextended_sp); #endif public: diff --git a/src/hotspot/cpu/x86/frame_x86.inline.hpp b/src/hotspot/cpu/x86/frame_x86.inline.hpp index f69803d579d..0f7e536a494 100644 --- a/src/hotspot/cpu/x86/frame_x86.inline.hpp +++ b/src/hotspot/cpu/x86/frame_x86.inline.hpp @@ -66,11 +66,11 @@ inline void frame::init(intptr_t* sp, intptr_t* fp, address pc) { inline void frame::setup(address pc) { adjust_unextended_sp(); - address original_pc = CompiledMethod::get_deopt_original_pc(this); + address original_pc = get_deopt_original_pc(); if (original_pc != nullptr) { _pc = original_pc; _deopt_state = is_deoptimized; - assert(_cb == nullptr || _cb->as_compiled_method()->insts_contains_inclusive(_pc), + assert(_cb == nullptr || _cb->as_nmethod()->insts_contains_inclusive(_pc), "original PC must be in the main code section of the compiled method (or must be immediately following it)"); } else { if (_cb == SharedRuntime::deopt_blob()) { @@ -164,7 +164,7 @@ inline frame::frame(intptr_t* sp, intptr_t* fp) { _cb = CodeCache::find_blob(_pc); adjust_unextended_sp(); - address original_pc = CompiledMethod::get_deopt_original_pc(this); + address original_pc = get_deopt_original_pc(); if (original_pc != nullptr) { _pc = original_pc; _deopt_state = is_deoptimized; @@ -226,8 +226,8 @@ inline int frame::frame_size() const { } inline int frame::compiled_frame_stack_argsize() const { - assert(cb()->is_compiled(), ""); - return (cb()->as_compiled_method()->method()->num_stack_arg_slots() * VMRegImpl::stack_slot_size) >> LogBytesPerWord; + assert(cb()->is_nmethod(), ""); + return (cb()->as_nmethod()->method()->num_stack_arg_slots() * VMRegImpl::stack_slot_size) >> LogBytesPerWord; } inline void frame::interpreted_frame_oop_map(InterpreterOopMap* mask) const { @@ -397,7 +397,7 @@ inline frame frame::sender_for_compiled_frame(RegisterMap* map) const { // Tell GC to use argument oopmaps for some runtime stubs that need it. // For C1, the runtime stub might not have oop maps, so set this flag // outside of update_register_map. - if (!_cb->is_compiled()) { // compiled frames do not use callee-saved registers + if (!_cb->is_nmethod()) { // compiled frames do not use callee-saved registers map->set_include_argument_oops(_cb->caller_must_gc_arguments(map->thread())); if (oop_map() != nullptr) { _oop_map->update_register_map(this, map); diff --git a/src/hotspot/cpu/x86/gc/g1/g1BarrierSetAssembler_x86.cpp b/src/hotspot/cpu/x86/gc/g1/g1BarrierSetAssembler_x86.cpp index f9f77c23f14..0ea93ec067e 100644 --- a/src/hotspot/cpu/x86/gc/g1/g1BarrierSetAssembler_x86.cpp +++ b/src/hotspot/cpu/x86/gc/g1/g1BarrierSetAssembler_x86.cpp @@ -269,8 +269,6 @@ void G1BarrierSetAssembler::g1_write_barrier_post(MacroAssembler* masm, Register thread, Register tmp, Register tmp2) { - // Generated code assumes that buffer index is pointer sized. - STATIC_ASSERT(in_bytes(SATBMarkQueue::byte_width_of_index()) == sizeof(intptr_t)); #ifdef _LP64 assert(thread == r15_thread, "must be"); #endif // _LP64 @@ -321,6 +319,9 @@ void G1BarrierSetAssembler::g1_write_barrier_post(MacroAssembler* masm, __ movb(Address(card_addr, 0), G1CardTable::dirty_card_val()); + // The code below assumes that buffer index is pointer sized. + STATIC_ASSERT(in_bytes(G1DirtyCardQueue::byte_width_of_index()) == sizeof(intptr_t)); + __ movptr(tmp2, queue_index); __ testptr(tmp2, tmp2); __ jcc(Assembler::zero, runtime); diff --git a/src/hotspot/cpu/x86/macroAssembler_x86.cpp b/src/hotspot/cpu/x86/macroAssembler_x86.cpp index 2f546c15e18..eb70c807e52 100644 --- a/src/hotspot/cpu/x86/macroAssembler_x86.cpp +++ b/src/hotspot/cpu/x86/macroAssembler_x86.cpp @@ -4339,7 +4339,7 @@ void MacroAssembler::lookup_interface_method(Register recv_klass, movl(scan_temp, Address(recv_klass, Klass::vtable_length_offset())); - // %%% Could store the aligned, prescaled offset in the klassoop. + // Could store the aligned, prescaled offset in the klass. lea(scan_temp, Address(recv_klass, scan_temp, times_vte_scale, vtable_base)); if (return_method) { @@ -5779,7 +5779,7 @@ void MacroAssembler::xmm_clear_mem(Register base, Register cnt, Register rtmp, X // Clearing constant sized memory using YMM/ZMM registers. void MacroAssembler::clear_mem(Register base, int cnt, Register rtmp, XMMRegister xtmp, KRegister mask) { - assert(UseAVX > 2 && VM_Version::supports_avx512vlbw(), ""); + assert(UseAVX > 2 && VM_Version::supports_avx512vl(), ""); bool use64byteVector = (MaxVectorSize > 32) && (VM_Version::avx3_threshold() == 0); int vector64_count = (cnt & (~0x7)) >> 3; diff --git a/src/hotspot/cpu/x86/stackChunkFrameStream_x86.inline.hpp b/src/hotspot/cpu/x86/stackChunkFrameStream_x86.inline.hpp index 3b3e2dee10c..71b938248ec 100644 --- a/src/hotspot/cpu/x86/stackChunkFrameStream_x86.inline.hpp +++ b/src/hotspot/cpu/x86/stackChunkFrameStream_x86.inline.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 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,7 +34,7 @@ template inline bool StackChunkFrameStream::is_in_frame(void* p0) const { assert(!is_done(), ""); intptr_t* p = (intptr_t*)p0; - int argsize = is_compiled() ? (_cb->as_compiled_method()->method()->num_stack_arg_slots() * VMRegImpl::stack_slot_size) >> LogBytesPerWord : 0; + int argsize = is_compiled() ? (_cb->as_nmethod()->method()->num_stack_arg_slots() * VMRegImpl::stack_slot_size) >> LogBytesPerWord : 0; int frame_size = _cb->frame_size() + argsize; return p == sp() - frame::sender_sp_offset || ((p - unextended_sp()) >= 0 && (p - unextended_sp()) < frame_size); } diff --git a/src/hotspot/cpu/x86/vm_version_x86.cpp b/src/hotspot/cpu/x86/vm_version_x86.cpp index 1159d0f69a3..0bffb1aee13 100644 --- a/src/hotspot/cpu/x86/vm_version_x86.cpp +++ b/src/hotspot/cpu/x86/vm_version_x86.cpp @@ -2951,6 +2951,8 @@ uint64_t VM_Version::CpuidInfo::feature_flags() const { if (sef_cpuid7_ecx1_eax.bits.avx_ifma != 0) result |= CPU_AVX_IFMA; } + if (sef_cpuid7_ecx.bits.gfni != 0) + result |= CPU_GFNI; if (sef_cpuid7_ebx.bits.avx512f != 0 && xem_xcr0_eax.bits.opmask != 0 && xem_xcr0_eax.bits.zmm512 != 0 && @@ -2976,8 +2978,6 @@ uint64_t VM_Version::CpuidInfo::feature_flags() const { result |= CPU_AVX512_VPCLMULQDQ; if (sef_cpuid7_ecx.bits.vaes != 0) result |= CPU_AVX512_VAES; - if (sef_cpuid7_ecx.bits.gfni != 0) - result |= CPU_GFNI; if (sef_cpuid7_ecx.bits.avx512_vnni != 0) result |= CPU_AVX512_VNNI; if (sef_cpuid7_ecx.bits.avx512_bitalg != 0) diff --git a/src/hotspot/cpu/x86/x86.ad b/src/hotspot/cpu/x86/x86.ad index 0c8fddcdc38..54306d02ea0 100644 --- a/src/hotspot/cpu/x86/x86.ad +++ b/src/hotspot/cpu/x86/x86.ad @@ -1750,7 +1750,6 @@ bool Matcher::match_rule_supported_vector(int opcode, int vlen, BasicType bt) { return false; } break; - case Op_ClearArray: case Op_VectorMaskGen: case Op_VectorCmpMasked: if (!is_LP64 || !VM_Version::supports_avx512bw()) { diff --git a/src/hotspot/cpu/x86/x86_32.ad b/src/hotspot/cpu/x86/x86_32.ad index 1c9f6fc4134..36ec4d283ed 100644 --- a/src/hotspot/cpu/x86/x86_32.ad +++ b/src/hotspot/cpu/x86/x86_32.ad @@ -11470,8 +11470,8 @@ instruct expandBitsL_reg(eADXRegL dst, eBCXRegL src, eBDPRegL mask, eSIRegI rtmp %} // ======================================================================= -// fast clearing of an array -// Small ClearArray non-AVX512. +// Fast clearing of an array +// Small non-constant length ClearArray for non-AVX512 targets. instruct rep_stos(eCXRegI cnt, eDIRegP base, regD tmp, eAXRegI zero, Universe dummy, eFlagsReg cr) %{ predicate(!((ClearArrayNode*)n)->is_large() && (UseAVX <= 2)); match(Set dummy (ClearArray cnt base)); @@ -11531,7 +11531,7 @@ instruct rep_stos(eCXRegI cnt, eDIRegP base, regD tmp, eAXRegI zero, Universe du ins_pipe( pipe_slow ); %} -// Small ClearArray AVX512 non-constant length. +// Small non-constant length ClearArray for AVX512 targets. instruct rep_stos_evex(eCXRegI cnt, eDIRegP base, legRegD tmp, kReg ktmp, eAXRegI zero, Universe dummy, eFlagsReg cr) %{ predicate(!((ClearArrayNode*)n)->is_large() && (UseAVX > 2)); match(Set dummy (ClearArray cnt base)); @@ -11592,7 +11592,7 @@ instruct rep_stos_evex(eCXRegI cnt, eDIRegP base, legRegD tmp, kReg ktmp, eAXReg ins_pipe( pipe_slow ); %} -// Large ClearArray non-AVX512. +// Large non-constant length ClearArray for non-AVX512 targets. instruct rep_stos_large(eCXRegI cnt, eDIRegP base, regD tmp, eAXRegI zero, Universe dummy, eFlagsReg cr) %{ predicate((UseAVX <= 2) && ((ClearArrayNode*)n)->is_large()); match(Set dummy (ClearArray cnt base)); @@ -11642,7 +11642,7 @@ instruct rep_stos_large(eCXRegI cnt, eDIRegP base, regD tmp, eAXRegI zero, Unive ins_pipe( pipe_slow ); %} -// Large ClearArray AVX512. +// Large non-constant length ClearArray for AVX512 targets. instruct rep_stos_large_evex(eCXRegI cnt, eDIRegP base, legRegD tmp, kReg ktmp, eAXRegI zero, Universe dummy, eFlagsReg cr) %{ predicate((UseAVX > 2) && ((ClearArrayNode*)n)->is_large()); match(Set dummy (ClearArray cnt base)); @@ -11692,11 +11692,10 @@ instruct rep_stos_large_evex(eCXRegI cnt, eDIRegP base, legRegD tmp, kReg ktmp, ins_pipe( pipe_slow ); %} -// Small ClearArray AVX512 constant length. +// Small constant length ClearArray for AVX512 targets. instruct rep_stos_im(immI cnt, kReg ktmp, eRegP base, regD tmp, rRegI zero, Universe dummy, eFlagsReg cr) %{ - predicate(!((ClearArrayNode*)n)->is_large() && - ((UseAVX > 2) && VM_Version::supports_avx512vlbw())); + predicate(!((ClearArrayNode*)n)->is_large() && (MaxVectorSize >= 32) && VM_Version::supports_avx512vl()); match(Set dummy (ClearArray cnt base)); ins_cost(100); effect(TEMP tmp, TEMP zero, TEMP ktmp, KILL cr); diff --git a/src/hotspot/cpu/x86/x86_64.ad b/src/hotspot/cpu/x86/x86_64.ad index aef3453b0b1..4e57f3e1bbe 100644 --- a/src/hotspot/cpu/x86/x86_64.ad +++ b/src/hotspot/cpu/x86/x86_64.ad @@ -5662,7 +5662,7 @@ instruct bytes_reversebit_int(rRegI dst, rRegI src, rRegI rtmp, rFlagsReg cr) %{ ins_pipe( ialu_reg ); %} -instruct bytes_reversebit_int_gfni(rRegI dst, rRegI src, regF xtmp1, regF xtmp2, rRegL rtmp, rFlagsReg cr) %{ +instruct bytes_reversebit_int_gfni(rRegI dst, rRegI src, vlRegF xtmp1, vlRegF xtmp2, rRegL rtmp, rFlagsReg cr) %{ predicate(VM_Version::supports_gfni()); match(Set dst (ReverseI src)); effect(TEMP dst, TEMP xtmp1, TEMP xtmp2, TEMP rtmp, KILL cr); @@ -5684,7 +5684,7 @@ instruct bytes_reversebit_long(rRegL dst, rRegL src, rRegL rtmp1, rRegL rtmp2, r ins_pipe( ialu_reg ); %} -instruct bytes_reversebit_long_gfni(rRegL dst, rRegL src, regD xtmp1, regD xtmp2, rRegL rtmp, rFlagsReg cr) %{ +instruct bytes_reversebit_long_gfni(rRegL dst, rRegL src, vlRegD xtmp1, vlRegD xtmp2, rRegL rtmp, rFlagsReg cr) %{ predicate(VM_Version::supports_gfni()); match(Set dst (ReverseL src)); effect(TEMP dst, TEMP xtmp1, TEMP xtmp2, TEMP rtmp, KILL cr); @@ -9959,6 +9959,7 @@ instruct convF2D_reg_reg(regD dst, regF src) instruct convF2D_reg_mem(regD dst, memory src) %{ + predicate(UseAVX == 0); match(Set dst (ConvF2D (LoadF src))); format %{ "cvtss2sd $dst, $src" %} @@ -9981,6 +9982,7 @@ instruct convD2F_reg_reg(regF dst, regD src) instruct convD2F_reg_mem(regF dst, memory src) %{ + predicate(UseAVX == 0); match(Set dst (ConvD2F (LoadD src))); format %{ "cvtsd2ss $dst, $src" %} @@ -10057,13 +10059,16 @@ instruct round_float_reg(rRegI dst, regF src, rRegL rtmp, rcx_RegL rcx, rFlagsRe ins_pipe(pipe_slow); %} -instruct convI2F_reg_reg(regF dst, rRegI src) +instruct convI2F_reg_reg(vlRegF dst, rRegI src) %{ predicate(!UseXmmI2F); match(Set dst (ConvI2F src)); format %{ "cvtsi2ssl $dst, $src\t# i2f" %} ins_encode %{ + if (UseAVX > 0) { + __ pxor($dst$$XMMRegister, $dst$$XMMRegister); + } __ cvtsi2ssl ($dst$$XMMRegister, $src$$Register); %} ins_pipe(pipe_slow); // XXX @@ -10071,6 +10076,7 @@ instruct convI2F_reg_reg(regF dst, rRegI src) instruct convI2F_reg_mem(regF dst, memory src) %{ + predicate(UseAVX == 0); match(Set dst (ConvI2F (LoadI src))); format %{ "cvtsi2ssl $dst, $src\t# i2f" %} @@ -10080,13 +10086,16 @@ instruct convI2F_reg_mem(regF dst, memory src) ins_pipe(pipe_slow); // XXX %} -instruct convI2D_reg_reg(regD dst, rRegI src) +instruct convI2D_reg_reg(vlRegD dst, rRegI src) %{ predicate(!UseXmmI2D); match(Set dst (ConvI2D src)); format %{ "cvtsi2sdl $dst, $src\t# i2d" %} ins_encode %{ + if (UseAVX > 0) { + __ pxor($dst$$XMMRegister, $dst$$XMMRegister); + } __ cvtsi2sdl ($dst$$XMMRegister, $src$$Register); %} ins_pipe(pipe_slow); // XXX @@ -10094,6 +10103,7 @@ instruct convI2D_reg_reg(regD dst, rRegI src) instruct convI2D_reg_mem(regD dst, memory src) %{ + predicate(UseAVX == 0); match(Set dst (ConvI2D (LoadI src))); format %{ "cvtsi2sdl $dst, $src\t# i2d" %} @@ -10131,12 +10141,15 @@ instruct convXI2D_reg(regD dst, rRegI src) ins_pipe(pipe_slow); // XXX %} -instruct convL2F_reg_reg(regF dst, rRegL src) +instruct convL2F_reg_reg(vlRegF dst, rRegL src) %{ match(Set dst (ConvL2F src)); format %{ "cvtsi2ssq $dst, $src\t# l2f" %} ins_encode %{ + if (UseAVX > 0) { + __ pxor($dst$$XMMRegister, $dst$$XMMRegister); + } __ cvtsi2ssq ($dst$$XMMRegister, $src$$Register); %} ins_pipe(pipe_slow); // XXX @@ -10144,6 +10157,7 @@ instruct convL2F_reg_reg(regF dst, rRegL src) instruct convL2F_reg_mem(regF dst, memory src) %{ + predicate(UseAVX == 0); match(Set dst (ConvL2F (LoadL src))); format %{ "cvtsi2ssq $dst, $src\t# l2f" %} @@ -10153,12 +10167,15 @@ instruct convL2F_reg_mem(regF dst, memory src) ins_pipe(pipe_slow); // XXX %} -instruct convL2D_reg_reg(regD dst, rRegL src) +instruct convL2D_reg_reg(vlRegD dst, rRegL src) %{ match(Set dst (ConvL2D src)); format %{ "cvtsi2sdq $dst, $src\t# l2d" %} ins_encode %{ + if (UseAVX > 0) { + __ pxor($dst$$XMMRegister, $dst$$XMMRegister); + } __ cvtsi2sdq ($dst$$XMMRegister, $src$$Register); %} ins_pipe(pipe_slow); // XXX @@ -10166,6 +10183,7 @@ instruct convL2D_reg_reg(regD dst, rRegL src) instruct convL2D_reg_mem(regD dst, memory src) %{ + predicate(UseAVX == 0); match(Set dst (ConvL2D (LoadL src))); format %{ "cvtsi2sdq $dst, $src\t# l2d" %} @@ -10392,7 +10410,7 @@ instruct MoveL2D_reg_reg(regD dst, rRegL src) %{ %} // Fast clearing of an array -// Small ClearArray non-AVX512. +// Small non-constant lenght ClearArray for non-AVX512 targets. instruct rep_stos(rcx_RegL cnt, rdi_RegP base, regD tmp, rax_RegI zero, Universe dummy, rFlagsReg cr) %{ @@ -10452,7 +10470,7 @@ instruct rep_stos(rcx_RegL cnt, rdi_RegP base, regD tmp, rax_RegI zero, ins_pipe(pipe_slow); %} -// Small ClearArray AVX512 non-constant length. +// Small non-constant length ClearArray for AVX512 targets. instruct rep_stos_evex(rcx_RegL cnt, rdi_RegP base, legRegD tmp, kReg ktmp, rax_RegI zero, Universe dummy, rFlagsReg cr) %{ @@ -10513,7 +10531,7 @@ instruct rep_stos_evex(rcx_RegL cnt, rdi_RegP base, legRegD tmp, kReg ktmp, rax_ ins_pipe(pipe_slow); %} -// Large ClearArray non-AVX512. +// Large non-constant length ClearArray for non-AVX512 targets. instruct rep_stos_large(rcx_RegL cnt, rdi_RegP base, regD tmp, rax_RegI zero, Universe dummy, rFlagsReg cr) %{ @@ -10564,7 +10582,7 @@ instruct rep_stos_large(rcx_RegL cnt, rdi_RegP base, regD tmp, rax_RegI zero, ins_pipe(pipe_slow); %} -// Large ClearArray AVX512. +// Large non-constant length ClearArray for AVX512 targets. instruct rep_stos_large_evex(rcx_RegL cnt, rdi_RegP base, legRegD tmp, kReg ktmp, rax_RegI zero, Universe dummy, rFlagsReg cr) %{ @@ -10615,11 +10633,10 @@ instruct rep_stos_large_evex(rcx_RegL cnt, rdi_RegP base, legRegD tmp, kReg ktmp ins_pipe(pipe_slow); %} -// Small ClearArray AVX512 constant length. +// Small constant length ClearArray for AVX512 targets. instruct rep_stos_im(immL cnt, rRegP base, regD tmp, rRegI zero, kReg ktmp, Universe dummy, rFlagsReg cr) %{ - predicate(!((ClearArrayNode*)n)->is_large() && - ((UseAVX > 2) && VM_Version::supports_avx512vlbw())); + predicate(!((ClearArrayNode*)n)->is_large() && (MaxVectorSize >= 32) && VM_Version::supports_avx512vl()); match(Set dummy (ClearArray cnt base)); ins_cost(100); effect(TEMP tmp, TEMP zero, TEMP ktmp, KILL cr); diff --git a/src/hotspot/os/linux/os_linux.cpp b/src/hotspot/os/linux/os_linux.cpp index 0fe0acacb3c..c6323ffe756 100644 --- a/src/hotspot/os/linux/os_linux.cpp +++ b/src/hotspot/os/linux/os_linux.cpp @@ -380,16 +380,9 @@ void os::Linux::kernel_version(long* major, long* minor) { log_warning(os)("uname(2) failed to get kernel version: %s", os::errno_name(ret)); return; } - - char* walker = buffer.release; - long* set_v = major; - while (*minor == -1 && walker != nullptr) { - if (isdigit(walker[0])) { - *set_v = strtol(walker, &walker, 10); - set_v = minor; - } else { - ++walker; - } + int nr_matched = sscanf(buffer.release, "%ld.%ld", major, minor); + if (nr_matched != 2) { + log_warning(os)("Parsing kernel version failed, expected 2 version numbers, only matched %d", nr_matched); } } diff --git a/src/hotspot/os/posix/os_posix.cpp b/src/hotspot/os/posix/os_posix.cpp index 1a82cd7f865..d2de5b30484 100644 --- a/src/hotspot/os/posix/os_posix.cpp +++ b/src/hotspot/os/posix/os_posix.cpp @@ -621,9 +621,14 @@ void os::print_jni_name_suffix_on(outputStream* st, int args_size) { bool os::get_host_name(char* buf, size_t buflen) { struct utsname name; - uname(&name); - jio_snprintf(buf, buflen, "%s", name.nodename); - return true; + int retcode = uname(&name); + if (retcode != -1) { + jio_snprintf(buf, buflen, "%s", name.nodename); + return true; + } + const char* errmsg = os::strerror(errno); + log_warning(os)("Failed to get host name, error message: %s", errmsg); + return false; } #ifndef _LP64 @@ -722,7 +727,16 @@ void* os::get_default_process_handle() { } void* os::dll_lookup(void* handle, const char* name) { - return dlsym(handle, name); + ::dlerror(); // Clear any previous error + void* ret = ::dlsym(handle, name); + if (ret == nullptr) { + const char* tmp = ::dlerror(); + // It is possible that we found a NULL symbol, hence no error. + if (tmp != nullptr) { + log_debug(os)("Symbol %s not found in dll: %s", name, tmp); + } + } + return ret; } void os::dll_unload(void *lib) { diff --git a/src/hotspot/os/posix/signals_posix.cpp b/src/hotspot/os/posix/signals_posix.cpp index a62f93ab930..5172853ecd5 100644 --- a/src/hotspot/os/posix/signals_posix.cpp +++ b/src/hotspot/os/posix/signals_posix.cpp @@ -24,8 +24,8 @@ #include "precompiled.hpp" #include "code/codeCache.hpp" -#include "code/compiledMethod.hpp" #include "code/nativeInst.hpp" +#include "code/nmethod.hpp" #include "jvm.h" #include "logging/log.hpp" #include "os_posix.hpp" @@ -613,17 +613,17 @@ int JVM_HANDLE_XXX_SIGNAL(int sig, siginfo_t* info, if (!signal_was_handled && pc != nullptr && os::is_readable_pointer(pc)) { if (NativeDeoptInstruction::is_deopt_at(pc)) { CodeBlob* cb = CodeCache::find_blob(pc); - if (cb != nullptr && cb->is_compiled()) { + if (cb != nullptr && cb->is_nmethod()) { MACOS_AARCH64_ONLY(ThreadWXEnable wx(WXWrite, t);) // can call PcDescCache::add_pc_desc - CompiledMethod* cm = cb->as_compiled_method(); - assert(cm->insts_contains_inclusive(pc), ""); - address deopt = cm->is_method_handle_return(pc) ? - cm->deopt_mh_handler_begin() : - cm->deopt_handler_begin(); + nmethod* nm = cb->as_nmethod(); + assert(nm->insts_contains_inclusive(pc), ""); + address deopt = nm->is_method_handle_return(pc) ? + nm->deopt_mh_handler_begin() : + nm->deopt_handler_begin(); assert(deopt != nullptr, ""); frame fr = os::fetch_frame_from_context(uc); - cm->set_original_pc(&fr, pc); + nm->set_original_pc(&fr, pc); os::Posix::ucontext_set_pc(uc, deopt); signal_was_handled = true; diff --git a/src/hotspot/os/windows/os_windows.cpp b/src/hotspot/os/windows/os_windows.cpp index e2d0b653d15..ddc1b1c335d 100644 --- a/src/hotspot/os/windows/os_windows.cpp +++ b/src/hotspot/os/windows/os_windows.cpp @@ -1280,7 +1280,15 @@ void os::dll_unload(void *lib) { } void* os::dll_lookup(void *lib, const char *name) { - return (void*)::GetProcAddress((HMODULE)lib, name); + ::SetLastError(0); // Clear old pending errors + void* ret = ::GetProcAddress((HMODULE)lib, name); + if (ret == nullptr) { + char buf[512]; + if (os::lasterror(buf, sizeof(buf)) > 0) { + log_debug(os)("Symbol %s not found in dll: %s", name, buf); + } + } + return ret; } // Directory routines copied from src/win32/native/java/io/dirent_md.c @@ -2781,10 +2789,10 @@ LONG WINAPI topLevelExceptionFilter(struct _EXCEPTION_POINTERS* exceptionInfo) { // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - if (exception_code == EXCEPTION_IN_PAGE_ERROR) { - CompiledMethod* nm = nullptr; + nmethod* nm = nullptr; if (in_java) { CodeBlob* cb = CodeCache::find_blob(pc); - nm = (cb != nullptr) ? cb->as_compiled_method_or_null() : nullptr; + nm = (cb != nullptr) ? cb->as_nmethod_or_null() : nullptr; } bool is_unsafe_arraycopy = (in_native || in_java) && UnsafeCopyMemory::contains_pc(pc); @@ -2833,14 +2841,14 @@ LONG WINAPI topLevelExceptionFilter(struct _EXCEPTION_POINTERS* exceptionInfo) { // If it is, patch return address to be deopt handler. if (NativeDeoptInstruction::is_deopt_at(pc)) { CodeBlob* cb = CodeCache::find_blob(pc); - if (cb != nullptr && cb->is_compiled()) { - CompiledMethod* cm = cb->as_compiled_method(); + if (cb != nullptr && cb->is_nmethod()) { + nmethod* nm = cb->as_nmethod(); frame fr = os::fetch_frame_from_context((void*)exceptionInfo->ContextRecord); - address deopt = cm->is_method_handle_return(pc) ? - cm->deopt_mh_handler_begin() : - cm->deopt_handler_begin(); - assert(cm->insts_contains_inclusive(pc), ""); - cm->set_original_pc(&fr, pc); + address deopt = nm->is_method_handle_return(pc) ? + nm->deopt_mh_handler_begin() : + nm->deopt_handler_begin(); + assert(nm->insts_contains_inclusive(pc), ""); + nm->set_original_pc(&fr, pc); // Set pc to handler exceptionInfo->ContextRecord->PC_NAME = (DWORD64)deopt; return EXCEPTION_CONTINUE_EXECUTION; diff --git a/src/hotspot/os_cpu/aix_ppc/os_aix_ppc.cpp b/src/hotspot/os_cpu/aix_ppc/os_aix_ppc.cpp index 242042d4247..e1e81d673a7 100644 --- a/src/hotspot/os_cpu/aix_ppc/os_aix_ppc.cpp +++ b/src/hotspot/os_cpu/aix_ppc/os_aix_ppc.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. * Copyright (c) 2012, 2023 SAP SE. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -236,7 +236,7 @@ bool PosixSignals::pd_hotspot_signal_handler(int sig, siginfo_t* info, ((NativeInstruction*)pc)->is_safepoint_poll() && CodeCache::contains((void*) pc) && ((cb = CodeCache::find_blob(pc)) != nullptr) && - cb->is_compiled()) { + cb->is_nmethod()) { if (TraceTraps) { tty->print_cr("trap: safepoint_poll at " INTPTR_FORMAT " (%s)", p2i(pc), USE_POLL_BIT_ONLY ? "SIGTRAP" : "SIGSEGV"); @@ -249,7 +249,7 @@ bool PosixSignals::pd_hotspot_signal_handler(int sig, siginfo_t* info, ((NativeInstruction*)pc)->is_safepoint_poll_return() && CodeCache::contains((void*) pc) && ((cb = CodeCache::find_blob(pc)) != nullptr) && - cb->is_compiled()) { + cb->is_nmethod()) { if (TraceTraps) { tty->print_cr("trap: safepoint_poll at return at " INTPTR_FORMAT " (nmethod)", p2i(pc)); } @@ -339,7 +339,7 @@ bool PosixSignals::pd_hotspot_signal_handler(int sig, siginfo_t* info, // BugId 4454115: A read from a MappedByteBuffer can fault here if the // underlying file has been truncated. Do not crash the VM in such a case. CodeBlob* cb = CodeCache::find_blob(pc); - CompiledMethod* nm = cb ? cb->as_compiled_method_or_null() : nullptr; + nmethod* nm = cb ? cb->as_nmethod_or_null() : nullptr; bool is_unsafe_arraycopy = (thread->doing_unsafe_access() && UnsafeCopyMemory::contains_pc(pc)); if ((nm != nullptr && nm->has_unsafe_access()) || is_unsafe_arraycopy) { address next_pc = pc + 4; diff --git a/src/hotspot/os_cpu/bsd_aarch64/os_bsd_aarch64.cpp b/src/hotspot/os_cpu/bsd_aarch64/os_bsd_aarch64.cpp index 4750ed88056..3dfe9e30f79 100644 --- a/src/hotspot/os_cpu/bsd_aarch64/os_bsd_aarch64.cpp +++ b/src/hotspot/os_cpu/bsd_aarch64/os_bsd_aarch64.cpp @@ -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. * Copyright (c) 2014, Red Hat Inc. All rights reserved. * Copyright (c) 2021, Azul Systems, Inc. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. @@ -256,7 +256,7 @@ bool PosixSignals::pd_hotspot_signal_handler(int sig, siginfo_t* info, // here if the underlying file has been truncated. // Do not crash the VM in such a case. CodeBlob* cb = CodeCache::find_blob(pc); - CompiledMethod* nm = (cb != nullptr) ? cb->as_compiled_method_or_null() : nullptr; + nmethod* nm = (cb != nullptr) ? cb->as_nmethod_or_null() : nullptr; bool is_unsafe_arraycopy = (thread->doing_unsafe_access() && UnsafeCopyMemory::contains_pc(pc)); if ((nm != nullptr && nm->has_unsafe_access()) || is_unsafe_arraycopy) { address next_pc = pc + NativeCall::instruction_size; diff --git a/src/hotspot/os_cpu/bsd_x86/os_bsd_x86.cpp b/src/hotspot/os_cpu/bsd_x86/os_bsd_x86.cpp index c73e83996ff..593f6494540 100644 --- a/src/hotspot/os_cpu/bsd_x86/os_bsd_x86.cpp +++ b/src/hotspot/os_cpu/bsd_x86/os_bsd_x86.cpp @@ -440,7 +440,7 @@ bool PosixSignals::pd_hotspot_signal_handler(int sig, siginfo_t* info, // here if the underlying file has been truncated. // Do not crash the VM in such a case. CodeBlob* cb = CodeCache::find_blob(pc); - CompiledMethod* nm = (cb != nullptr) ? cb->as_compiled_method_or_null() : nullptr; + nmethod* nm = (cb != nullptr) ? cb->as_nmethod_or_null() : nullptr; bool is_unsafe_arraycopy = thread->doing_unsafe_access() && UnsafeCopyMemory::contains_pc(pc); if ((nm != nullptr && nm->has_unsafe_access()) || is_unsafe_arraycopy) { address next_pc = Assembler::locate_next_instruction(pc); diff --git a/src/hotspot/os_cpu/linux_aarch64/os_linux_aarch64.cpp b/src/hotspot/os_cpu/linux_aarch64/os_linux_aarch64.cpp index 3698896abb7..e1c9dc8a13a 100644 --- a/src/hotspot/os_cpu/linux_aarch64/os_linux_aarch64.cpp +++ b/src/hotspot/os_cpu/linux_aarch64/os_linux_aarch64.cpp @@ -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. * Copyright (c) 2014, Red Hat Inc. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -239,7 +239,7 @@ bool PosixSignals::pd_hotspot_signal_handler(int sig, siginfo_t* info, // here if the underlying file has been truncated. // Do not crash the VM in such a case. CodeBlob* cb = CodeCache::find_blob(pc); - CompiledMethod* nm = (cb != nullptr) ? cb->as_compiled_method_or_null() : nullptr; + nmethod* nm = (cb != nullptr) ? cb->as_nmethod_or_null() : nullptr; bool is_unsafe_arraycopy = (thread->doing_unsafe_access() && UnsafeCopyMemory::contains_pc(pc)); if ((nm != nullptr && nm->has_unsafe_access()) || is_unsafe_arraycopy) { address next_pc = pc + NativeCall::instruction_size; diff --git a/src/hotspot/os_cpu/linux_arm/os_linux_arm.cpp b/src/hotspot/os_cpu/linux_arm/os_linux_arm.cpp index 55127058843..6f9ac548ce1 100644 --- a/src/hotspot/os_cpu/linux_arm/os_linux_arm.cpp +++ b/src/hotspot/os_cpu/linux_arm/os_linux_arm.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 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 @@ -323,7 +323,7 @@ bool PosixSignals::pd_hotspot_signal_handler(int sig, siginfo_t* info, // here if the underlying file has been truncated. // Do not crash the VM in such a case. CodeBlob* cb = CodeCache::find_blob(pc); - CompiledMethod* nm = (cb != nullptr) ? cb->as_compiled_method_or_null() : nullptr; + nmethod* nm = (cb != nullptr) ? cb->as_nmethod_or_null() : nullptr; if ((nm != nullptr && nm->has_unsafe_access()) || (thread->doing_unsafe_access() && UnsafeCopyMemory::contains_pc(pc))) { unsafe_access = true; } diff --git a/src/hotspot/os_cpu/linux_ppc/os_linux_ppc.cpp b/src/hotspot/os_cpu/linux_ppc/os_linux_ppc.cpp index 0b666f29c31..55963b06806 100644 --- a/src/hotspot/os_cpu/linux_ppc/os_linux_ppc.cpp +++ b/src/hotspot/os_cpu/linux_ppc/os_linux_ppc.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. * Copyright (c) 2012, 2021 SAP SE. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -263,7 +263,7 @@ bool PosixSignals::pd_hotspot_signal_handler(int sig, siginfo_t* info, ((NativeInstruction*)pc)->is_safepoint_poll() && CodeCache::contains((void*) pc) && ((cb = CodeCache::find_blob(pc)) != nullptr) && - cb->is_compiled()) { + cb->is_nmethod()) { if (TraceTraps) { tty->print_cr("trap: safepoint_poll at " INTPTR_FORMAT " (%s)", p2i(pc), USE_POLL_BIT_ONLY ? "SIGTRAP" : "SIGSEGV"); @@ -275,7 +275,7 @@ bool PosixSignals::pd_hotspot_signal_handler(int sig, siginfo_t* info, ((NativeInstruction*)pc)->is_safepoint_poll_return() && CodeCache::contains((void*) pc) && ((cb = CodeCache::find_blob(pc)) != nullptr) && - cb->is_compiled()) { + cb->is_nmethod()) { if (TraceTraps) { tty->print_cr("trap: safepoint_poll at return at " INTPTR_FORMAT " (nmethod)", p2i(pc)); } @@ -354,7 +354,7 @@ bool PosixSignals::pd_hotspot_signal_handler(int sig, siginfo_t* info, // BugId 4454115: A read from a MappedByteBuffer can fault here if the // underlying file has been truncated. Do not crash the VM in such a case. CodeBlob* cb = CodeCache::find_blob(pc); - CompiledMethod* nm = (cb != nullptr) ? cb->as_compiled_method_or_null() : nullptr; + nmethod* nm = (cb != nullptr) ? cb->as_nmethod_or_null() : nullptr; bool is_unsafe_arraycopy = (thread->doing_unsafe_access() && UnsafeCopyMemory::contains_pc(pc)); if ((nm != nullptr && nm->has_unsafe_access()) || is_unsafe_arraycopy) { address next_pc = pc + 4; diff --git a/src/hotspot/os_cpu/linux_riscv/os_linux_riscv.cpp b/src/hotspot/os_cpu/linux_riscv/os_linux_riscv.cpp index 9f13e2bdd2c..079c3b42a9c 100644 --- a/src/hotspot/os_cpu/linux_riscv/os_linux_riscv.cpp +++ b/src/hotspot/os_cpu/linux_riscv/os_linux_riscv.cpp @@ -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. * Copyright (c) 2020, 2022, Huawei Technologies Co., Ltd. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -229,7 +229,7 @@ bool PosixSignals::pd_hotspot_signal_handler(int sig, siginfo_t* info, // here if the underlying file has been truncated. // Do not crash the VM in such a case. CodeBlob* cb = CodeCache::find_blob(pc); - CompiledMethod* nm = (cb != nullptr) ? cb->as_compiled_method_or_null() : nullptr; + nmethod* nm = (cb != nullptr) ? cb->as_nmethod_or_null() : nullptr; bool is_unsafe_arraycopy = (thread->doing_unsafe_access() && UnsafeCopyMemory::contains_pc(pc)); if ((nm != nullptr && nm->has_unsafe_access()) || is_unsafe_arraycopy) { address next_pc = Assembler::locate_next_instruction(pc); diff --git a/src/hotspot/os_cpu/linux_riscv/vm_version_linux_riscv.cpp b/src/hotspot/os_cpu/linux_riscv/vm_version_linux_riscv.cpp index 5c72b64b629..f74ed8c8f81 100644 --- a/src/hotspot/os_cpu/linux_riscv/vm_version_linux_riscv.cpp +++ b/src/hotspot/os_cpu/linux_riscv/vm_version_linux_riscv.cpp @@ -115,6 +115,15 @@ void VM_Version::setup_cpu_available_features() { int i = 0; while (_feature_list[i] != nullptr) { if (_feature_list[i]->enabled()) { + // Change flag default + _feature_list[i]->update_flag(); + + // Feature will be disabled by update_flag() if flag + // is set to false by the user on the command line. + if (!_feature_list[i]->enabled()) { + continue; + } + log_debug(os, cpu)("Enabled RV64 feature \"%s\" (%ld)", _feature_list[i]->pretty(), _feature_list[i]->value()); @@ -139,8 +148,6 @@ void VM_Version::setup_cpu_available_features() { if (_feature_list[i]->feature_bit() != 0) { _features |= _feature_list[i]->feature_bit(); } - // Change flag default - _feature_list[i]->update_flag(); } i++; } diff --git a/src/hotspot/os_cpu/linux_s390/os_linux_s390.cpp b/src/hotspot/os_cpu/linux_s390/os_linux_s390.cpp index 5aa65e705d9..9ac1152a013 100644 --- a/src/hotspot/os_cpu/linux_s390/os_linux_s390.cpp +++ b/src/hotspot/os_cpu/linux_s390/os_linux_s390.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. * Copyright (c) 2016, 2023 SAP SE. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -309,7 +309,7 @@ bool PosixSignals::pd_hotspot_signal_handler(int sig, siginfo_t* info, // BugId 4454115: A read from a MappedByteBuffer can fault here if the // underlying file has been truncated. Do not crash the VM in such a case. CodeBlob* cb = CodeCache::find_blob(pc); - CompiledMethod* nm = (cb != nullptr) ? cb->as_compiled_method_or_null() : nullptr; + nmethod* nm = (cb != nullptr) ? cb->as_nmethod_or_null() : nullptr; if (nm != nullptr && nm->has_unsafe_access()) { // We don't really need a stub here! Just set the pending exception and // continue at the next instruction after the faulting read. Returning diff --git a/src/hotspot/os_cpu/linux_x86/os_linux_x86.cpp b/src/hotspot/os_cpu/linux_x86/os_linux_x86.cpp index 4dcaedf71da..b37a8d1f3a6 100644 --- a/src/hotspot/os_cpu/linux_x86/os_linux_x86.cpp +++ b/src/hotspot/os_cpu/linux_x86/os_linux_x86.cpp @@ -259,7 +259,7 @@ bool PosixSignals::pd_hotspot_signal_handler(int sig, siginfo_t* info, // here if the underlying file has been truncated. // Do not crash the VM in such a case. CodeBlob* cb = CodeCache::find_blob(pc); - CompiledMethod* nm = (cb != nullptr) ? cb->as_compiled_method_or_null() : nullptr; + nmethod* nm = (cb != nullptr) ? cb->as_nmethod_or_null() : nullptr; bool is_unsafe_arraycopy = thread->doing_unsafe_access() && UnsafeCopyMemory::contains_pc(pc); if ((nm != nullptr && nm->has_unsafe_access()) || is_unsafe_arraycopy) { address next_pc = Assembler::locate_next_instruction(pc); diff --git a/src/hotspot/share/c1/c1_LIRGenerator.cpp b/src/hotspot/share/c1/c1_LIRGenerator.cpp index 7335e521474..1cb350f1e39 100644 --- a/src/hotspot/share/c1/c1_LIRGenerator.cpp +++ b/src/hotspot/share/c1/c1_LIRGenerator.cpp @@ -1323,9 +1323,9 @@ void LIRGenerator::do_getModifiers(Intrinsic* x) { // from the primitive class itself. See spec for Class.getModifiers that provides // the typed array klasses with similar modifiers as their component types. - Klass* univ_klass_obj = Universe::byteArrayKlassObj(); - assert(univ_klass_obj->modifier_flags() == (JVM_ACC_ABSTRACT | JVM_ACC_FINAL | JVM_ACC_PUBLIC), "Sanity"); - LIR_Opr prim_klass = LIR_OprFact::metadataConst(univ_klass_obj); + Klass* univ_klass = Universe::byteArrayKlass(); + assert(univ_klass->modifier_flags() == (JVM_ACC_ABSTRACT | JVM_ACC_FINAL | JVM_ACC_PUBLIC), "Sanity"); + LIR_Opr prim_klass = LIR_OprFact::metadataConst(univ_klass); LIR_Opr recv_klass = new_register(T_METADATA); __ move(new LIR_Address(receiver.result(), java_lang_Class::klass_offset(), T_ADDRESS), recv_klass, info); diff --git a/src/hotspot/share/cds/archiveHeapWriter.cpp b/src/hotspot/share/cds/archiveHeapWriter.cpp index 458993f15d7..a86996d3b1f 100644 --- a/src/hotspot/share/cds/archiveHeapWriter.cpp +++ b/src/hotspot/share/cds/archiveHeapWriter.cpp @@ -41,7 +41,6 @@ #include "runtime/java.hpp" #include "runtime/mutexLocker.hpp" #include "utilities/bitMap.inline.hpp" - #if INCLUDE_G1GC #include "gc/g1/g1CollectedHeap.hpp" #include "gc/g1/g1HeapRegion.hpp" @@ -62,7 +61,7 @@ address ArchiveHeapWriter::_requested_top; GrowableArrayCHeap* ArchiveHeapWriter::_native_pointers; GrowableArrayCHeap* ArchiveHeapWriter::_source_objs; -GrowableArrayCHeap* ArchiveHeapWriter::_source_objs_order; +GrowableArrayCHeap* ArchiveHeapWriter::_source_objs_order; ArchiveHeapWriter::BufferOffsetToSourceObjectTable* ArchiveHeapWriter::_buffer_offset_to_source_obj_table = nullptr; @@ -79,14 +78,13 @@ void ArchiveHeapWriter::init() { if (HeapShared::can_write()) { Universe::heap()->collect(GCCause::_java_lang_system_gc); - _buffer_offset_to_source_obj_table = new BufferOffsetToSourceObjectTable(); + _buffer_offset_to_source_obj_table = new BufferOffsetToSourceObjectTable(/*size (prime)*/36137, /*max size*/1 * M); _fillers = new FillersTable(); _requested_bottom = nullptr; _requested_top = nullptr; _native_pointers = new GrowableArrayCHeap(2048); _source_objs = new GrowableArrayCHeap(10000); - _source_objs_order = new GrowableArrayCHeap(10000); guarantee(UseG1GC, "implementation limitation"); guarantee(MIN_GC_REGION_ALIGNMENT <= /*G1*/HeapRegion::min_region_size_in_words() * HeapWordSize, "must be"); @@ -94,7 +92,6 @@ void ArchiveHeapWriter::init() { } void ArchiveHeapWriter::add_source_obj(oop src_obj) { - _source_objs_order->append(_source_objs->length()); _source_objs->append(src_obj); } @@ -188,7 +185,7 @@ void ArchiveHeapWriter::ensure_buffer_space(size_t min_bytes) { } void ArchiveHeapWriter::copy_roots_to_buffer(GrowableArrayCHeap* roots) { - Klass* k = Universe::objectArrayKlassObj(); // already relocated to point to archived klass + Klass* k = Universe::objectArrayKlass(); // already relocated to point to archived klass int length = roots->length(); _heap_roots_word_size = objArrayOopDesc::object_size(length); size_t byte_size = _heap_roots_word_size * HeapWordSize; @@ -231,17 +228,17 @@ void ArchiveHeapWriter::copy_roots_to_buffer(GrowableArrayCHeapat(*a); - oop ob = _source_objs->at(*b); - - int rank_a = oop_sorting_rank(oa); - int rank_b = oop_sorting_rank(ob); +int ArchiveHeapWriter::compare_objs_by_oop_fields(HeapObjOrder* a, HeapObjOrder* b) { + int rank_a = a->_rank; + int rank_b = b->_rank; if (rank_a != rank_b) { return rank_a - rank_b; } else { // If they are the same rank, sort them by their position in the _source_objs array - return *a - *b; + return a->_index - b->_index; } } void ArchiveHeapWriter::sort_source_objs() { + log_info(cds)("sorting heap objects"); + int len = _source_objs->length(); + _source_objs_order = new GrowableArrayCHeap(len); + + for (int i = 0; i < len; i++) { + oop o = _source_objs->at(i); + int rank = oop_sorting_rank(o); + HeapObjOrder os = {i, rank}; + _source_objs_order->append(os); + } + log_info(cds)("computed ranks"); _source_objs_order->sort(compare_objs_by_oop_fields); + log_info(cds)("sorting heap objects done"); } void ArchiveHeapWriter::copy_source_objs_to_buffer(GrowableArrayCHeap* roots) { sort_source_objs(); for (int i = 0; i < _source_objs_order->length(); i++) { - int src_obj_index = _source_objs_order->at(i); + int src_obj_index = _source_objs_order->at(i)._index; oop src_obj = _source_objs->at(src_obj_index); HeapShared::CachedOopInfo* info = HeapShared::archived_object_cache()->get(src_obj); assert(info != nullptr, "must be"); size_t buffer_offset = copy_one_source_obj_to_buffer(src_obj); info->set_buffer_offset(buffer_offset); - _buffer_offset_to_source_obj_table->put(buffer_offset, src_obj); + _buffer_offset_to_source_obj_table->put_when_absent(buffer_offset, src_obj); + _buffer_offset_to_source_obj_table->maybe_grow(); } copy_roots_to_buffer(roots); @@ -315,7 +322,7 @@ int ArchiveHeapWriter::filler_array_length(size_t fill_bytes) { HeapWord* ArchiveHeapWriter::init_filler_array_at_buffer_top(int array_length, size_t fill_bytes) { assert(UseCompressedClassPointers, "Archived heap only supported for compressed klasses"); - Klass* oak = Universe::objectArrayKlassObj(); // already relocated to point to archived klass + Klass* oak = Universe::objectArrayKlass(); // already relocated to point to archived klass HeapWord* mem = offset_to_buffered_address(_buffer_used); memset(mem, 0, fill_bytes); oopDesc::set_mark(mem, markWord::prototype()); @@ -580,7 +587,7 @@ void ArchiveHeapWriter::relocate_embedded_oops(GrowableArrayCHeapoopmap()->resize(heap_region_byte_size / oopmap_unit); for (int i = 0; i < _source_objs_order->length(); i++) { - int src_obj_index = _source_objs_order->at(i); + int src_obj_index = _source_objs_order->at(i)._index; oop src_obj = _source_objs->at(src_obj_index); HeapShared::CachedOopInfo* info = HeapShared::archived_object_cache()->get(src_obj); assert(info != nullptr, "must be"); @@ -594,7 +601,7 @@ void ArchiveHeapWriter::relocate_embedded_oops(GrowableArrayCHeaplength() : 0; for (int i = 0; i < length; i++) { if (UseCompressedOops) { diff --git a/src/hotspot/share/cds/archiveHeapWriter.hpp b/src/hotspot/share/cds/archiveHeapWriter.hpp index 3acb8753877..99d5294007f 100644 --- a/src/hotspot/share/cds/archiveHeapWriter.hpp +++ b/src/hotspot/share/cds/archiveHeapWriter.hpp @@ -140,10 +140,21 @@ class ArchiveHeapWriter : AllStatic { static GrowableArrayCHeap* _native_pointers; static GrowableArrayCHeap* _source_objs; - static GrowableArrayCHeap* _source_objs_order; - typedef ResourceHashtableat(_source_objs_order->at(0)._index) + // source_objs->at(_source_objs_order->at(1)._index) + // source_objs->at(_source_objs_order->at(2)._index) + // ... + struct HeapObjOrder { + int _index; // The location of this object in _source_objs + int _rank; // A lower rank means the object will be written at a lower location. + }; + static GrowableArrayCHeap* _source_objs_order; + + typedef ResizeableResourceHashtable BufferOffsetToSourceObjectTable; static BufferOffsetToSourceObjectTable* _buffer_offset_to_source_obj_table; @@ -212,7 +223,7 @@ class ArchiveHeapWriter : AllStatic { static void update_header_for_requested_obj(oop requested_obj, oop src_obj, Klass* src_klass); - static int compare_objs_by_oop_fields(int* a, int* b); + static int compare_objs_by_oop_fields(HeapObjOrder* a, HeapObjOrder* b); static void sort_source_objs(); public: diff --git a/src/hotspot/share/cds/dynamicArchive.cpp b/src/hotspot/share/cds/dynamicArchive.cpp index 9f265520686..cd5dd88b099 100644 --- a/src/hotspot/share/cds/dynamicArchive.cpp +++ b/src/hotspot/share/cds/dynamicArchive.cpp @@ -180,7 +180,7 @@ class DynamicArchiveBuilder : public ArchiveBuilder { void iterate_primitive_array_klasses(MetaspaceClosure* it) { for (int i = T_BOOLEAN; i <= T_LONG; i++) { assert(is_java_primitive((BasicType)i), "sanity"); - Klass* k = Universe::typeArrayKlassObj((BasicType)i); // this give you "[I", etc + Klass* k = Universe::typeArrayKlass((BasicType)i); // this give you "[I", etc assert(MetaspaceShared::is_shared_static((void*)k), "one-dimensional primitive array should be in static archive"); ArrayKlass* ak = ArrayKlass::cast(k); diff --git a/src/hotspot/share/cds/filemap.cpp b/src/hotspot/share/cds/filemap.cpp index 97f0e58030a..2b35e64c264 100644 --- a/src/hotspot/share/cds/filemap.cpp +++ b/src/hotspot/share/cds/filemap.cpp @@ -2227,11 +2227,11 @@ void FileMapInfo::fixup_mapped_heap_region() { if (ArchiveHeapLoader::is_mapped()) { assert(!_mapped_heap_memregion.is_empty(), "sanity"); - // Populate the archive regions' G1BlockOffsetTableParts. That ensures - // fast G1BlockOffsetTablePart::block_start operations for any given address + // Populate the archive regions' G1BlockOffsetTables. That ensures + // fast G1BlockOffsetTable::block_start operations for any given address // within the archive regions when trying to find start of an object // (e.g. during card table scanning). - G1CollectedHeap::heap()->populate_archive_regions_bot_part(_mapped_heap_memregion); + G1CollectedHeap::heap()->populate_archive_regions_bot(_mapped_heap_memregion); } } diff --git a/src/hotspot/share/cds/heapShared.cpp b/src/hotspot/share/cds/heapShared.cpp index 46af33af146..a9dd5de9f4a 100644 --- a/src/hotspot/share/cds/heapShared.cpp +++ b/src/hotspot/share/cds/heapShared.cpp @@ -285,7 +285,8 @@ bool HeapShared::archive_object(oop obj) { // making the archive reproducible. obj->identity_hash(); CachedOopInfo info = make_cached_oop_info(obj); - archived_object_cache()->put(obj, info); + archived_object_cache()->put_when_absent(obj, info); + archived_object_cache()->maybe_grow(); mark_native_pointers(obj); if (log_is_enabled(Debug, cds, heap)) { @@ -443,16 +444,11 @@ void HeapShared::mark_native_pointers(oop orig_obj) { } } -bool HeapShared::has_oop_pointers(oop src_obj) { +void HeapShared::get_pointer_info(oop src_obj, bool& has_oop_pointers, bool& has_native_pointers) { CachedOopInfo* info = archived_object_cache()->get(src_obj); assert(info != nullptr, "must be"); - return info->has_oop_pointers(); -} - -bool HeapShared::has_native_pointers(oop src_obj) { - CachedOopInfo* info = archived_object_cache()->get(src_obj); - assert(info != nullptr, "must be"); - return info->has_native_pointers(); + has_oop_pointers = info->has_oop_pointers(); + has_native_pointers = info->has_native_pointers(); } void HeapShared::set_has_native_pointers(oop src_obj) { @@ -691,7 +687,7 @@ void KlassSubGraphInfo::add_subgraph_object_klass(Klass* orig_k) { "must be boot class"); check_allowed_klass(InstanceKlass::cast(ObjArrayKlass::cast(orig_k)->bottom_klass())); } - if (buffered_k == Universe::objectArrayKlassObj()) { + if (buffered_k == Universe::objectArrayKlass()) { // Initialized early during Universe::genesis. No need to be added // to the list. return; @@ -1424,7 +1420,8 @@ bool HeapShared::has_been_seen_during_subgraph_recording(oop obj) { void HeapShared::set_has_been_seen_during_subgraph_recording(oop obj) { assert(!has_been_seen_during_subgraph_recording(obj), "sanity"); - _seen_objects_table->put(obj, true); + _seen_objects_table->put_when_absent(obj, true); + _seen_objects_table->maybe_grow(); ++ _num_new_walked_objs; } @@ -1630,7 +1627,7 @@ bool HeapShared::is_a_test_class_in_unnamed_module(Klass* ik) { void HeapShared::init_for_dumping(TRAPS) { if (HeapShared::can_write()) { setup_test_class(ArchiveHeapTestClass); - _dumped_interned_strings = new (mtClass)DumpedInternedStrings(); + _dumped_interned_strings = new (mtClass)DumpedInternedStrings(INITIAL_TABLE_SIZE, MAX_TABLE_SIZE); init_subgraph_entry_fields(CHECK); } } @@ -1696,6 +1693,9 @@ void HeapShared::add_to_dumped_interned_strings(oop string) { assert(!ArchiveHeapWriter::is_string_too_large_to_archive(string), "must be"); bool created; _dumped_interned_strings->put_if_absent(string, true, &created); + if (created) { + _dumped_interned_strings->maybe_grow(); + } } #ifndef PRODUCT diff --git a/src/hotspot/share/cds/heapShared.hpp b/src/hotspot/share/cds/heapShared.hpp index f66de5c5e95..aa8c1dd3bc4 100644 --- a/src/hotspot/share/cds/heapShared.hpp +++ b/src/hotspot/share/cds/heapShared.hpp @@ -215,8 +215,9 @@ class HeapShared: AllStatic { static void check_enum_obj(int level, KlassSubGraphInfo* subgraph_info, oop orig_obj); - typedef ResourceHashtable ArchivedObjectCache; @@ -277,8 +278,7 @@ class HeapShared: AllStatic { // !UseCompressedOops only: used to relocate pointers to the archived objects static ptrdiff_t _runtime_delta; - typedef ResourceHashtable SeenObjectsTable; @@ -300,7 +300,7 @@ class HeapShared: AllStatic { static void init_seen_objects_table() { assert(_seen_objects_table == nullptr, "must be"); - _seen_objects_table = new (mtClass)SeenObjectsTable(); + _seen_objects_table = new (mtClass)SeenObjectsTable(INITIAL_TABLE_SIZE, MAX_TABLE_SIZE); } static void delete_seen_objects_table() { assert(_seen_objects_table != nullptr, "must be"); @@ -355,7 +355,7 @@ class HeapShared: AllStatic { static void reset_archived_object_states(TRAPS); static void create_archived_object_cache() { _archived_object_cache = - new (mtClass)ArchivedObjectCache(); + new (mtClass)ArchivedObjectCache(INITIAL_TABLE_SIZE, MAX_TABLE_SIZE); } static void destroy_archived_object_cache() { delete _archived_object_cache; @@ -380,9 +380,8 @@ class HeapShared: AllStatic { // Scratch objects for archiving Klass::java_mirror() static void set_scratch_java_mirror(Klass* k, oop mirror); static void remove_scratch_objects(Klass* k); - static bool has_oop_pointers(oop obj); - static bool has_native_pointers(oop obj); - static void set_has_native_pointers(oop obj); + static void get_pointer_info(oop src_obj, bool& has_oop_pointers, bool& has_native_pointers); + static void set_has_native_pointers(oop src_obj); // We use the HeapShared::roots() array to make sure that objects stored in the // archived heap region are not prematurely collected. These roots include: @@ -436,12 +435,18 @@ class HeapShared: AllStatic { #if INCLUDE_CDS_JAVA_HEAP class DumpedInternedStrings : - public ResourceHashtable -{}; +{ +public: + DumpedInternedStrings(unsigned size, unsigned max_size) : + ResizeableResourceHashtable(size, max_size) {} +}; #endif #endif // SHARE_CDS_HEAPSHARED_HPP diff --git a/src/hotspot/share/ci/ciEnv.cpp b/src/hotspot/share/ci/ciEnv.cpp index caf92cd0bfc..40abaa06df2 100644 --- a/src/hotspot/share/ci/ciEnv.cpp +++ b/src/hotspot/share/ci/ciEnv.cpp @@ -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 @@ -1142,7 +1142,7 @@ void ciEnv::register_method(ciMethod* target, if (entry_bci == InvocationEntryBci) { // If there is an old version we're done with it - CompiledMethod* old = method->code(); + nmethod* old = method->code(); if (TraceMethodReplacement && old != nullptr) { ResourceMark rm; char *method_name = method->name_and_sig_as_C_string(); @@ -1160,7 +1160,7 @@ void ciEnv::register_method(ciMethod* target, task()->comp_level(), method_name); } // Allow the code to be executed - MutexLocker ml(CompiledMethod_lock, Mutex::_no_safepoint_check_flag); + MutexLocker ml(NMethodState_lock, Mutex::_no_safepoint_check_flag); if (nm->make_in_use()) { method->set_code(method, nm); } @@ -1172,7 +1172,7 @@ void ciEnv::register_method(ciMethod* target, lt.print("Installing osr method (%d) %s @ %d", task()->comp_level(), method_name, entry_bci); } - MutexLocker ml(CompiledMethod_lock, Mutex::_no_safepoint_check_flag); + MutexLocker ml(NMethodState_lock, Mutex::_no_safepoint_check_flag); if (nm->make_in_use()) { method->method_holder()->add_osr_nmethod(nm); } diff --git a/src/hotspot/share/ci/ciMethod.cpp b/src/hotspot/share/ci/ciMethod.cpp index d54e8a4d697..0b41a257a4b 100644 --- a/src/hotspot/share/ci/ciMethod.cpp +++ b/src/hotspot/share/ci/ciMethod.cpp @@ -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 @@ -1129,7 +1129,7 @@ int ciMethod::code_size_for_inlining() { int ciMethod::inline_instructions_size() { if (_inline_instructions_size == -1) { GUARDED_VM_ENTRY( - CompiledMethod* code = get_Method()->code(); + nmethod* code = get_Method()->code(); if (code != nullptr && (code->comp_level() == CompLevel_full_optimization)) { int isize = code->insts_end() - code->verified_entry_point() - code->skipped_instructions_size(); _inline_instructions_size = isize > 0 ? isize : 0; @@ -1145,7 +1145,7 @@ int ciMethod::inline_instructions_size() { // ciMethod::log_nmethod_identity void ciMethod::log_nmethod_identity(xmlStream* log) { GUARDED_VM_ENTRY( - CompiledMethod* code = get_Method()->code(); + nmethod* code = get_Method()->code(); if (code != nullptr) { code->log_identity(log); } diff --git a/src/hotspot/share/ci/ciObjectFactory.cpp b/src/hotspot/share/ci/ciObjectFactory.cpp index ee099f46664..2008ccbc1bc 100644 --- a/src/hotspot/share/ci/ciObjectFactory.cpp +++ b/src/hotspot/share/ci/ciObjectFactory.cpp @@ -180,14 +180,14 @@ void ciObjectFactory::init_shared_objects() { init_ident_of(ciEnv::_unloaded_ciobjarrayklass); assert(ciEnv::_unloaded_ciobjarrayklass->is_obj_array_klass(), "just checking"); - get_metadata(Universe::boolArrayKlassObj()); - get_metadata(Universe::charArrayKlassObj()); - get_metadata(Universe::floatArrayKlassObj()); - get_metadata(Universe::doubleArrayKlassObj()); - get_metadata(Universe::byteArrayKlassObj()); - get_metadata(Universe::shortArrayKlassObj()); - get_metadata(Universe::intArrayKlassObj()); - get_metadata(Universe::longArrayKlassObj()); + get_metadata(Universe::boolArrayKlass()); + get_metadata(Universe::charArrayKlass()); + get_metadata(Universe::floatArrayKlass()); + get_metadata(Universe::doubleArrayKlass()); + get_metadata(Universe::byteArrayKlass()); + get_metadata(Universe::shortArrayKlass()); + get_metadata(Universe::intArrayKlass()); + get_metadata(Universe::longArrayKlass()); assert(_non_perm_count == 0, "no shared non-perm objects"); diff --git a/src/hotspot/share/ci/ciReplay.cpp b/src/hotspot/share/ci/ciReplay.cpp index 449d49a2368..6edbadcec4f 100644 --- a/src/hotspot/share/ci/ciReplay.cpp +++ b/src/hotspot/share/ci/ciReplay.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 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 @@ -804,7 +804,7 @@ class CompileReplay : public StackObj { } } // Make sure the existence of a prior compile doesn't stop this one - CompiledMethod* nm = (entry_bci != InvocationEntryBci) ? method->lookup_osr_nmethod_for(entry_bci, comp_level, true) : method->code(); + nmethod* nm = (entry_bci != InvocationEntryBci) ? method->lookup_osr_nmethod_for(entry_bci, comp_level, true) : method->code(); if (nm != nullptr) { nm->make_not_entrant(); } diff --git a/src/hotspot/share/ci/ciTypeArrayKlass.cpp b/src/hotspot/share/ci/ciTypeArrayKlass.cpp index 405b5c48f38..11aef8b57e6 100644 --- a/src/hotspot/share/ci/ciTypeArrayKlass.cpp +++ b/src/hotspot/share/ci/ciTypeArrayKlass.cpp @@ -44,7 +44,7 @@ ciTypeArrayKlass::ciTypeArrayKlass(Klass* k) : ciArrayKlass(k) { // // Implementation of make. ciTypeArrayKlass* ciTypeArrayKlass::make_impl(BasicType t) { - Klass* k = Universe::typeArrayKlassObj(t); + Klass* k = Universe::typeArrayKlass(t); return CURRENT_ENV->get_type_array_klass(k); } diff --git a/src/hotspot/share/classfile/bytecodeAssembler.cpp b/src/hotspot/share/classfile/bytecodeAssembler.cpp index 0ddc6282806..e1e54b56e41 100644 --- a/src/hotspot/share/classfile/bytecodeAssembler.cpp +++ b/src/hotspot/share/classfile/bytecodeAssembler.cpp @@ -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,31 +33,63 @@ #include "utilities/bytes.hpp" #include "utilities/checkedCast.hpp" +void BytecodeConstantPool::init() { + for (int i = 1; i < _orig->length(); i++) { + BytecodeCPEntry entry; + switch(_orig->tag_at(i).value()) { + case JVM_CONSTANT_Class: + case JVM_CONSTANT_UnresolvedClass: + entry = BytecodeCPEntry::klass(_orig->klass_slot_at(i).name_index()); + break; + case JVM_CONSTANT_Utf8: + entry = BytecodeCPEntry::utf8(_orig->symbol_at(i)); + break; + case JVM_CONSTANT_NameAndType: + entry = BytecodeCPEntry::name_and_type(_orig->name_ref_index_at(i), _orig->signature_ref_index_at(i)); + break; + case JVM_CONSTANT_Methodref: + entry = BytecodeCPEntry::methodref(_orig->uncached_klass_ref_index_at(i), _orig->uncached_name_and_type_ref_index_at(i)); + break; + case JVM_CONSTANT_String: + entry = BytecodeCPEntry::string(_orig->unresolved_string_at(i)); + break; + } + if (entry._tag != BytecodeCPEntry::tag::ERROR_TAG) { + bool created = false; + _index_map.put_if_absent(entry, i, &created); + if (created) { + _orig_cp_added += 1; + _added_entries.append(entry); + } + } + } +} + u2 BytecodeConstantPool::find_or_add(BytecodeCPEntry const& bcpe, TRAPS) { // Check for overflow - int new_size = _orig->length() + _entries.length(); + int new_size = _orig->length() + _added_entries.length() - _orig_cp_added; if (new_size > USHRT_MAX) { THROW_MSG_0(vmSymbols::java_lang_InternalError(), "default methods constant pool overflowed"); } - u2 index = checked_cast(_entries.length()); + u2 index = checked_cast(new_size); bool created = false; - u2* probe = _indices.put_if_absent(bcpe, index, &created); + u2* probe = _index_map.put_if_absent(bcpe, index, &created); if (created) { - _entries.append(bcpe); + _added_entries.append(bcpe); } else { index = *probe; } - return checked_cast(index + _orig->length()); + return index; } ConstantPool* BytecodeConstantPool::create_constant_pool(TRAPS) const { - if (_entries.length() == 0) { + if (_added_entries.length() == 0) { return _orig; } - int new_size = _orig->length() + _entries.length(); + int new_size = _orig->length() + _added_entries.length() - _orig_cp_added; ConstantPool* cp = ConstantPool::allocate( _orig->pool_holder()->class_loader_data(), new_size, CHECK_NULL); @@ -69,9 +101,13 @@ ConstantPool* BytecodeConstantPool::create_constant_pool(TRAPS) const { // Preserve dynamic constant information from the original pool cp->copy_fields(_orig); - for (int i = 0; i < _entries.length(); ++i) { - BytecodeCPEntry entry = _entries.at(i); - int idx = i + _orig->length(); + for (int i = _orig_cp_added; i < _added_entries.length(); ++i) { + // Add new entries that we added to the temporary constant pool, to the + // newly creatd constant pool. + BytecodeCPEntry entry = _added_entries.at(i); + // Get the constant pool index saved in the hashtable for this new entry. + u2* value = _index_map.get(entry); + int idx = *value; switch (entry._tag) { case BytecodeCPEntry::UTF8: entry._u.utf8->increment_refcount(); @@ -83,7 +119,7 @@ ConstantPool* BytecodeConstantPool::create_constant_pool(TRAPS) const { break; case BytecodeCPEntry::STRING: cp->unresolved_string_at_put( - idx, cp->symbol_at(entry._u.string)); + idx, entry._u.utf8); break; case BytecodeCPEntry::NAME_AND_TYPE: cp->name_and_type_at_put(idx, diff --git a/src/hotspot/share/classfile/bytecodeAssembler.hpp b/src/hotspot/share/classfile/bytecodeAssembler.hpp index 4505db28aef..fb51924a9c6 100644 --- a/src/hotspot/share/classfile/bytecodeAssembler.hpp +++ b/src/hotspot/share/classfile/bytecodeAssembler.hpp @@ -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 @@ -66,7 +66,6 @@ class BytecodeCPEntry { union { Symbol* utf8; u2 klass; - u2 string; struct { u2 name_index; u2 type_index; @@ -93,9 +92,9 @@ class BytecodeCPEntry { return bcpe; } - static BytecodeCPEntry string(u2 index) { + static BytecodeCPEntry string(Symbol* symbol) { BytecodeCPEntry bcpe(STRING); - bcpe._u.string = index; + bcpe._u.utf8 = symbol; return bcpe; } @@ -114,6 +113,8 @@ class BytecodeCPEntry { } static bool equals(BytecodeCPEntry const& e0, BytecodeCPEntry const& e1) { + // The hash is the "union trick" value of the information saved for the tag, + // so can be compared for equality. return e0._tag == e1._tag && e0._u.hash == e1._u.hash; } @@ -122,23 +123,27 @@ class BytecodeCPEntry { } }; -class BytecodeConstantPool : ResourceObj { +class BytecodeConstantPool : public ResourceObj { private: typedef ResourceHashtable IndexHash; ConstantPool* _orig; - GrowableArray _entries; - IndexHash _indices; + GrowableArray _added_entries; + IndexHash _index_map; + int _orig_cp_added; u2 find_or_add(BytecodeCPEntry const& bcpe, TRAPS); + void init(); public: - BytecodeConstantPool(ConstantPool* orig) : _orig(orig) {} + BytecodeConstantPool(ConstantPool* orig) : _orig(orig), _orig_cp_added(0) { + init(); + } - BytecodeCPEntry const& at(u2 index) const { return _entries.at(index); } + BytecodeCPEntry const& at(u2 index) const { return _added_entries.at(index); } InstanceKlass* pool_holder() const { return _orig->pool_holder(); @@ -154,8 +159,9 @@ class BytecodeConstantPool : ResourceObj { } u2 string(Symbol* str, TRAPS) { - u2 utf8_entry = utf8(str, CHECK_0); - return find_or_add(BytecodeCPEntry::string(utf8_entry), THREAD); + // Create the utf8_entry in the hashtable but use Symbol for matching. + (void)utf8(str, CHECK_0); + return find_or_add(BytecodeCPEntry::string(str), THREAD); } u2 name_and_type(Symbol* name, Symbol* sig, TRAPS) { diff --git a/src/hotspot/share/classfile/defaultMethods.cpp b/src/hotspot/share/classfile/defaultMethods.cpp index 60c75a44007..dd221efb409 100644 --- a/src/hotspot/share/classfile/defaultMethods.cpp +++ b/src/hotspot/share/classfile/defaultMethods.cpp @@ -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 @@ -939,9 +939,10 @@ static void create_defaults_and_exceptions(GrowableArray* slot GrowableArray overpasses; GrowableArray defaults; - BytecodeConstantPool bpool(klass->constants()); BytecodeBuffer* buffer = nullptr; // Lazily create a reusable buffer + BytecodeConstantPool* bpool = nullptr; + for (int i = 0; i < slots->length(); ++i) { EmptyVtableSlot* slot = slots->at(i); @@ -974,11 +975,15 @@ static void create_defaults_and_exceptions(GrowableArray* slot } else { buffer->clear(); } - int max_stack = BytecodeAssembler::assemble_method_error(&bpool, buffer, + // Lazily allocate bytecode constant pool also. + if (bpool == nullptr) { + bpool = new BytecodeConstantPool(klass->constants()); + } + int max_stack = BytecodeAssembler::assemble_method_error(bpool, buffer, method->get_exception_name(), method->get_exception_message(), CHECK); AccessFlags flags = accessFlags_from( JVM_ACC_PUBLIC | JVM_ACC_SYNTHETIC | JVM_ACC_BRIDGE); - Method* m = new_method(&bpool, buffer, slot->name(), slot->signature(), + Method* m = new_method(bpool, buffer, slot->name(), slot->signature(), flags, max_stack, slot->size_of_parameters(), ConstMethod::OVERPASS, CHECK); // We push to the methods list: @@ -995,7 +1000,7 @@ static void create_defaults_and_exceptions(GrowableArray* slot log_debug(defaultmethods)("Created %d default methods", defaults.length()); if (overpasses.length() > 0) { - switchover_constant_pool(&bpool, klass, &overpasses, CHECK); + switchover_constant_pool(bpool, klass, &overpasses, CHECK); merge_in_new_methods(klass, &overpasses, CHECK); } if (defaults.length() > 0) { diff --git a/src/hotspot/share/classfile/javaClasses.cpp b/src/hotspot/share/classfile/javaClasses.cpp index 39f0a9e4ba4..b942c155d1a 100644 --- a/src/hotspot/share/classfile/javaClasses.cpp +++ b/src/hotspot/share/classfile/javaClasses.cpp @@ -1259,7 +1259,7 @@ oop java_lang_Class::create_basic_type_mirror(const char* basic_type_name, Basic // introducing a new VM klass (see comment in ClassFileParser) oop java_class = InstanceMirrorKlass::cast(vmClasses::Class_klass())->allocate_instance(nullptr, CHECK_NULL); if (type != T_VOID) { - Klass* aklass = Universe::typeArrayKlassObj(type); + Klass* aklass = Universe::typeArrayKlass(type); assert(aklass != nullptr, "correct bootstrap"); release_set_array_klass(java_class, aklass); } @@ -2417,7 +2417,7 @@ static void print_stack_element_to_stream(outputStream* st, Handle mirror, int m // Neither sourcename nor linenumber buf_off += os::snprintf_checked(buf + buf_off, buf_size - buf_off, "Unknown Source)"); } - CompiledMethod* nm = method->code(); + nmethod* nm = method->code(); if (WizardMode && nm != nullptr) { os::snprintf_checked(buf + buf_off, buf_size - buf_off, "(nmethod " INTPTR_FORMAT ")", (intptr_t)nm); } @@ -2543,7 +2543,7 @@ void java_lang_Throwable::fill_in_stack_trace(Handle throwable, const methodHand RegisterMap::ProcessFrames::skip, RegisterMap::WalkContinuation::include); int decode_offset = 0; - CompiledMethod* nm = nullptr; + nmethod* nm = nullptr; bool skip_fillInStackTrace_check = false; bool skip_throwableInit_check = false; bool skip_hidden = !ShowHiddenFrames; @@ -2587,10 +2587,10 @@ void java_lang_Throwable::fill_in_stack_trace(Handle throwable, const methodHand // HMMM QQQ might be nice to have frame return nm as null if cb is non-null // but non nmethod fr = fr.sender(&map); - if (cb == nullptr || !cb->is_compiled()) { + if (cb == nullptr || !cb->is_nmethod()) { continue; } - nm = cb->as_compiled_method(); + nm = cb->as_nmethod(); assert(nm->method() != nullptr, "must be"); if (nm->method()->is_native()) { method = nm->method(); diff --git a/src/hotspot/share/classfile/systemDictionary.cpp b/src/hotspot/share/classfile/systemDictionary.cpp index f0c8e2a5524..6a8d2975059 100644 --- a/src/hotspot/share/classfile/systemDictionary.cpp +++ b/src/hotspot/share/classfile/systemDictionary.cpp @@ -367,8 +367,8 @@ Klass* SystemDictionary::resolve_array_class_or_null(Symbol* class_name, k = k->array_klass(ndims, CHECK_NULL); } } else { - k = Universe::typeArrayKlassObj(t); - k = TypeArrayKlass::cast(k)->array_klass(ndims, CHECK_NULL); + k = Universe::typeArrayKlass(t); + k = k->array_klass(ndims, CHECK_NULL); } return k; } @@ -782,7 +782,7 @@ Klass* SystemDictionary::find_instance_or_array_klass(Thread* current, int ndims = ss.skip_array_prefix(); // skip all '['s BasicType t = ss.type(); if (t != T_OBJECT) { - k = Universe::typeArrayKlassObj(t); + k = Universe::typeArrayKlass(t); } else { k = SystemDictionary::find_instance_klass(current, ss.as_symbol(), class_loader, protection_domain); } @@ -1727,7 +1727,7 @@ Klass* SystemDictionary::find_constrained_instance_or_array_klass( int ndims = ss.skip_array_prefix(); // skip all '['s BasicType t = ss.type(); if (t != T_OBJECT) { - klass = Universe::typeArrayKlassObj(t); + klass = Universe::typeArrayKlass(t); } else { MutexLocker mu(current, SystemDictionary_lock); klass = LoaderConstraintTable::find_constrained_klass(ss.as_symbol(), class_loader_data(class_loader)); diff --git a/src/hotspot/share/code/codeBehaviours.cpp b/src/hotspot/share/code/codeBehaviours.cpp index 279eca4738e..34fda41b0eb 100644 --- a/src/hotspot/share/code/codeBehaviours.cpp +++ b/src/hotspot/share/code/codeBehaviours.cpp @@ -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 @@ -29,7 +29,7 @@ CompiledICProtectionBehaviour* CompiledICProtectionBehaviour::_current = nullptr; -bool DefaultICProtectionBehaviour::lock(CompiledMethod* method) { +bool DefaultICProtectionBehaviour::lock(nmethod* method) { if (is_safe(method)) { return false; } @@ -37,10 +37,10 @@ bool DefaultICProtectionBehaviour::lock(CompiledMethod* method) { return true; } -void DefaultICProtectionBehaviour::unlock(CompiledMethod* method) { +void DefaultICProtectionBehaviour::unlock(nmethod* method) { CompiledIC_lock->unlock(); } -bool DefaultICProtectionBehaviour::is_safe(CompiledMethod* method) { +bool DefaultICProtectionBehaviour::is_safe(nmethod* method) { return SafepointSynchronize::is_at_safepoint() || CompiledIC_lock->owned_by_self(); } diff --git a/src/hotspot/share/code/codeBehaviours.hpp b/src/hotspot/share/code/codeBehaviours.hpp index f026957aa97..0350f5752f6 100644 --- a/src/hotspot/share/code/codeBehaviours.hpp +++ b/src/hotspot/share/code/codeBehaviours.hpp @@ -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 @@ -27,24 +27,24 @@ #include "memory/allocation.hpp" -class CompiledMethod; +class nmethod; class CompiledICProtectionBehaviour { static CompiledICProtectionBehaviour* _current; public: - virtual bool lock(CompiledMethod* method) = 0; - virtual void unlock(CompiledMethod* method) = 0; - virtual bool is_safe(CompiledMethod* method) = 0; + virtual bool lock(nmethod* method) = 0; + virtual void unlock(nmethod* method) = 0; + virtual bool is_safe(nmethod* method) = 0; static CompiledICProtectionBehaviour* current() { return _current; } static void set_current(CompiledICProtectionBehaviour* current) { _current = current; } }; class DefaultICProtectionBehaviour: public CompiledICProtectionBehaviour, public CHeapObj { - virtual bool lock(CompiledMethod* method); - virtual void unlock(CompiledMethod* method); - virtual bool is_safe(CompiledMethod* method); + virtual bool lock(nmethod* method); + virtual void unlock(nmethod* method); + virtual bool is_safe(nmethod* method); }; #endif // SHARE_CODE_CODEBEHAVIOURS_HPP diff --git a/src/hotspot/share/code/codeBlob.cpp b/src/hotspot/share/code/codeBlob.cpp index d24e29c288d..83418742988 100644 --- a/src/hotspot/share/code/codeBlob.cpp +++ b/src/hotspot/share/code/codeBlob.cpp @@ -54,9 +54,6 @@ #include "c1/c1_Runtime1.hpp" #endif -const char* CodeBlob::compiler_name() const { - return compilertype2name(_type); -} unsigned int CodeBlob::align_code_offset(int offset) { // align the size to CodeEntryAlignment @@ -64,7 +61,6 @@ unsigned int CodeBlob::align_code_offset(int offset) { return align_up(offset + header_size, CodeEntryAlignment) - header_size; } - // This must be consistent with the CodeBlob constructor's layout actions. unsigned int CodeBlob::allocation_size(CodeBuffer* cb, int header_size) { unsigned int size = header_size; @@ -77,86 +73,125 @@ unsigned int CodeBlob::allocation_size(CodeBuffer* cb, int header_size) { return size; } -CodeBlob::CodeBlob(const char* name, CompilerType type, const CodeBlobLayout& layout, int frame_complete_offset, int frame_size, ImmutableOopMapSet* oop_maps, bool caller_must_gc_arguments, bool compiled) : - _code_begin(layout.code_begin()), - _code_end(layout.code_end()), - _content_begin(layout.content_begin()), - _data_end(layout.data_end()), - _relocation_begin(layout.relocation_begin()), - _relocation_end(layout.relocation_end()), +#ifdef ASSERT +void CodeBlob::verify_parameters() { + assert(is_aligned(_size, oopSize), "unaligned size"); + assert(is_aligned(_header_size, oopSize), "unaligned size"); + assert(is_aligned(_relocation_size, oopSize), "unaligned size"); + assert(_data_offset <= size(), "codeBlob is too small"); + assert(code_end() == content_end(), "must be the same - see code_end()"); +#ifdef COMPILER1 + // probably wrong for tiered + assert(frame_size() >= -1, "must use frame size or -1 for runtime stubs"); +#endif // COMPILER1 +} +#endif + +CodeBlob::CodeBlob(const char* name, CodeBlobKind kind, int size, int header_size, int relocation_size, + int content_offset, int code_offset, int frame_complete_offset, int data_offset, + int frame_size, ImmutableOopMapSet* oop_maps, bool caller_must_gc_arguments) : _oop_maps(oop_maps), _name(name), - _size(layout.size()), - _header_size(layout.header_size()), + _size(size), + _header_size(header_size), + _relocation_size(relocation_size), + _content_offset(content_offset), + _code_offset(code_offset), _frame_complete_offset(frame_complete_offset), - _data_offset(layout.data_offset()), + _data_offset(data_offset), _frame_size(frame_size), - _caller_must_gc_arguments(caller_must_gc_arguments), - _is_compiled(compiled), - _type(type) + S390_ONLY(_ctable_offset(0) COMMA) + _kind(kind), + _caller_must_gc_arguments(caller_must_gc_arguments) { - assert(is_aligned(layout.size(), oopSize), "unaligned size"); - assert(is_aligned(layout.header_size(), oopSize), "unaligned size"); - assert(is_aligned(layout.relocation_size(), oopSize), "unaligned size"); - assert(layout.code_end() == layout.content_end(), "must be the same - see code_end()"); -#ifdef COMPILER1 - // probably wrong for tiered - assert(_frame_size >= -1, "must use frame size or -1 for runtime stubs"); -#endif // COMPILER1 - S390_ONLY(_ctable_offset = 0;) // avoid uninitialized fields + DEBUG_ONLY( verify_parameters(); ) } -CodeBlob::CodeBlob(const char* name, CompilerType type, const CodeBlobLayout& layout, CodeBuffer* cb /*UNUSED*/, int frame_complete_offset, int frame_size, OopMapSet* oop_maps, bool caller_must_gc_arguments, bool compiled) : - _code_begin(layout.code_begin()), - _code_end(layout.code_end()), - _content_begin(layout.content_begin()), - _data_end(layout.data_end()), - _relocation_begin(layout.relocation_begin()), - _relocation_end(layout.relocation_end()), +CodeBlob::CodeBlob(const char* name, CodeBlobKind kind, CodeBuffer* cb, int size, int header_size, + int frame_complete_offset, int frame_size, OopMapSet* oop_maps, bool caller_must_gc_arguments) : + _oop_maps(nullptr), // will be set by set_oop_maps() call _name(name), - _size(layout.size()), - _header_size(layout.header_size()), + _size(size), + _header_size(header_size), + _relocation_size(align_up(cb->total_relocation_size(), oopSize)), + _content_offset(CodeBlob::align_code_offset(_header_size + _relocation_size)), + _code_offset(_content_offset + cb->total_offset_of(cb->insts())), _frame_complete_offset(frame_complete_offset), - _data_offset(layout.data_offset()), + _data_offset(_content_offset + align_up(cb->total_content_size(), oopSize)), _frame_size(frame_size), - _caller_must_gc_arguments(caller_must_gc_arguments), - _is_compiled(compiled), - _type(type) + S390_ONLY(_ctable_offset(0) COMMA) + _kind(kind), + _caller_must_gc_arguments(caller_must_gc_arguments) { - assert(is_aligned(_size, oopSize), "unaligned size"); - assert(is_aligned(_header_size, oopSize), "unaligned size"); - assert(_data_offset <= _size, "codeBlob is too small"); - assert(layout.code_end() == layout.content_end(), "must be the same - see code_end()"); + DEBUG_ONLY( verify_parameters(); ) set_oop_maps(oop_maps); -#ifdef COMPILER1 - // probably wrong for tiered - assert(_frame_size >= -1, "must use frame size or -1 for runtime stubs"); -#endif // COMPILER1 - S390_ONLY(_ctable_offset = 0;) // avoid uninitialized fields } - -// Creates a simple CodeBlob. Sets up the size of the different regions. -RuntimeBlob::RuntimeBlob(const char* name, int header_size, int size, int frame_complete, int locs_size) - : CodeBlob(name, compiler_none, CodeBlobLayout((address) this, size, header_size, locs_size, size), frame_complete, 0, nullptr, false /* caller_must_gc_arguments */) +// Simple CodeBlob used for simple BufferBlob. +CodeBlob::CodeBlob(const char* name, CodeBlobKind kind, int size, int header_size) : + _oop_maps(nullptr), + _name(name), + _size(size), + _header_size(header_size), + _relocation_size(0), + _content_offset(CodeBlob::align_code_offset(header_size)), + _code_offset(_content_offset), + _frame_complete_offset(CodeOffsets::frame_never_safe), + _data_offset(size), + _frame_size(0), + S390_ONLY(_ctable_offset(0) COMMA) + _kind(kind), + _caller_must_gc_arguments(false) { - assert(is_aligned(locs_size, oopSize), "unaligned size"); + assert(is_aligned(size, oopSize), "unaligned size"); + assert(is_aligned(header_size, oopSize), "unaligned size"); } +void CodeBlob::purge(bool free_code_cache_data, bool unregister_nmethod) { + if (_oop_maps != nullptr) { + delete _oop_maps; + _oop_maps = nullptr; + } + NOT_PRODUCT(_asm_remarks.clear()); + NOT_PRODUCT(_dbg_strings.clear()); +} + +void CodeBlob::set_oop_maps(OopMapSet* p) { + // Danger Will Robinson! This method allocates a big + // chunk of memory, its your job to free it. + if (p != nullptr) { + _oop_maps = ImmutableOopMapSet::build_from(p); + } else { + _oop_maps = nullptr; + } +} + +const ImmutableOopMap* CodeBlob::oop_map_for_return_address(address return_address) const { + assert(_oop_maps != nullptr, "nope"); + return _oop_maps->find_map_at_offset((intptr_t) return_address - (intptr_t) code_begin()); +} + +void CodeBlob::print_code_on(outputStream* st) { + ResourceMark m; + Disassembler::decode(this, st); +} + +//----------------------------------------------------------------------------------------- +// Creates a RuntimeBlob from a CodeBuffer and copy code and relocation info. -// Creates a RuntimeBlob from a CodeBuffer -// and copy code and relocation info. RuntimeBlob::RuntimeBlob( const char* name, + CodeBlobKind kind, CodeBuffer* cb, - int header_size, int size, + int header_size, int frame_complete, int frame_size, OopMapSet* oop_maps, - bool caller_must_gc_arguments -) : CodeBlob(name, compiler_none, CodeBlobLayout((address) this, size, header_size, cb), cb, frame_complete, frame_size, oop_maps, caller_must_gc_arguments) { + bool caller_must_gc_arguments) + : CodeBlob(name, kind, cb, size, header_size, frame_complete, frame_size, oop_maps, caller_must_gc_arguments) +{ cb->copy_code_and_locs_to(this); } @@ -172,25 +207,6 @@ void RuntimeBlob::free(RuntimeBlob* blob) { MemoryService::track_code_cache_memory_usage(); } -void CodeBlob::purge(bool free_code_cache_data, bool unregister_nmethod) { - if (_oop_maps != nullptr) { - delete _oop_maps; - _oop_maps = nullptr; - } - NOT_PRODUCT(_asm_remarks.clear()); - NOT_PRODUCT(_dbg_strings.clear()); -} - -void CodeBlob::set_oop_maps(OopMapSet* p) { - // Danger Will Robinson! This method allocates a big - // chunk of memory, its your job to free it. - if (p != nullptr) { - _oop_maps = ImmutableOopMapSet::build_from(p); - } else { - _oop_maps = nullptr; - } -} - void RuntimeBlob::trace_new_stub(RuntimeBlob* stub, const char* name1, const char* name2) { // Do not hold the CodeCache lock during name formatting. assert(!CodeCache_lock->owned_by_self(), "release CodeCache before registering the stub"); @@ -230,22 +246,11 @@ void RuntimeBlob::trace_new_stub(RuntimeBlob* stub, const char* name1, const cha MemoryService::track_code_cache_memory_usage(); } -const ImmutableOopMap* CodeBlob::oop_map_for_return_address(address return_address) const { - assert(_oop_maps != nullptr, "nope"); - return _oop_maps->find_map_at_offset((intptr_t) return_address - (intptr_t) code_begin()); -} - -void CodeBlob::print_code_on(outputStream* st) { - ResourceMark m; - Disassembler::decode(this, st); -} - //---------------------------------------------------------------------------------------------------- // Implementation of BufferBlob - -BufferBlob::BufferBlob(const char* name, int size) -: RuntimeBlob(name, sizeof(BufferBlob), size, CodeOffsets::frame_never_safe, /*locs_size:*/ 0) +BufferBlob::BufferBlob(const char* name, CodeBlobKind kind, int size) +: RuntimeBlob(name, kind, size, sizeof(BufferBlob)) {} BufferBlob* BufferBlob::create(const char* name, uint buffer_size) { @@ -259,7 +264,7 @@ BufferBlob* BufferBlob::create(const char* name, uint buffer_size) { assert(name != nullptr, "must provide a name"); { MutexLocker mu(CodeCache_lock, Mutex::_no_safepoint_check_flag); - blob = new (size) BufferBlob(name, size); + blob = new (size) BufferBlob(name, CodeBlobKind::Buffer, size); } // Track memory usage statistic after releasing CodeCache_lock MemoryService::track_code_cache_memory_usage(); @@ -268,10 +273,11 @@ BufferBlob* BufferBlob::create(const char* name, uint buffer_size) { } -BufferBlob::BufferBlob(const char* name, int size, CodeBuffer* cb) - : RuntimeBlob(name, cb, sizeof(BufferBlob), size, CodeOffsets::frame_never_safe, 0, nullptr) +BufferBlob::BufferBlob(const char* name, CodeBlobKind kind, CodeBuffer* cb, int size) + : RuntimeBlob(name, kind, cb, size, sizeof(BufferBlob), CodeOffsets::frame_never_safe, 0, nullptr) {} +// Used by gtest BufferBlob* BufferBlob::create(const char* name, CodeBuffer* cb) { ThreadInVMfromUnknown __tiv; // get to VM state in case we block on CodeCache_lock @@ -280,7 +286,7 @@ BufferBlob* BufferBlob::create(const char* name, CodeBuffer* cb) { assert(name != nullptr, "must provide a name"); { MutexLocker mu(CodeCache_lock, Mutex::_no_safepoint_check_flag); - blob = new (size) BufferBlob(name, size, cb); + blob = new (size) BufferBlob(name, CodeBlobKind::Buffer, cb, size); } // Track memory usage statistic after releasing CodeCache_lock MemoryService::track_code_cache_memory_usage(); @@ -301,7 +307,7 @@ void BufferBlob::free(BufferBlob *blob) { // Implementation of AdapterBlob AdapterBlob::AdapterBlob(int size, CodeBuffer* cb) : - BufferBlob("I2C/C2I adapters", size, cb) { + BufferBlob("I2C/C2I adapters", CodeBlobKind::Adapter, cb, size) { CodeCache::commit(this); } @@ -322,6 +328,9 @@ AdapterBlob* AdapterBlob::create(CodeBuffer* cb) { return blob; } +//---------------------------------------------------------------------------------------------------- +// Implementation of VtableBlob + void* VtableBlob::operator new(size_t s, unsigned size) throw() { // Handling of allocation failure stops compilation and prints a bunch of // stuff, which requires unlocking the CodeCache_lock, so that the Compile_lock @@ -333,7 +342,7 @@ void* VtableBlob::operator new(size_t s, unsigned size) throw() { } VtableBlob::VtableBlob(const char* name, int size) : - BufferBlob(name, size) { + BufferBlob(name, CodeBlobKind::Vtable, size) { } VtableBlob* VtableBlob::create(const char* name, int buffer_size) { @@ -404,7 +413,8 @@ RuntimeStub::RuntimeStub( OopMapSet* oop_maps, bool caller_must_gc_arguments ) -: RuntimeBlob(name, cb, sizeof(RuntimeStub), size, frame_complete, frame_size, oop_maps, caller_must_gc_arguments) +: RuntimeBlob(name, CodeBlobKind::Runtime_Stub, cb, size, sizeof(RuntimeStub), + frame_complete, frame_size, oop_maps, caller_must_gc_arguments) { } @@ -460,7 +470,8 @@ DeoptimizationBlob::DeoptimizationBlob( int unpack_with_reexecution_offset, int frame_size ) -: SingletonBlob("DeoptimizationBlob", cb, sizeof(DeoptimizationBlob), size, frame_size, oop_maps) +: SingletonBlob("DeoptimizationBlob", CodeBlobKind::Deoptimization, cb, + size, sizeof(DeoptimizationBlob), frame_size, oop_maps) { _unpack_offset = unpack_offset; _unpack_with_exception = unpack_with_exception_offset; @@ -509,7 +520,8 @@ UncommonTrapBlob::UncommonTrapBlob( OopMapSet* oop_maps, int frame_size ) -: SingletonBlob("UncommonTrapBlob", cb, sizeof(UncommonTrapBlob), size, frame_size, oop_maps) +: SingletonBlob("UncommonTrapBlob", CodeBlobKind::Uncommon_Trap, cb, + size, sizeof(UncommonTrapBlob), frame_size, oop_maps) {} @@ -545,7 +557,8 @@ ExceptionBlob::ExceptionBlob( OopMapSet* oop_maps, int frame_size ) -: SingletonBlob("ExceptionBlob", cb, sizeof(ExceptionBlob), size, frame_size, oop_maps) +: SingletonBlob("ExceptionBlob", CodeBlobKind::Exception, cb, + size, sizeof(ExceptionBlob), frame_size, oop_maps) {} @@ -580,7 +593,8 @@ SafepointBlob::SafepointBlob( OopMapSet* oop_maps, int frame_size ) -: SingletonBlob("SafepointBlob", cb, sizeof(SafepointBlob), size, frame_size, oop_maps) +: SingletonBlob("SafepointBlob", CodeBlobKind::Safepoint, cb, + size, sizeof(SafepointBlob), frame_size, oop_maps) {} @@ -602,6 +616,61 @@ SafepointBlob* SafepointBlob::create( return blob; } +//---------------------------------------------------------------------------------------------------- +// Implementation of UpcallStub + +UpcallStub::UpcallStub(const char* name, CodeBuffer* cb, int size, jobject receiver, ByteSize frame_data_offset) : + RuntimeBlob(name, CodeBlobKind::Upcall, cb, size, sizeof(UpcallStub), + CodeOffsets::frame_never_safe, 0 /* no frame size */, + /* oop maps = */ nullptr, /* caller must gc arguments = */ false), + _receiver(receiver), + _frame_data_offset(frame_data_offset) +{ + CodeCache::commit(this); +} + +void* UpcallStub::operator new(size_t s, unsigned size) throw() { + return CodeCache::allocate(size, CodeBlobType::NonNMethod); +} + +UpcallStub* UpcallStub::create(const char* name, CodeBuffer* cb, jobject receiver, ByteSize frame_data_offset) { + ThreadInVMfromUnknown __tiv; // get to VM state in case we block on CodeCache_lock + + UpcallStub* blob = nullptr; + unsigned int size = CodeBlob::allocation_size(cb, sizeof(UpcallStub)); + { + MutexLocker mu(CodeCache_lock, Mutex::_no_safepoint_check_flag); + blob = new (size) UpcallStub(name, cb, size, receiver, frame_data_offset); + } + if (blob == nullptr) { + return nullptr; // caller must handle this + } + + // Track memory usage statistic after releasing CodeCache_lock + MemoryService::track_code_cache_memory_usage(); + + trace_new_stub(blob, "UpcallStub"); + + return blob; +} + +void UpcallStub::oops_do(OopClosure* f, const frame& frame) { + frame_data_for_frame(frame)->old_handles->oops_do(f); +} + +JavaFrameAnchor* UpcallStub::jfa_for_frame(const frame& frame) const { + return &frame_data_for_frame(frame)->jfa; +} + +void UpcallStub::free(UpcallStub* blob) { + assert(blob != nullptr, "caller must check for nullptr"); + JNIHandles::destroy_global(blob->receiver()); + RuntimeBlob::free(blob); +} + +void UpcallStub::preserve_callee_argument_oops(frame fr, const RegisterMap* reg_map, OopClosure* f) { + ShouldNotReachHere(); // caller should never have to gc arguments +} //---------------------------------------------------------------------------------------------------- // Verification and printing @@ -678,10 +747,6 @@ void CodeBlob::dump_for_addr(address addr, outputStream* st, bool verbose) const print_on(st); } -void RuntimeBlob::verify() { - ShouldNotReachHere(); -} - void BufferBlob::verify() { // unimplemented } @@ -730,60 +795,6 @@ void DeoptimizationBlob::print_value_on(outputStream* st) const { st->print_cr("Deoptimization (frame not available)"); } -// Implementation of UpcallStub - -UpcallStub::UpcallStub(const char* name, CodeBuffer* cb, int size, jobject receiver, ByteSize frame_data_offset) : - RuntimeBlob(name, cb, sizeof(UpcallStub), size, CodeOffsets::frame_never_safe, 0 /* no frame size */, - /* oop maps = */ nullptr, /* caller must gc arguments = */ false), - _receiver(receiver), - _frame_data_offset(frame_data_offset) { - CodeCache::commit(this); -} - -void* UpcallStub::operator new(size_t s, unsigned size) throw() { - return CodeCache::allocate(size, CodeBlobType::NonNMethod); -} - -UpcallStub* UpcallStub::create(const char* name, CodeBuffer* cb, jobject receiver, ByteSize frame_data_offset) { - ThreadInVMfromUnknown __tiv; // get to VM state in case we block on CodeCache_lock - - UpcallStub* blob = nullptr; - unsigned int size = CodeBlob::allocation_size(cb, sizeof(UpcallStub)); - { - MutexLocker mu(CodeCache_lock, Mutex::_no_safepoint_check_flag); - blob = new (size) UpcallStub(name, cb, size, receiver, frame_data_offset); - } - if (blob == nullptr) { - return nullptr; // caller must handle this - } - - // Track memory usage statistic after releasing CodeCache_lock - MemoryService::track_code_cache_memory_usage(); - - trace_new_stub(blob, "UpcallStub"); - - return blob; -} - -void UpcallStub::oops_do(OopClosure* f, const frame& frame) { - frame_data_for_frame(frame)->old_handles->oops_do(f); -} - -JavaFrameAnchor* UpcallStub::jfa_for_frame(const frame& frame) const { - return &frame_data_for_frame(frame)->jfa; -} - -void UpcallStub::free(UpcallStub* blob) { - assert(blob != nullptr, "caller must check for nullptr"); - JNIHandles::destroy_global(blob->receiver()); - RuntimeBlob::free(blob); -} - -void UpcallStub::preserve_callee_argument_oops(frame fr, const RegisterMap* reg_map, OopClosure* f) { - ShouldNotReachHere(); // caller should never have to gc arguments -} - -// Misc. void UpcallStub::verify() { // unimplemented } diff --git a/src/hotspot/share/code/codeBlob.hpp b/src/hotspot/share/code/codeBlob.hpp index 56caa906ecb..134d60e5cb5 100644 --- a/src/hotspot/share/code/codeBlob.hpp +++ b/src/hotspot/share/code/codeBlob.hpp @@ -52,8 +52,7 @@ enum class CodeBlobType { // CodeBlob - superclass for all entries in the CodeCache. // // Subtypes are: -// CompiledMethod : Compiled Java methods (include method that calls to native code) -// nmethod : JIT Compiled Java methods +// nmethod : JIT Compiled Java methods // RuntimeBlob : Non-compiled method code; generated glue code // BufferBlob : Used for non-relocatable code such as interpreter, stubroutines, etc. // AdapterBlob : Used to hold C2I/I2C adapters @@ -75,8 +74,22 @@ enum class CodeBlobType { // - instruction space // - data space +enum class CodeBlobKind : u1 { + None, + Nmethod, + Buffer, + Adapter, + Vtable, + MH_Adapter, + Runtime_Stub, + Deoptimization, + Exception, + Safepoint, + Uncommon_Trap, + Upcall, + Number_Of_Kinds +}; -class CodeBlobLayout; class UpcallStub; // for as_upcall_stub() class RuntimeStub; // for as_runtime_stub() class JavaFrameAnchor; // for UpcallStub::jfa_for_frame @@ -87,23 +100,15 @@ class CodeBlob { friend class CodeCacheDumper; protected: - // order fields from large to small to minimize padding between fields - address _code_begin; - address _code_end; - address _content_begin; // address to where content region begins (this includes consts, insts, stubs) - // address _content_end - not required, for all CodeBlobs _code_end == _content_end for now - address _data_end; - address _relocation_begin; - address _relocation_end; - ImmutableOopMapSet* _oop_maps; // OopMap for this CodeBlob - const char* _name; - S390_ONLY(int _ctable_offset;) int _size; // total size of CodeBlob in bytes int _header_size; // size of header (depends on subclass) + int _relocation_size; // size of relocation + int _content_offset; // offset to where content region begins (this includes consts, insts, stubs) + int _code_offset; // offset to where instructions region begins (this includes insts, stubs) int _frame_complete_offset; // instruction offsets in [0.._frame_complete_offset) have // not finished setting up their frame. Beware of pc's in // that range. There is a similar range(s) on returns @@ -111,28 +116,32 @@ class CodeBlob { int _data_offset; // offset to where data region begins int _frame_size; // size of stack frame in words (NOT slots. On x64 these are 64bit words) - bool _caller_must_gc_arguments; + S390_ONLY(int _ctable_offset;) + + CodeBlobKind _kind; // Kind of this code blob - bool _is_compiled; - const CompilerType _type; // CompilerType + bool _caller_must_gc_arguments; #ifndef PRODUCT AsmRemarks _asm_remarks; DbgStrings _dbg_strings; #endif // not PRODUCT - CodeBlob(const char* name, CompilerType type, const CodeBlobLayout& layout, int frame_complete_offset, - int frame_size, ImmutableOopMapSet* oop_maps, - bool caller_must_gc_arguments, bool compiled = false); - CodeBlob(const char* name, CompilerType type, const CodeBlobLayout& layout, CodeBuffer* cb, int frame_complete_offset, - int frame_size, OopMapSet* oop_maps, - bool caller_must_gc_arguments, bool compiled = false); + DEBUG_ONLY( void verify_parameters() ); + + CodeBlob(const char* name, CodeBlobKind kind, int size, int header_size, int relocation_size, + int content_offset, int code_offset, int data_offset, int frame_complete_offset, + int frame_size, ImmutableOopMapSet* oop_maps, bool caller_must_gc_arguments); + + CodeBlob(const char* name, CodeBlobKind kind, CodeBuffer* cb, int size, int header_size, + int frame_complete_offset, int frame_size, OopMapSet* oop_maps, bool caller_must_gc_arguments); + + // Simple CodeBlob used for simple BufferBlob. + CodeBlob(const char* name, CodeBlobKind kind, int size, int header_size); void operator delete(void* p) { } public: - // Only used by unit test. - CodeBlob() : _type(compiler_none) {} virtual ~CodeBlob() { assert(_oop_maps == nullptr, "Not flushed"); @@ -146,44 +155,42 @@ class CodeBlob { virtual void purge(bool free_code_cache_data, bool unregister_nmethod); // Typing - virtual bool is_buffer_blob() const { return false; } - virtual bool is_nmethod() const { return false; } - virtual bool is_runtime_stub() const { return false; } - virtual bool is_deoptimization_stub() const { return false; } - virtual bool is_uncommon_trap_stub() const { return false; } - virtual bool is_exception_stub() const { return false; } - virtual bool is_safepoint_stub() const { return false; } - virtual bool is_adapter_blob() const { return false; } - virtual bool is_vtable_blob() const { return false; } - virtual bool is_method_handles_adapter_blob() const { return false; } - virtual bool is_upcall_stub() const { return false; } - bool is_compiled() const { return _is_compiled; } - const bool* is_compiled_addr() const { return &_is_compiled; } - - inline bool is_compiled_by_c1() const { return _type == compiler_c1; }; - inline bool is_compiled_by_c2() const { return _type == compiler_c2; }; - inline bool is_compiled_by_jvmci() const { return _type == compiler_jvmci; }; - const char* compiler_name() const; - CompilerType compiler_type() const { return _type; } + bool is_nmethod() const { return _kind == CodeBlobKind::Nmethod; } + bool is_buffer_blob() const { return _kind == CodeBlobKind::Buffer; } + bool is_runtime_stub() const { return _kind == CodeBlobKind::Runtime_Stub; } + bool is_deoptimization_stub() const { return _kind == CodeBlobKind::Deoptimization; } + bool is_uncommon_trap_stub() const { return _kind == CodeBlobKind::Uncommon_Trap; } + bool is_exception_stub() const { return _kind == CodeBlobKind::Exception; } + bool is_safepoint_stub() const { return _kind == CodeBlobKind::Safepoint; } + bool is_adapter_blob() const { return _kind == CodeBlobKind::Adapter; } + bool is_vtable_blob() const { return _kind == CodeBlobKind::Vtable; } + bool is_method_handles_adapter_blob() const { return _kind == CodeBlobKind::MH_Adapter; } + bool is_upcall_stub() const { return _kind == CodeBlobKind::Upcall; } // Casting - nmethod* as_nmethod_or_null() { return is_nmethod() ? (nmethod*) this : nullptr; } - nmethod* as_nmethod() { assert(is_nmethod(), "must be nmethod"); return (nmethod*) this; } - CompiledMethod* as_compiled_method_or_null() { return is_compiled() ? (CompiledMethod*) this : nullptr; } - CompiledMethod* as_compiled_method() { assert(is_compiled(), "must be compiled"); return (CompiledMethod*) this; } - CodeBlob* as_codeblob_or_null() const { return (CodeBlob*) this; } - UpcallStub* as_upcall_stub() const { assert(is_upcall_stub(), "must be upcall stub"); return (UpcallStub*) this; } - RuntimeStub* as_runtime_stub() const { assert(is_runtime_stub(), "must be runtime blob"); return (RuntimeStub*) this; } + nmethod* as_nmethod_or_null() { return is_nmethod() ? (nmethod*) this : nullptr; } + nmethod* as_nmethod() { assert(is_nmethod(), "must be nmethod"); return (nmethod*) this; } + CodeBlob* as_codeblob_or_null() const { return (CodeBlob*) this; } + UpcallStub* as_upcall_stub() const { assert(is_upcall_stub(), "must be upcall stub"); return (UpcallStub*) this; } + RuntimeStub* as_runtime_stub() const { assert(is_runtime_stub(), "must be runtime blob"); return (RuntimeStub*) this; } // Boundaries - address header_begin() const { return (address) this; } - relocInfo* relocation_begin() const { return (relocInfo*) _relocation_begin; }; - relocInfo* relocation_end() const { return (relocInfo*) _relocation_end; } - address content_begin() const { return _content_begin; } - address content_end() const { return _code_end; } // _code_end == _content_end is true for all types of blobs for now, it is also checked in the constructor - address code_begin() const { return _code_begin; } - address code_end() const { return _code_end; } - address data_end() const { return _data_end; } + address header_begin() const { return (address) this; } + address header_end() const { return ((address) this) + _header_size; } + relocInfo* relocation_begin() const { return (relocInfo*) header_end(); } + relocInfo* relocation_end() const { return (relocInfo*)(header_end() + _relocation_size); } + address content_begin() const { return (address) header_begin() + _content_offset; } + address content_end() const { return (address) header_begin() + _data_offset; } + address code_begin() const { return (address) header_begin() + _code_offset; } + // code_end == content_end is true for all types of blobs for now, it is also checked in the constructor + address code_end() const { return (address) header_begin() + _data_offset; } + address data_begin() const { return (address) header_begin() + _data_offset; } + address data_end() const { return (address) header_begin() + _size; } + + // Offsets + int content_offset() const { return _content_offset; } + int code_offset() const { return _code_offset; } + int data_offset() const { return _data_offset; } // This field holds the beginning of the const section in the old code buffer. // It is needed to fix relocations of pc-relative loads when resizing the @@ -192,17 +199,16 @@ class CodeBlob { void set_ctable_begin(address ctable) { S390_ONLY(_ctable_offset = ctable - header_begin();) } // Sizes - int size() const { return _size; } - int header_size() const { return _header_size; } - int relocation_size() const { return pointer_delta_as_int((address) relocation_end(), (address) relocation_begin()); } - int content_size() const { return pointer_delta_as_int(content_end(), content_begin()); } - int code_size() const { return pointer_delta_as_int(code_end(), code_begin()); } + int size() const { return _size; } + int header_size() const { return _header_size; } + int relocation_size() const { return pointer_delta_as_int((address) relocation_end(), (address) relocation_begin()); } + int content_size() const { return pointer_delta_as_int(content_end(), content_begin()); } + int code_size() const { return pointer_delta_as_int(code_end(), code_begin()); } + // Only used from CodeCache::free_unused_tail() after the Interpreter blob was trimmed void adjust_size(size_t used) { _size = (int)used; _data_offset = (int)used; - _code_end = (address)this + used; - _data_end = (address)this + used; } // Containment @@ -213,8 +219,6 @@ class CodeBlob { code_contains(addr) && addr >= code_begin() + _frame_complete_offset; } int frame_complete_offset() const { return _frame_complete_offset; } - virtual bool is_not_entrant() const { return false; } - // OopMap for frame ImmutableOopMapSet* oop_maps() const { return _oop_maps; } void set_oop_maps(OopMapSet* p); @@ -260,97 +264,8 @@ class CodeBlob { #endif }; -class CodeBlobLayout : public StackObj { -private: - int _size; - int _header_size; - int _relocation_size; - int _content_offset; - int _code_offset; - int _data_offset; - address _code_begin; - address _code_end; - address _content_begin; - address _content_end; - address _data_end; - address _relocation_begin; - address _relocation_end; - -public: - CodeBlobLayout(address code_begin, address code_end, address content_begin, address content_end, address data_end, address relocation_begin, address relocation_end) : - _size(0), - _header_size(0), - _relocation_size(0), - _content_offset(0), - _code_offset(0), - _data_offset(0), - _code_begin(code_begin), - _code_end(code_end), - _content_begin(content_begin), - _content_end(content_end), - _data_end(data_end), - _relocation_begin(relocation_begin), - _relocation_end(relocation_end) - { - } - - CodeBlobLayout(const address start, int size, int header_size, int relocation_size, int data_offset) : - _size(size), - _header_size(header_size), - _relocation_size(relocation_size), - _content_offset(CodeBlob::align_code_offset(_header_size + _relocation_size)), - _code_offset(_content_offset), - _data_offset(data_offset) - { - assert(is_aligned(_relocation_size, oopSize), "unaligned size"); - - _code_begin = (address) start + _code_offset; - _code_end = (address) start + _data_offset; - - _content_begin = (address) start + _content_offset; - _content_end = (address) start + _data_offset; - - _data_end = (address) start + _size; - _relocation_begin = (address) start + _header_size; - _relocation_end = _relocation_begin + _relocation_size; - } - - CodeBlobLayout(const address start, int size, int header_size, const CodeBuffer* cb) : - _size(size), - _header_size(header_size), - _relocation_size(align_up(cb->total_relocation_size(), oopSize)), - _content_offset(CodeBlob::align_code_offset(_header_size + _relocation_size)), - _code_offset(_content_offset + cb->total_offset_of(cb->insts())), - _data_offset(_content_offset + align_up(cb->total_content_size(), oopSize)) - { - assert(is_aligned(_relocation_size, oopSize), "unaligned size"); - - _code_begin = (address) start + _code_offset; - _code_end = (address) start + _data_offset; - - _content_begin = (address) start + _content_offset; - _content_end = (address) start + _data_offset; - - _data_end = (address) start + _size; - _relocation_begin = (address) start + _header_size; - _relocation_end = _relocation_begin + _relocation_size; - } - - int size() const { return _size; } - int header_size() const { return _header_size; } - int relocation_size() const { return _relocation_size; } - int content_offset() const { return _content_offset; } - int code_offset() const { return _code_offset; } - int data_offset() const { return _data_offset; } - address code_begin() const { return _code_begin; } - address code_end() const { return _code_end; } - address data_end() const { return _data_end; } - address relocation_begin() const { return _relocation_begin; } - address relocation_end() const { return _relocation_end; } - address content_begin() const { return _content_begin; } - address content_end() const { return _content_end; } -}; - +//---------------------------------------------------------------------------------------------------- +// RuntimeBlob: used for non-compiled method code (adapters, stubs, blobs) class RuntimeBlob : public CodeBlob { friend class VMStructs; @@ -358,16 +273,19 @@ class RuntimeBlob : public CodeBlob { // Creation // a) simple CodeBlob - // frame_complete is the offset from the beginning of the instructions - // to where the frame setup (from stackwalk viewpoint) is complete. - RuntimeBlob(const char* name, int header_size, int size, int frame_complete, int locs_size); + RuntimeBlob(const char* name, CodeBlobKind kind, int size, int header_size) + : CodeBlob(name, kind, size, header_size) + {} // b) full CodeBlob + // frame_complete is the offset from the beginning of the instructions + // to where the frame setup (from stackwalk viewpoint) is complete. RuntimeBlob( const char* name, + CodeBlobKind kind, CodeBuffer* cb, - int header_size, int size, + int header_size, int frame_complete, int frame_size, OopMapSet* oop_maps, @@ -376,15 +294,6 @@ class RuntimeBlob : public CodeBlob { static void free(RuntimeBlob* blob); - void verify(); - - // OopMap for frame - virtual void preserve_callee_argument_oops(frame fr, const RegisterMap* reg_map, OopClosure* f) { ShouldNotReachHere(); } - - // Debugging - virtual void print_on(outputStream* st) const { CodeBlob::print_on(st); } - virtual void print_value_on(outputStream* st) const { CodeBlob::print_value_on(st); } - // Deal with Disassembler, VTune, Forte, JvmtiExport, MemoryService. static void trace_new_stub(RuntimeBlob* blob, const char* name1, const char* name2 = ""); }; @@ -403,8 +312,8 @@ class BufferBlob: public RuntimeBlob { private: // Creation support - BufferBlob(const char* name, int size); - BufferBlob(const char* name, int size, CodeBuffer* cb); + BufferBlob(const char* name, CodeBlobKind kind, int size); + BufferBlob(const char* name, CodeBlobKind kind, CodeBuffer* cb, int size); void* operator new(size_t s, unsigned size) throw(); @@ -415,15 +324,12 @@ class BufferBlob: public RuntimeBlob { static void free(BufferBlob* buf); - // Typing - virtual bool is_buffer_blob() const { return true; } - // GC/Verification support - void preserve_callee_argument_oops(frame fr, const RegisterMap* reg_map, OopClosure* f) { /* nothing to do */ } + void preserve_callee_argument_oops(frame fr, const RegisterMap* reg_map, OopClosure* f) override { /* nothing to do */ } - void verify(); - void print_on(outputStream* st) const; - void print_value_on(outputStream* st) const; + void verify() override; + void print_on(outputStream* st) const override; + void print_value_on(outputStream* st) const override; }; @@ -437,9 +343,6 @@ class AdapterBlob: public BufferBlob { public: // Creation static AdapterBlob* create(CodeBuffer* cb); - - // Typing - virtual bool is_adapter_blob() const { return true; } }; //--------------------------------------------------------------------------------------------------- @@ -452,9 +355,6 @@ class VtableBlob: public BufferBlob { public: // Creation static VtableBlob* create(const char* name, int buffer_size); - - // Typing - virtual bool is_vtable_blob() const { return true; } }; //---------------------------------------------------------------------------------------------------- @@ -462,14 +362,11 @@ class VtableBlob: public BufferBlob { class MethodHandlesAdapterBlob: public BufferBlob { private: - MethodHandlesAdapterBlob(int size): BufferBlob("MethodHandles adapters", size) {} + MethodHandlesAdapterBlob(int size): BufferBlob("MethodHandles adapters", CodeBlobKind::MH_Adapter, size) {} public: // Creation static MethodHandlesAdapterBlob* create(int buffer_size); - - // Typing - virtual bool is_method_handles_adapter_blob() const { return true; } }; @@ -506,17 +403,14 @@ class RuntimeStub: public RuntimeBlob { static void free(RuntimeStub* stub) { RuntimeBlob::free(stub); } - // Typing - bool is_runtime_stub() const { return true; } - address entry_point() const { return code_begin(); } // GC/Verification support - void preserve_callee_argument_oops(frame fr, const RegisterMap *reg_map, OopClosure* f) { /* nothing to do */ } + void preserve_callee_argument_oops(frame fr, const RegisterMap *reg_map, OopClosure* f) override { /* nothing to do */ } - void verify(); - void print_on(outputStream* st) const; - void print_value_on(outputStream* st) const; + void verify() override; + void print_on(outputStream* st) const override; + void print_value_on(outputStream* st) const override; }; @@ -531,23 +425,24 @@ class SingletonBlob: public RuntimeBlob { public: SingletonBlob( - const char* name, - CodeBuffer* cb, - int header_size, - int size, - int frame_size, - OopMapSet* oop_maps + const char* name, + CodeBlobKind kind, + CodeBuffer* cb, + int size, + int header_size, + int frame_size, + OopMapSet* oop_maps ) - : RuntimeBlob(name, cb, header_size, size, CodeOffsets::frame_never_safe, frame_size, oop_maps) + : RuntimeBlob(name, kind, cb, size, header_size, CodeOffsets::frame_never_safe, frame_size, oop_maps) {}; address entry_point() { return code_begin(); } // GC/Verification support - void preserve_callee_argument_oops(frame fr, const RegisterMap *reg_map, OopClosure* f) { /* nothing to do */ } - void verify(); // does nothing - void print_on(outputStream* st) const; - void print_value_on(outputStream* st) const; + void preserve_callee_argument_oops(frame fr, const RegisterMap *reg_map, OopClosure* f) override { /* nothing to do */ } + void verify() override; // does nothing + void print_on(outputStream* st) const override; + void print_value_on(outputStream* st) const override; }; @@ -592,14 +487,8 @@ class DeoptimizationBlob: public SingletonBlob { int frame_size ); - // Typing - bool is_deoptimization_stub() const { return true; } - - // GC for args - void preserve_callee_argument_oops(frame fr, const RegisterMap *reg_map, OopClosure* f) { /* Nothing to do */ } - // Printing - void print_value_on(outputStream* st) const; + void print_value_on(outputStream* st) const override; address unpack() const { return code_begin() + _unpack_offset; } address unpack_with_exception() const { return code_begin() + _unpack_with_exception; } @@ -656,12 +545,6 @@ class UncommonTrapBlob: public SingletonBlob { OopMapSet* oop_maps, int frame_size ); - - // GC for args - void preserve_callee_argument_oops(frame fr, const RegisterMap *reg_map, OopClosure* f) { /* nothing to do */ } - - // Typing - bool is_uncommon_trap_stub() const { return true; } }; @@ -686,12 +569,6 @@ class ExceptionBlob: public SingletonBlob { OopMapSet* oop_maps, int frame_size ); - - // GC for args - void preserve_callee_argument_oops(frame fr, const RegisterMap* reg_map, OopClosure* f) { /* nothing to do */ } - - // Typing - bool is_exception_stub() const { return true; } }; #endif // COMPILER2 @@ -717,12 +594,6 @@ class SafepointBlob: public SingletonBlob { OopMapSet* oop_maps, int frame_size ); - - // GC for args - void preserve_callee_argument_oops(frame fr, const RegisterMap* reg_map, OopClosure* f) { /* nothing to do */ } - - // Typing - bool is_safepoint_stub() const { return true; } }; //---------------------------------------------------------------------------------------------------- @@ -759,17 +630,14 @@ class UpcallStub: public RuntimeBlob { JavaFrameAnchor* jfa_for_frame(const frame& frame) const; - // Typing - virtual bool is_upcall_stub() const override { return true; } - // GC/Verification support void oops_do(OopClosure* f, const frame& frame); - virtual void preserve_callee_argument_oops(frame fr, const RegisterMap* reg_map, OopClosure* f) override; - virtual void verify() override; + void preserve_callee_argument_oops(frame fr, const RegisterMap* reg_map, OopClosure* f) override; + void verify() override; // Misc. - virtual void print_on(outputStream* st) const override; - virtual void print_value_on(outputStream* st) const override; + void print_on(outputStream* st) const override; + void print_value_on(outputStream* st) const override; }; #endif // SHARE_CODE_CODEBLOB_HPP diff --git a/src/hotspot/share/code/codeCache.cpp b/src/hotspot/share/code/codeCache.cpp index 9c0fa80cab5..73eca19f086 100644 --- a/src/hotspot/share/code/codeCache.cpp +++ b/src/hotspot/share/code/codeCache.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 @@ -161,7 +161,6 @@ class CodeBlob_sizes { // Iterate over all CodeHeaps #define FOR_ALL_HEAPS(heap) for (GrowableArrayIterator heap = _heaps->begin(); heap != _heaps->end(); ++heap) -#define FOR_ALL_NMETHOD_HEAPS(heap) for (GrowableArrayIterator heap = _nmethod_heaps->begin(); heap != _nmethod_heaps->end(); ++heap) #define FOR_ALL_ALLOCABLE_HEAPS(heap) for (GrowableArrayIterator heap = _allocable_heaps->begin(); heap != _allocable_heaps->end(); ++heap) // Iterate over all CodeBlobs (cb) on the given CodeHeap @@ -174,147 +173,125 @@ ExceptionCache* volatile CodeCache::_exception_cache_purge_list = nullptr; // Initialize arrays of CodeHeap subsets GrowableArray* CodeCache::_heaps = new(mtCode) GrowableArray (static_cast(CodeBlobType::All), mtCode); -GrowableArray* CodeCache::_compiled_heaps = new(mtCode) GrowableArray (static_cast(CodeBlobType::All), mtCode); GrowableArray* CodeCache::_nmethod_heaps = new(mtCode) GrowableArray (static_cast(CodeBlobType::All), mtCode); GrowableArray* CodeCache::_allocable_heaps = new(mtCode) GrowableArray (static_cast(CodeBlobType::All), mtCode); -void CodeCache::check_heap_sizes(size_t non_nmethod_size, size_t profiled_size, size_t non_profiled_size, size_t cache_size, bool all_set) { - size_t total_size = non_nmethod_size + profiled_size + non_profiled_size; - // Prepare error message - const char* error = "Invalid code heap sizes"; - err_msg message("NonNMethodCodeHeapSize (" SIZE_FORMAT "K) + ProfiledCodeHeapSize (" SIZE_FORMAT "K)" - " + NonProfiledCodeHeapSize (" SIZE_FORMAT "K) = " SIZE_FORMAT "K", - non_nmethod_size/K, profiled_size/K, non_profiled_size/K, total_size/K); - - if (total_size > cache_size) { - // Some code heap sizes were explicitly set: total_size must be <= cache_size - message.append(" is greater than ReservedCodeCacheSize (" SIZE_FORMAT "K).", cache_size/K); - vm_exit_during_initialization(error, message); - } else if (all_set && total_size != cache_size) { - // All code heap sizes were explicitly set: total_size must equal cache_size - message.append(" is not equal to ReservedCodeCacheSize (" SIZE_FORMAT "K).", cache_size/K); - vm_exit_during_initialization(error, message); +static void check_min_size(const char* codeheap, size_t size, size_t required_size) { + if (size < required_size) { + log_debug(codecache)("Code heap (%s) size " SIZE_FORMAT "K below required minimal size " SIZE_FORMAT "K", + codeheap, size/K, required_size/K); + err_msg title("Not enough space in %s to run VM", codeheap); + err_msg message(SIZE_FORMAT "K < " SIZE_FORMAT "K", size/K, required_size/K); + vm_exit_during_initialization(title, message); } } +struct CodeHeapInfo { + size_t size; + bool set; + bool enabled; +}; + +static void set_size_of_unset_code_heap(CodeHeapInfo* heap, size_t available_size, size_t used_size, size_t min_size) { + assert(!heap->set, "sanity"); + heap->size = (available_size > (used_size + min_size)) ? (available_size - used_size) : min_size; +} + void CodeCache::initialize_heaps() { - bool non_nmethod_set = FLAG_IS_CMDLINE(NonNMethodCodeHeapSize); - bool profiled_set = FLAG_IS_CMDLINE(ProfiledCodeHeapSize); - bool non_profiled_set = FLAG_IS_CMDLINE(NonProfiledCodeHeapSize); - const size_t ps = page_size(false, 8); - const size_t min_size = MAX2(os::vm_allocation_granularity(), ps); - const size_t cache_size = ReservedCodeCacheSize; - size_t non_nmethod_size = NonNMethodCodeHeapSize; - size_t profiled_size = ProfiledCodeHeapSize; - size_t non_profiled_size = NonProfiledCodeHeapSize; - // Check if total size set via command line flags exceeds the reserved size - check_heap_sizes((non_nmethod_set ? non_nmethod_size : min_size), - (profiled_set ? profiled_size : min_size), - (non_profiled_set ? non_profiled_size : min_size), - cache_size, - non_nmethod_set && profiled_set && non_profiled_set); - - // Determine size of compiler buffers - size_t code_buffers_size = 0; -#ifdef COMPILER1 - // C1 temporary code buffers (see Compiler::init_buffer_blob()) - const int c1_count = CompilationPolicy::c1_count(); - code_buffers_size += c1_count * Compiler::code_buffer_size(); -#endif -#ifdef COMPILER2 - // C2 scratch buffers (see Compile::init_scratch_buffer_blob()) - const int c2_count = CompilationPolicy::c2_count(); - // Initial size of constant table (this may be increased if a compiled method needs more space) - code_buffers_size += c2_count * C2Compiler::initial_code_buffer_size(); -#endif - // Increase default non_nmethod_size to account for compiler buffers - if (!non_nmethod_set) { - non_nmethod_size += code_buffers_size; - } - // Calculate default CodeHeap sizes if not set by user - if (!non_nmethod_set && !profiled_set && !non_profiled_set) { - // Leave room for the other two parts of the code cache - const size_t max_non_nmethod_size = cache_size - 2 * min_size; - // Check if we have enough space for the non-nmethod code heap - if (max_non_nmethod_size >= non_nmethod_size) { - // Use the default value for non_nmethod_size and one half of the - // remaining size for non-profiled and one half for profiled methods - size_t remaining_size = cache_size - non_nmethod_size; - profiled_size = remaining_size / 2; - non_profiled_size = remaining_size - profiled_size; - } else { - // Use all space for the non-nmethod heap and set other heaps to minimal size - non_nmethod_size = max_non_nmethod_size; - profiled_size = min_size; - non_profiled_size = min_size; - } - } else if (!non_nmethod_set || !profiled_set || !non_profiled_set) { - // The user explicitly set some code heap sizes. Increase or decrease the (default) - // sizes of the other code heaps accordingly. First adapt non-profiled and profiled - // code heap sizes and then only change non-nmethod code heap size if still necessary. - intx diff_size = cache_size - (non_nmethod_size + profiled_size + non_profiled_size); - if (non_profiled_set) { - if (!profiled_set) { - // Adapt size of profiled code heap - if (diff_size < 0 && ((intx)profiled_size + diff_size) <= 0) { - // Not enough space available, set to minimum size - diff_size += profiled_size - min_size; - profiled_size = min_size; - } else { - profiled_size += diff_size; - diff_size = 0; - } - } - } else if (profiled_set) { - // Adapt size of non-profiled code heap - if (diff_size < 0 && ((intx)non_profiled_size + diff_size) <= 0) { - // Not enough space available, set to minimum size - diff_size += non_profiled_size - min_size; - non_profiled_size = min_size; - } else { - non_profiled_size += diff_size; - diff_size = 0; - } - } else if (non_nmethod_set) { - // Distribute remaining size between profiled and non-profiled code heaps - diff_size = cache_size - non_nmethod_size; - profiled_size = diff_size / 2; - non_profiled_size = diff_size - profiled_size; - diff_size = 0; - } - if (diff_size != 0) { - // Use non-nmethod code heap for remaining space requirements - assert(!non_nmethod_set && ((intx)non_nmethod_size + diff_size) > 0, "sanity"); - non_nmethod_size += diff_size; - } - } + CodeHeapInfo non_nmethod = {NonNMethodCodeHeapSize, FLAG_IS_CMDLINE(NonNMethodCodeHeapSize), true}; + CodeHeapInfo profiled = {ProfiledCodeHeapSize, FLAG_IS_CMDLINE(ProfiledCodeHeapSize), true}; + CodeHeapInfo non_profiled = {NonProfiledCodeHeapSize, FLAG_IS_CMDLINE(NonProfiledCodeHeapSize), true}; - // We do not need the profiled CodeHeap, use all space for the non-profiled CodeHeap + const bool cache_size_set = FLAG_IS_CMDLINE(ReservedCodeCacheSize); + const size_t ps = page_size(false, 8); + const size_t min_size = MAX2(os::vm_allocation_granularity(), ps); + const size_t min_cache_size = CodeCacheMinimumUseSpace DEBUG_ONLY(* 3); // Make sure we have enough space for VM internal code + size_t cache_size = align_up(ReservedCodeCacheSize, min_size); + + // Prerequisites if (!heap_available(CodeBlobType::MethodProfiled)) { - non_profiled_size += profiled_size; - profiled_size = 0; + // For compatibility reasons, disabled tiered compilation overrides + // segment size even if it is set explicitly. + non_profiled.size += profiled.size; + // Profiled code heap is not available, forcibly set size to 0 + profiled.size = 0; + profiled.set = true; + profiled.enabled = false; + } + + assert(heap_available(CodeBlobType::MethodNonProfiled), "MethodNonProfiled heap is always available for segmented code heap"); + + size_t compiler_buffer_size = 0; + COMPILER1_PRESENT(compiler_buffer_size += CompilationPolicy::c1_count() * Compiler::code_buffer_size()); + COMPILER2_PRESENT(compiler_buffer_size += CompilationPolicy::c2_count() * C2Compiler::initial_code_buffer_size()); + + if (!non_nmethod.set) { + non_nmethod.size += compiler_buffer_size; + } + + if (!profiled.set && !non_profiled.set) { + non_profiled.size = profiled.size = (cache_size > non_nmethod.size + 2 * min_size) ? + (cache_size - non_nmethod.size) / 2 : min_size; + } + + if (profiled.set && !non_profiled.set) { + set_size_of_unset_code_heap(&non_profiled, cache_size, non_nmethod.size + profiled.size, min_size); + } + + if (!profiled.set && non_profiled.set) { + set_size_of_unset_code_heap(&profiled, cache_size, non_nmethod.size + non_profiled.size, min_size); + } + + // Compatibility. + size_t non_nmethod_min_size = min_cache_size + compiler_buffer_size; + if (!non_nmethod.set && profiled.set && non_profiled.set) { + set_size_of_unset_code_heap(&non_nmethod, cache_size, profiled.size + non_profiled.size, non_nmethod_min_size); + } + + size_t total = non_nmethod.size + profiled.size + non_profiled.size; + if (total != cache_size && !cache_size_set) { + log_info(codecache)("ReservedCodeCache size " SIZE_FORMAT "K changed to total segments size NonNMethod " + SIZE_FORMAT "K NonProfiled " SIZE_FORMAT "K Profiled " SIZE_FORMAT "K = " SIZE_FORMAT "K", + cache_size/K, non_nmethod.size/K, non_profiled.size/K, profiled.size/K, total/K); + // Adjust ReservedCodeCacheSize as necessary because it was not set explicitly + cache_size = total; + } + + log_debug(codecache)("Initializing code heaps ReservedCodeCache " SIZE_FORMAT "K NonNMethod " SIZE_FORMAT "K" + " NonProfiled " SIZE_FORMAT "K Profiled " SIZE_FORMAT "K", + cache_size/K, non_nmethod.size/K, non_profiled.size/K, profiled.size/K); + + // Validation + // Check minimal required sizes + check_min_size("non-nmethod code heap", non_nmethod.size, non_nmethod_min_size); + if (profiled.enabled) { + check_min_size("profiled code heap", profiled.size, min_size); } - // We do not need the non-profiled CodeHeap, use all space for the non-nmethod CodeHeap - if (!heap_available(CodeBlobType::MethodNonProfiled)) { - non_nmethod_size += non_profiled_size; - non_profiled_size = 0; + if (non_profiled.enabled) { // non_profiled.enabled is always ON for segmented code heap, leave it checked for clarity + check_min_size("non-profiled code heap", non_profiled.size, min_size); } - // Make sure we have enough space for VM internal code - uint min_code_cache_size = CodeCacheMinimumUseSpace DEBUG_ONLY(* 3); - if (non_nmethod_size < min_code_cache_size) { - vm_exit_during_initialization(err_msg( - "Not enough space in non-nmethod code heap to run VM: " SIZE_FORMAT "K < " SIZE_FORMAT "K", - non_nmethod_size/K, min_code_cache_size/K)); + if (cache_size_set) { + check_min_size("reserved code cache", cache_size, min_cache_size); } - // Verify sizes and update flag values - assert(non_profiled_size + profiled_size + non_nmethod_size == cache_size, "Invalid code heap sizes"); - FLAG_SET_ERGO(NonNMethodCodeHeapSize, non_nmethod_size); - FLAG_SET_ERGO(ProfiledCodeHeapSize, profiled_size); - FLAG_SET_ERGO(NonProfiledCodeHeapSize, non_profiled_size); + // ReservedCodeCacheSize was set explicitly, so report an error and abort if it doesn't match the segment sizes + if (total != cache_size && cache_size_set) { + err_msg message("NonNMethodCodeHeapSize (" SIZE_FORMAT "K)", non_nmethod.size/K); + if (profiled.enabled) { + message.append(" + ProfiledCodeHeapSize (" SIZE_FORMAT "K)", profiled.size/K); + } + if (non_profiled.enabled) { + message.append(" + NonProfiledCodeHeapSize (" SIZE_FORMAT "K)", non_profiled.size/K); + } + message.append(" = " SIZE_FORMAT "K", total/K); + message.append((total > cache_size) ? " is greater than " : " is less than "); + message.append("ReservedCodeCacheSize (" SIZE_FORMAT "K).", cache_size/K); - // Print warning if using large pages but not able to use the size given + vm_exit_during_initialization("Invalid code heap sizes", message); + } + + // Compatibility. Print warning if using large pages but not able to use the size given if (UseLargePages) { const size_t lg_ps = page_size(false, 1); if (ps < lg_ps) { @@ -326,32 +303,40 @@ void CodeCache::initialize_heaps() { // Note: if large page support is enabled, min_size is at least the large // page size. This ensures that the code cache is covered by large pages. - non_nmethod_size = align_up(non_nmethod_size, min_size); - profiled_size = align_down(profiled_size, min_size); - non_profiled_size = align_down(non_profiled_size, min_size); - - // Reserve one continuous chunk of memory for CodeHeaps and split it into - // parts for the individual heaps. The memory layout looks like this: - // ---------- high ----------- - // Non-profiled nmethods - // Non-nmethods - // Profiled nmethods - // ---------- low ------------ + non_profiled.size += non_nmethod.size & alignment_mask(min_size); + non_profiled.size += profiled.size & alignment_mask(min_size); + non_nmethod.size = align_down(non_nmethod.size, min_size); + profiled.size = align_down(profiled.size, min_size); + non_profiled.size = align_down(non_profiled.size, min_size); + + FLAG_SET_ERGO(NonNMethodCodeHeapSize, non_nmethod.size); + FLAG_SET_ERGO(ProfiledCodeHeapSize, profiled.size); + FLAG_SET_ERGO(NonProfiledCodeHeapSize, non_profiled.size); + FLAG_SET_ERGO(ReservedCodeCacheSize, cache_size); + ReservedCodeSpace rs = reserve_heap_memory(cache_size, ps); - ReservedSpace profiled_space = rs.first_part(profiled_size); - ReservedSpace rest = rs.last_part(profiled_size); - ReservedSpace non_method_space = rest.first_part(non_nmethod_size); - ReservedSpace non_profiled_space = rest.last_part(non_nmethod_size); // Register CodeHeaps with LSan as we sometimes embed pointers to malloc memory. LSAN_REGISTER_ROOT_REGION(rs.base(), rs.size()); + size_t offset = 0; + if (profiled.enabled) { + ReservedSpace profiled_space = rs.partition(offset, profiled.size); + offset += profiled.size; + // Tier 2 and tier 3 (profiled) methods + add_heap(profiled_space, "CodeHeap 'profiled nmethods'", CodeBlobType::MethodProfiled); + } + + ReservedSpace non_method_space = rs.partition(offset, non_nmethod.size); + offset += non_nmethod.size; // Non-nmethods (stubs, adapters, ...) add_heap(non_method_space, "CodeHeap 'non-nmethods'", CodeBlobType::NonNMethod); - // Tier 2 and tier 3 (profiled) methods - add_heap(profiled_space, "CodeHeap 'profiled nmethods'", CodeBlobType::MethodProfiled); - // Tier 1 and tier 4 (non-profiled) methods and native methods - add_heap(non_profiled_space, "CodeHeap 'non-profiled nmethods'", CodeBlobType::MethodNonProfiled); + + if (non_profiled.enabled) { + ReservedSpace non_profiled_space = rs.partition(offset, non_profiled.size); + // Tier 1 and tier 4 (non-profiled) methods and native methods + add_heap(non_profiled_space, "CodeHeap 'non-profiled nmethods'", CodeBlobType::MethodNonProfiled); + } } size_t CodeCache::page_size(bool aligned, size_t min_pages) { @@ -424,9 +409,6 @@ void CodeCache::add_heap(CodeHeap* heap) { _heaps->insert_sorted(heap); CodeBlobType type = heap->code_blob_type(); - if (code_blob_type_accepts_compiled(type)) { - _compiled_heaps->insert_sorted(heap); - } if (code_blob_type_accepts_nmethod(type)) { _nmethod_heaps->insert_sorted(heap); } @@ -669,7 +651,7 @@ CodeBlob* CodeCache::find_blob(void* start) { nmethod* CodeCache::find_nmethod(void* start) { CodeBlob* cb = find_blob(start); - assert(cb->is_nmethod(), "did not find an nmethod"); + assert(cb == nullptr || cb->is_nmethod(), "did not find an nmethod"); return (nmethod*)cb; } @@ -684,15 +666,23 @@ void CodeCache::blobs_do(void f(CodeBlob* nm)) { void CodeCache::nmethods_do(void f(nmethod* nm)) { assert_locked_or_safepoint(CodeCache_lock); - NMethodIterator iter(NMethodIterator::all_blobs); + NMethodIterator iter(NMethodIterator::all); while(iter.next()) { f(iter.method()); } } +void CodeCache::nmethods_do(NMethodClosure* cl) { + assert_locked_or_safepoint(CodeCache_lock); + NMethodIterator iter(NMethodIterator::all); + while(iter.next()) { + cl->do_nmethod(iter.method()); + } +} + void CodeCache::metadata_do(MetadataClosure* f) { assert_locked_or_safepoint(CodeCache_lock); - NMethodIterator iter(NMethodIterator::all_blobs); + NMethodIterator iter(NMethodIterator::all); while(iter.next()) { iter.method()->metadata_do(f); } @@ -882,29 +872,15 @@ void CodeCache::arm_all_nmethods() { // Mark nmethods for unloading if they contain otherwise unreachable oops. void CodeCache::do_unloading(bool unloading_occurred) { assert_locked_or_safepoint(CodeCache_lock); - CompiledMethodIterator iter(CompiledMethodIterator::all_blobs); + NMethodIterator iter(NMethodIterator::all); while(iter.next()) { iter.method()->do_unloading(unloading_occurred); } } -void CodeCache::blobs_do(CodeBlobClosure* f) { - assert_locked_or_safepoint(CodeCache_lock); - FOR_ALL_ALLOCABLE_HEAPS(heap) { - FOR_ALL_BLOBS(cb, *heap) { - f->do_code_blob(cb); -#ifdef ASSERT - if (cb->is_nmethod()) { - Universe::heap()->verify_nmethod((nmethod*)cb); - } -#endif //ASSERT - } - } -} - void CodeCache::verify_clean_inline_caches() { #ifdef ASSERT - NMethodIterator iter(NMethodIterator::only_not_unloading); + NMethodIterator iter(NMethodIterator::not_unloading); while(iter.next()) { nmethod* nm = iter.method(); nm->verify_clean_inline_caches(); @@ -983,7 +959,7 @@ CodeCache::UnlinkingScope::~UnlinkingScope() { void CodeCache::verify_oops() { MutexLocker mu(CodeCache_lock, Mutex::_no_safepoint_check_flag); VerifyOopClosure voc; - NMethodIterator iter(NMethodIterator::only_not_unloading); + NMethodIterator iter(NMethodIterator::not_unloading); while(iter.next()) { nmethod* nm = iter.method(); nm->oops_do(&voc); @@ -1011,8 +987,8 @@ int CodeCache::nmethod_count(CodeBlobType code_blob_type) { int CodeCache::nmethod_count() { int count = 0; - FOR_ALL_NMETHOD_HEAPS(heap) { - count += (*heap)->nmethod_count(); + for (CodeHeap* heap : *_nmethod_heaps) { + count += heap->nmethod_count(); } return count; } @@ -1178,7 +1154,7 @@ bool CodeCache::has_nmethods_with_dependencies() { void CodeCache::clear_inline_caches() { assert_locked_or_safepoint(CodeCache_lock); - CompiledMethodIterator iter(CompiledMethodIterator::only_not_unloading); + NMethodIterator iter(NMethodIterator::not_unloading); while(iter.next()) { iter.method()->clear_inline_caches(); } @@ -1187,7 +1163,7 @@ void CodeCache::clear_inline_caches() { // Only used by whitebox API void CodeCache::cleanup_inline_caches_whitebox() { assert_locked_or_safepoint(CodeCache_lock); - NMethodIterator iter(NMethodIterator::only_not_unloading); + NMethodIterator iter(NMethodIterator::not_unloading); while(iter.next()) { iter.method()->cleanup_inline_caches_whitebox(); } @@ -1215,7 +1191,7 @@ static void check_live_nmethods_dependencies(DepChange& changes) { // Iterate over live nmethods and check dependencies of all nmethods that are not // marked for deoptimization. A particular dependency is only checked once. - NMethodIterator iter(NMethodIterator::only_not_unloading); + NMethodIterator iter(NMethodIterator::not_unloading); while(iter.next()) { nmethod* nm = iter.method(); // Only notify for live nmethods @@ -1271,38 +1247,32 @@ void CodeCache::mark_for_deoptimization(DeoptimizationScope* deopt_scope, KlassD #endif } -CompiledMethod* CodeCache::find_compiled(void* start) { - CodeBlob *cb = find_blob(start); - assert(cb == nullptr || cb->is_compiled(), "did not find an compiled_method"); - return (CompiledMethod*)cb; -} - #if INCLUDE_JVMTI // RedefineClasses support for saving nmethods that are dependent on "old" methods. // We don't really expect this table to grow very large. If it does, it can become a hashtable. -static GrowableArray* old_compiled_method_table = nullptr; +static GrowableArray* old_nmethod_table = nullptr; -static void add_to_old_table(CompiledMethod* c) { - if (old_compiled_method_table == nullptr) { - old_compiled_method_table = new (mtCode) GrowableArray(100, mtCode); +static void add_to_old_table(nmethod* c) { + if (old_nmethod_table == nullptr) { + old_nmethod_table = new (mtCode) GrowableArray(100, mtCode); } - old_compiled_method_table->push(c); + old_nmethod_table->push(c); } static void reset_old_method_table() { - if (old_compiled_method_table != nullptr) { - delete old_compiled_method_table; - old_compiled_method_table = nullptr; + if (old_nmethod_table != nullptr) { + delete old_nmethod_table; + old_nmethod_table = nullptr; } } // Remove this method when flushed. -void CodeCache::unregister_old_nmethod(CompiledMethod* c) { +void CodeCache::unregister_old_nmethod(nmethod* c) { assert_lock_strong(CodeCache_lock); - if (old_compiled_method_table != nullptr) { - int index = old_compiled_method_table->find(c); + if (old_nmethod_table != nullptr) { + int index = old_nmethod_table->find(c); if (index != -1) { - old_compiled_method_table->delete_at(index); + old_nmethod_table->delete_at(index); } } } @@ -1310,13 +1280,13 @@ void CodeCache::unregister_old_nmethod(CompiledMethod* c) { void CodeCache::old_nmethods_do(MetadataClosure* f) { // Walk old method table and mark those on stack. int length = 0; - if (old_compiled_method_table != nullptr) { - length = old_compiled_method_table->length(); + if (old_nmethod_table != nullptr) { + length = old_nmethod_table->length(); for (int i = 0; i < length; i++) { // Walk all methods saved on the last pass. Concurrent class unloading may // also be looking at this method's metadata, so don't delete it yet if // it is marked as unloaded. - old_compiled_method_table->at(i)->metadata_do(f); + old_nmethod_table->at(i)->metadata_do(f); } } log_debug(redefine, class, nmethod)("Walked %d nmethods for mark_on_stack", length); @@ -1329,9 +1299,9 @@ void CodeCache::mark_dependents_for_evol_deoptimization(DeoptimizationScope* deo // So delete old method table and create a new one. reset_old_method_table(); - CompiledMethodIterator iter(CompiledMethodIterator::all_blobs); + NMethodIterator iter(NMethodIterator::all); while(iter.next()) { - CompiledMethod* nm = iter.method(); + nmethod* nm = iter.method(); // Walk all alive nmethods to check for old Methods. // This includes methods whose inline caches point to old methods, so // inline cache clearing is unnecessary. @@ -1344,9 +1314,9 @@ void CodeCache::mark_dependents_for_evol_deoptimization(DeoptimizationScope* deo void CodeCache::mark_all_nmethods_for_evol_deoptimization(DeoptimizationScope* deopt_scope) { assert(SafepointSynchronize::is_at_safepoint(), "Can only do this at a safepoint!"); - CompiledMethodIterator iter(CompiledMethodIterator::all_blobs); + NMethodIterator iter(NMethodIterator::all); while(iter.next()) { - CompiledMethod* nm = iter.method(); + nmethod* nm = iter.method(); if (!nm->method()->is_method_handle_intrinsic()) { if (nm->can_be_deoptimized()) { deopt_scope->mark(nm); @@ -1365,9 +1335,9 @@ void CodeCache::mark_directives_matches(bool top_only) { Thread *thread = Thread::current(); HandleMark hm(thread); - CompiledMethodIterator iter(CompiledMethodIterator::only_not_unloading); + NMethodIterator iter(NMethodIterator::not_unloading); while(iter.next()) { - CompiledMethod* nm = iter.method(); + nmethod* nm = iter.method(); methodHandle mh(thread, nm->method()); if (DirectivesStack::hasMatchingDirectives(mh, top_only)) { ResourceMark rm; @@ -1383,9 +1353,9 @@ void CodeCache::recompile_marked_directives_matches() { // Try the max level and let the directives be applied during the compilation. int comp_level = CompilationPolicy::highest_compile_level(); - RelaxedCompiledMethodIterator iter(RelaxedCompiledMethodIterator::only_not_unloading); + RelaxedNMethodIterator iter(RelaxedNMethodIterator::not_unloading); while(iter.next()) { - CompiledMethod* nm = iter.method(); + nmethod* nm = iter.method(); methodHandle mh(thread, nm->method()); if (mh->has_matching_directives()) { ResourceMark rm; @@ -1424,9 +1394,9 @@ void CodeCache::recompile_marked_directives_matches() { // Mark methods for deopt (if safe or possible). void CodeCache::mark_all_nmethods_for_deoptimization(DeoptimizationScope* deopt_scope) { MutexLocker mu(CodeCache_lock, Mutex::_no_safepoint_check_flag); - CompiledMethodIterator iter(CompiledMethodIterator::only_not_unloading); + NMethodIterator iter(NMethodIterator::not_unloading); while(iter.next()) { - CompiledMethod* nm = iter.method(); + nmethod* nm = iter.method(); if (!nm->is_native_method()) { deopt_scope->mark(nm); } @@ -1436,9 +1406,9 @@ void CodeCache::mark_all_nmethods_for_deoptimization(DeoptimizationScope* deopt_ void CodeCache::mark_for_deoptimization(DeoptimizationScope* deopt_scope, Method* dependee) { MutexLocker mu(CodeCache_lock, Mutex::_no_safepoint_check_flag); - CompiledMethodIterator iter(CompiledMethodIterator::only_not_unloading); + NMethodIterator iter(NMethodIterator::not_unloading); while(iter.next()) { - CompiledMethod* nm = iter.method(); + nmethod* nm = iter.method(); if (nm->is_dependent_on_method(dependee)) { deopt_scope->mark(nm); } @@ -1446,9 +1416,9 @@ void CodeCache::mark_for_deoptimization(DeoptimizationScope* deopt_scope, Method } void CodeCache::make_marked_nmethods_deoptimized() { - RelaxedCompiledMethodIterator iter(RelaxedCompiledMethodIterator::only_not_unloading); + RelaxedNMethodIterator iter(RelaxedNMethodIterator::not_unloading); while(iter.next()) { - CompiledMethod* nm = iter.method(); + nmethod* nm = iter.method(); if (nm->is_marked_for_deoptimization() && !nm->has_been_deoptimized() && nm->can_be_deoptimized()) { nm->make_not_entrant(); nm->make_deoptimized(); @@ -1658,7 +1628,7 @@ void CodeCache::print_internals() { int *buckets = NEW_C_HEAP_ARRAY(int, bucketLimit, mtCode); memset(buckets, 0, sizeof(int) * bucketLimit); - NMethodIterator iter(NMethodIterator::all_blobs); + NMethodIterator iter(NMethodIterator::all); while(iter.next()) { nmethod* nm = iter.method(); if(nm->method() != nullptr && nm->is_java_method()) { @@ -1849,15 +1819,15 @@ void CodeCache::print_summary(outputStream* st, bool detailed) { void CodeCache::print_codelist(outputStream* st) { MutexLocker mu(CodeCache_lock, Mutex::_no_safepoint_check_flag); - CompiledMethodIterator iter(CompiledMethodIterator::only_not_unloading); + NMethodIterator iter(NMethodIterator::not_unloading); while (iter.next()) { - CompiledMethod* cm = iter.method(); + nmethod* nm = iter.method(); ResourceMark rm; - char* method_name = cm->method()->name_and_sig_as_C_string(); + char* method_name = nm->method()->name_and_sig_as_C_string(); st->print_cr("%d %d %d %s [" INTPTR_FORMAT ", " INTPTR_FORMAT " - " INTPTR_FORMAT "]", - cm->compile_id(), cm->comp_level(), cm->get_state(), + nm->compile_id(), nm->comp_level(), nm->get_state(), method_name, - (intptr_t)cm->header_begin(), (intptr_t)cm->code_begin(), (intptr_t)cm->code_end()); + (intptr_t)nm->header_begin(), (intptr_t)nm->code_begin(), (intptr_t)nm->code_end()); } } @@ -1892,13 +1862,13 @@ void CodeCache::write_perf_map(const char* filename) { return; } - AllCodeBlobsIterator iter(AllCodeBlobsIterator::only_not_unloading); + AllCodeBlobsIterator iter(AllCodeBlobsIterator::not_unloading); while (iter.next()) { CodeBlob *cb = iter.method(); ResourceMark rm; const char* method_name = - cb->is_compiled() ? cb->as_compiled_method()->method()->external_name() - : cb->name(); + cb->is_nmethod() ? cb->as_nmethod()->method()->external_name() + : cb->name(); fs.print_cr(INTPTR_FORMAT " " INTPTR_FORMAT " %s", (intptr_t)cb->code_begin(), (intptr_t)cb->code_size(), method_name); diff --git a/src/hotspot/share/code/codeCache.hpp b/src/hotspot/share/code/codeCache.hpp index eb4759d7ea4..7d8835abd11 100644 --- a/src/hotspot/share/code/codeCache.hpp +++ b/src/hotspot/share/code/codeCache.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 @@ -83,14 +83,13 @@ class DeoptimizationScope; class CodeCache : AllStatic { friend class VMStructs; friend class JVMCIVMStructs; - template friend class CodeBlobIterator; + template friend class CodeBlobIterator; friend class WhiteBox; friend class CodeCacheLoader; friend class ShenandoahParallelCodeHeapIterator; private: // CodeHeaps of the cache static GrowableArray* _heaps; - static GrowableArray* _compiled_heaps; static GrowableArray* _nmethod_heaps; static GrowableArray* _allocable_heaps; @@ -111,8 +110,7 @@ class CodeCache : AllStatic { // CodeHeap management static void initialize_heaps(); // Initializes the CodeHeaps - // Check the code heap sizes set by the user via command line - static void check_heap_sizes(size_t non_nmethod_size, size_t profiled_size, size_t non_profiled_size, size_t cache_size, bool all_set); + // Creates a new heap with the given name and size, containing CodeBlobs of the given type static void add_heap(ReservedSpace rs, const char* name, CodeBlobType code_blob_type); static CodeHeap* get_code_heap_containing(void* p); // Returns the CodeHeap containing the given pointer, or nullptr @@ -144,7 +142,6 @@ class CodeCache : AllStatic { static void add_heap(CodeHeap* heap); static const GrowableArray* heaps() { return _heaps; } - static const GrowableArray* compiled_heaps() { return _compiled_heaps; } static const GrowableArray* nmethod_heaps() { return _nmethod_heaps; } // Allocation/administration @@ -155,8 +152,8 @@ class CodeCache : AllStatic { static bool contains(void *p); // returns whether p is included static bool contains(nmethod* nm); // returns whether nm is included static void blobs_do(void f(CodeBlob* cb)); // iterates over all CodeBlobs - static void blobs_do(CodeBlobClosure* f); // iterates over all CodeBlobs static void nmethods_do(void f(nmethod* nm)); // iterates over all nmethods + static void nmethods_do(NMethodClosure* cl); // iterates over all nmethods static void metadata_do(MetadataClosure* f); // iterates over metadata in alive nmethods // Lookup @@ -165,7 +162,6 @@ class CodeCache : AllStatic { static CodeBlob* find_blob_and_oopmap(void* start, int& slot); // Returns the CodeBlob containing the given address static int find_oopmap_slot_fast(void* start); // Returns a fast oopmap slot if there is any; -1 otherwise static nmethod* find_nmethod(void* start); // Returns the nmethod containing the given address - static CompiledMethod* find_compiled(void* start); static int blob_count(); // Returns the total number of CodeBlobs in the cache static int blob_count(CodeBlobType code_blob_type); @@ -258,14 +254,9 @@ class CodeCache : AllStatic { // Returns true if an own CodeHeap for the given CodeBlobType is available static bool heap_available(CodeBlobType code_blob_type); - // Returns the CodeBlobType for the given CompiledMethod - static CodeBlobType get_code_blob_type(CompiledMethod* cm) { - return get_code_heap(cm)->code_blob_type(); - } - - static bool code_blob_type_accepts_compiled(CodeBlobType code_blob_type) { - bool result = code_blob_type == CodeBlobType::All || code_blob_type <= CodeBlobType::MethodProfiled; - return result; + // Returns the CodeBlobType for the given nmethod + static CodeBlobType get_code_blob_type(nmethod* nm) { + return get_code_heap(nm)->code_blob_type(); } static bool code_blob_type_accepts_nmethod(CodeBlobType type) { @@ -315,7 +306,7 @@ class CodeCache : AllStatic { static void mark_dependents_for_evol_deoptimization(DeoptimizationScope* deopt_scope); static void mark_all_nmethods_for_evol_deoptimization(DeoptimizationScope* deopt_scope); static void old_nmethods_do(MetadataClosure* f) NOT_JVMTI_RETURN; - static void unregister_old_nmethod(CompiledMethod* c) NOT_JVMTI_RETURN; + static void unregister_old_nmethod(nmethod* c) NOT_JVMTI_RETURN; // Support for fullspeed debugging static void mark_dependents_on_method_for_breakpoint(const methodHandle& dependee); @@ -345,13 +336,13 @@ class CodeCache : AllStatic { // The relaxed iterators only hold the CodeCache_lock across next calls template class CodeBlobIterator : public StackObj { public: - enum LivenessFilter { all_blobs, only_not_unloading }; + enum LivenessFilter { all, not_unloading }; private: CodeBlob* _code_blob; // Current CodeBlob GrowableArrayIterator _heap; GrowableArrayIterator _end; - bool _only_not_unloading; + bool _not_unloading; // Those nmethods that are not unloading void initialize_iteration(T* nm) { } @@ -368,9 +359,9 @@ template class CodeBlobIterator : publi } // Filter is_unloading as required - if (_only_not_unloading) { - CompiledMethod* cm = _code_blob->as_compiled_method_or_null(); - if (cm != nullptr && cm->is_unloading()) { + if (_not_unloading) { + nmethod* nm = _code_blob->as_nmethod_or_null(); + if (nm != nullptr && nm->is_unloading()) { continue; } } @@ -381,7 +372,7 @@ template class CodeBlobIterator : publi public: CodeBlobIterator(LivenessFilter filter, T* nm = nullptr) - : _only_not_unloading(filter == only_not_unloading) + : _not_unloading(filter == not_unloading) { if (Filter::heaps() == nullptr) { // The iterator is supposed to shortcut since we have @@ -442,12 +433,6 @@ template class CodeBlobIterator : publi } }; -struct CompiledMethodFilter { - static bool apply(CodeBlob* cb) { return cb->is_compiled(); } - static const GrowableArray* heaps() { return CodeCache::compiled_heaps(); } -}; - - struct NMethodFilter { static bool apply(CodeBlob* cb) { return cb->is_nmethod(); } static const GrowableArray* heaps() { return CodeCache::nmethod_heaps(); } @@ -458,9 +443,8 @@ struct AllCodeBlobsFilter { static const GrowableArray* heaps() { return CodeCache::heaps(); } }; -typedef CodeBlobIterator CompiledMethodIterator; -typedef CodeBlobIterator RelaxedCompiledMethodIterator; typedef CodeBlobIterator NMethodIterator; +typedef CodeBlobIterator RelaxedNMethodIterator; typedef CodeBlobIterator AllCodeBlobsIterator; #endif // SHARE_CODE_CODECACHE_HPP diff --git a/src/hotspot/share/code/codeHeapState.hpp b/src/hotspot/share/code/codeHeapState.hpp index ad3b03d1303..f30e492d7a5 100644 --- a/src/hotspot/share/code/codeHeapState.hpp +++ b/src/hotspot/share/code/codeHeapState.hpp @@ -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. * Copyright (c) 2018, 2019 SAP SE. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -44,8 +44,8 @@ class CodeHeapState : public CHeapObj { enum blobType { noType = 0, // must be! due to initialization by memset to zero - // The nMethod_* values correspond to the CompiledMethod enum values. - // We can't use the CompiledMethod values 1:1 because we depend on noType == 0. + // The nMethod_* values correspond to the nmethod enum values. + // We can't use the nmethod values 1:1 because we depend on noType == 0. nMethod_inconstruction, // under construction. Very soon, the type will transition to "in_use". // can't be observed while holding Compile_lock and CodeCache_lock simultaneously. // left in here for completeness (and to document we spent a thought). diff --git a/src/hotspot/share/code/compiledIC.cpp b/src/hotspot/share/code/compiledIC.cpp index 250ef063a2a..079c8199b18 100644 --- a/src/hotspot/share/code/compiledIC.cpp +++ b/src/hotspot/share/code/compiledIC.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 @@ -44,7 +44,7 @@ // Every time a compiled IC is changed or its type is being accessed, // either the CompiledIC_lock must be set or we must be at a safe point. -CompiledICLocker::CompiledICLocker(CompiledMethod* method) +CompiledICLocker::CompiledICLocker(nmethod* method) : _method(method), _behaviour(CompiledICProtectionBehaviour::current()), _locked(_behaviour->lock(_method)) { @@ -56,15 +56,15 @@ CompiledICLocker::~CompiledICLocker() { } } -bool CompiledICLocker::is_safe(CompiledMethod* method) { +bool CompiledICLocker::is_safe(nmethod* method) { return CompiledICProtectionBehaviour::current()->is_safe(method); } bool CompiledICLocker::is_safe(address code) { CodeBlob* cb = CodeCache::find_blob(code); - assert(cb != nullptr && cb->is_compiled(), "must be compiled"); - CompiledMethod* cm = cb->as_compiled_method(); - return CompiledICProtectionBehaviour::current()->is_safe(cm); + assert(cb != nullptr && cb->is_nmethod(), "must be compiled"); + nmethod* nm = cb->as_nmethod(); + return CompiledICProtectionBehaviour::current()->is_safe(nm); } CompiledICData::CompiledICData() @@ -167,12 +167,12 @@ CompiledIC::CompiledIC(RelocIterator* iter) assert(CompiledICLocker::is_safe(_method), "mt unsafe call"); } -CompiledIC* CompiledIC_before(CompiledMethod* nm, address return_addr) { +CompiledIC* CompiledIC_before(nmethod* nm, address return_addr) { address call_site = nativeCall_before(return_addr)->instruction_address(); return CompiledIC_at(nm, call_site); } -CompiledIC* CompiledIC_at(CompiledMethod* nm, address call_site) { +CompiledIC* CompiledIC_at(nmethod* nm, address call_site) { RelocIterator iter(nm, call_site, call_site + 1); iter.next(); return CompiledIC_at(&iter); @@ -180,8 +180,8 @@ CompiledIC* CompiledIC_at(CompiledMethod* nm, address call_site) { CompiledIC* CompiledIC_at(Relocation* call_reloc) { address call_site = call_reloc->addr(); - CompiledMethod* cm = CodeCache::find_blob(call_reloc->addr())->as_compiled_method(); - return CompiledIC_at(cm, call_site); + nmethod* nm = CodeCache::find_blob(call_reloc->addr())->as_nmethod(); + return CompiledIC_at(nm, call_site); } CompiledIC* CompiledIC_at(RelocIterator* reloc_iter) { @@ -204,7 +204,7 @@ void CompiledIC::set_to_clean() { void CompiledIC::set_to_monomorphic() { assert(data()->is_initialized(), "must be initialized"); Method* method = data()->speculated_method(); - CompiledMethod* code = method->code(); + nmethod* code = method->code(); address entry; bool to_compiled = code != nullptr && code->is_in_use() && !code->is_unloading(); @@ -321,7 +321,7 @@ void CompiledIC::verify() { // ---------------------------------------------------------------------------- void CompiledDirectCall::set_to_clean() { - // in_use is unused but needed to match template function in CompiledMethod + // in_use is unused but needed to match template function in nmethod assert(CompiledICLocker::is_safe(instruction_address()), "mt unsafe call"); // Reset call site RelocIterator iter((nmethod*)nullptr, instruction_address(), instruction_address() + 1); @@ -343,8 +343,9 @@ void CompiledDirectCall::set_to_clean() { } void CompiledDirectCall::set(const methodHandle& callee_method) { - CompiledMethod* code = callee_method->code(); - CompiledMethod* caller = CodeCache::find_compiled(instruction_address()); + nmethod* code = callee_method->code(); + nmethod* caller = CodeCache::find_nmethod(instruction_address()); + assert(caller != nullptr, "did not find caller nmethod"); bool to_interp_cont_enter = caller->method()->is_continuation_enter_intrinsic() && ContinuationEntry::is_interpreted_call(instruction_address()); @@ -377,14 +378,16 @@ bool CompiledDirectCall::is_clean() const { bool CompiledDirectCall::is_call_to_interpreted() const { // It is a call to interpreted, if it calls to a stub. Hence, the destination // must be in the stub part of the nmethod that contains the call - CompiledMethod* cm = CodeCache::find_compiled(instruction_address()); - return cm->stub_contains(destination()); + nmethod* nm = CodeCache::find_nmethod(instruction_address()); + assert(nm != nullptr, "did not find nmethod"); + return nm->stub_contains(destination()); } bool CompiledDirectCall::is_call_to_compiled() const { - CompiledMethod* caller = CodeCache::find_compiled(instruction_address()); + nmethod* caller = CodeCache::find_nmethod(instruction_address()); + assert(caller != nullptr, "did not find caller nmethod"); CodeBlob* dest_cb = CodeCache::find_blob(destination()); - return !caller->stub_contains(destination()) && dest_cb->is_compiled(); + return !caller->stub_contains(destination()) && dest_cb->is_nmethod(); } address CompiledDirectCall::find_stub_for(address instruction) { diff --git a/src/hotspot/share/code/compiledIC.hpp b/src/hotspot/share/code/compiledIC.hpp index 321bf280ed4..4439ff958f7 100644 --- a/src/hotspot/share/code/compiledIC.hpp +++ b/src/hotspot/share/code/compiledIC.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 @@ -39,18 +39,18 @@ // class CompiledIC; class CompiledICProtectionBehaviour; -class CompiledMethod; +class nmethod; class CompiledICLocker: public StackObj { - CompiledMethod* _method; + nmethod* _method; CompiledICProtectionBehaviour* _behaviour; bool _locked; NoSafepointVerifier _nsv; public: - CompiledICLocker(CompiledMethod* method); + CompiledICLocker(nmethod* method); ~CompiledICLocker(); - static bool is_safe(CompiledMethod* method); + static bool is_safe(nmethod* method); static bool is_safe(address code); }; @@ -98,7 +98,7 @@ class CompiledICData : public CHeapObj { class CompiledIC: public ResourceObj { private: - CompiledMethod* _method; + nmethod* _method; CompiledICData* _data; NativeCall* _call; @@ -114,8 +114,8 @@ class CompiledIC: public ResourceObj { public: // conversion (machine PC to CompiledIC*) - friend CompiledIC* CompiledIC_before(CompiledMethod* nm, address return_addr); - friend CompiledIC* CompiledIC_at(CompiledMethod* nm, address call_site); + friend CompiledIC* CompiledIC_before(nmethod* nm, address return_addr); + friend CompiledIC* CompiledIC_at(nmethod* nm, address call_site); friend CompiledIC* CompiledIC_at(Relocation* call_site); friend CompiledIC* CompiledIC_at(RelocIterator* reloc_iter); @@ -146,8 +146,8 @@ class CompiledIC: public ResourceObj { void verify() PRODUCT_RETURN; }; -CompiledIC* CompiledIC_before(CompiledMethod* nm, address return_addr); -CompiledIC* CompiledIC_at(CompiledMethod* nm, address call_site); +CompiledIC* CompiledIC_before(nmethod* nm, address return_addr); +CompiledIC* CompiledIC_at(nmethod* nm, address call_site); CompiledIC* CompiledIC_at(Relocation* call_site); CompiledIC* CompiledIC_at(RelocIterator* reloc_iter); diff --git a/src/hotspot/share/code/compiledMethod.cpp b/src/hotspot/share/code/compiledMethod.cpp deleted file mode 100644 index 6553d6f7934..00000000000 --- a/src/hotspot/share/code/compiledMethod.cpp +++ /dev/null @@ -1,647 +0,0 @@ -/* - * 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. - * - */ - -#include "precompiled.hpp" -#include "code/compiledIC.hpp" -#include "code/compiledMethod.inline.hpp" -#include "code/exceptionHandlerTable.hpp" -#include "code/scopeDesc.hpp" -#include "code/codeCache.hpp" -#include "gc/shared/barrierSet.hpp" -#include "gc/shared/barrierSetNMethod.hpp" -#include "gc/shared/gcBehaviours.hpp" -#include "interpreter/bytecode.inline.hpp" -#include "logging/log.hpp" -#include "logging/logTag.hpp" -#include "memory/resourceArea.hpp" -#include "oops/klass.inline.hpp" -#include "oops/methodData.hpp" -#include "oops/method.inline.hpp" -#include "oops/weakHandle.inline.hpp" -#include "prims/methodHandles.hpp" -#include "runtime/atomic.hpp" -#include "runtime/deoptimization.hpp" -#include "runtime/frame.inline.hpp" -#include "runtime/jniHandles.inline.hpp" -#include "runtime/handles.inline.hpp" -#include "runtime/mutexLocker.hpp" -#include "runtime/sharedRuntime.hpp" - -CompiledMethod::CompiledMethod(Method* method, const char* name, CompilerType type, const CodeBlobLayout& layout, - int frame_complete_offset, int frame_size, ImmutableOopMapSet* oop_maps, - bool caller_must_gc_arguments, bool compiled) - : CodeBlob(name, type, layout, frame_complete_offset, frame_size, oop_maps, caller_must_gc_arguments, compiled), - _deoptimization_status(not_marked), - _deoptimization_generation(0), - _method(method), - _gc_data(nullptr) -{ - init_defaults(); -} - -CompiledMethod::CompiledMethod(Method* method, const char* name, CompilerType type, int size, - int header_size, CodeBuffer* cb, int frame_complete_offset, int frame_size, - OopMapSet* oop_maps, bool caller_must_gc_arguments, bool compiled) - : CodeBlob(name, type, CodeBlobLayout((address) this, size, header_size, cb), cb, - frame_complete_offset, frame_size, oop_maps, caller_must_gc_arguments, compiled), - _deoptimization_status(not_marked), - _deoptimization_generation(0), - _method(method), - _gc_data(nullptr) -{ - init_defaults(); -} - -void CompiledMethod::init_defaults() { - { // avoid uninitialized fields, even for short time periods - _scopes_data_begin = nullptr; - _deopt_handler_begin = nullptr; - _deopt_mh_handler_begin = nullptr; - _exception_cache = nullptr; - } - _has_unsafe_access = 0; - _has_method_handle_invokes = 0; - _has_wide_vectors = 0; - _has_monitors = 0; -} - -bool CompiledMethod::is_method_handle_return(address return_pc) { - if (!has_method_handle_invokes()) return false; - PcDesc* pd = pc_desc_at(return_pc); - if (pd == nullptr) - return false; - return pd->is_method_handle_invoke(); -} - -// Returns a string version of the method state. -const char* CompiledMethod::state() const { - int state = get_state(); - switch (state) { - case not_installed: - return "not installed"; - case in_use: - return "in use"; - case not_used: - return "not_used"; - case not_entrant: - return "not_entrant"; - default: - fatal("unexpected method state: %d", state); - return nullptr; - } -} - -//----------------------------------------------------------------------------- -void CompiledMethod::set_deoptimized_done() { - ConditionalMutexLocker ml(CompiledMethod_lock, !CompiledMethod_lock->owned_by_self(), Mutex::_no_safepoint_check_flag); - if (_deoptimization_status != deoptimize_done) { // can't go backwards - Atomic::store(&_deoptimization_status, deoptimize_done); - } -} - -//----------------------------------------------------------------------------- - -ExceptionCache* CompiledMethod::exception_cache_acquire() const { - return Atomic::load_acquire(&_exception_cache); -} - -void CompiledMethod::add_exception_cache_entry(ExceptionCache* new_entry) { - assert(ExceptionCache_lock->owned_by_self(),"Must hold the ExceptionCache_lock"); - assert(new_entry != nullptr,"Must be non null"); - assert(new_entry->next() == nullptr, "Must be null"); - - for (;;) { - ExceptionCache *ec = exception_cache(); - if (ec != nullptr) { - Klass* ex_klass = ec->exception_type(); - if (!ex_klass->is_loader_alive()) { - // We must guarantee that entries are not inserted with new next pointer - // edges to ExceptionCache entries with dead klasses, due to bad interactions - // with concurrent ExceptionCache cleanup. Therefore, the inserts roll - // the head pointer forward to the first live ExceptionCache, so that the new - // next pointers always point at live ExceptionCaches, that are not removed due - // to concurrent ExceptionCache cleanup. - ExceptionCache* next = ec->next(); - if (Atomic::cmpxchg(&_exception_cache, ec, next) == ec) { - CodeCache::release_exception_cache(ec); - } - continue; - } - ec = exception_cache(); - if (ec != nullptr) { - new_entry->set_next(ec); - } - } - if (Atomic::cmpxchg(&_exception_cache, ec, new_entry) == ec) { - return; - } - } -} - -void CompiledMethod::clean_exception_cache() { - // For each nmethod, only a single thread may call this cleanup function - // at the same time, whether called in STW cleanup or concurrent cleanup. - // Note that if the GC is processing exception cache cleaning in a concurrent phase, - // then a single writer may contend with cleaning up the head pointer to the - // first ExceptionCache node that has a Klass* that is alive. That is fine, - // as long as there is no concurrent cleanup of next pointers from concurrent writers. - // And the concurrent writers do not clean up next pointers, only the head. - // Also note that concurrent readers will walk through Klass* pointers that are not - // alive. That does not cause ABA problems, because Klass* is deleted after - // a handshake with all threads, after all stale ExceptionCaches have been - // unlinked. That is also when the CodeCache::exception_cache_purge_list() - // is deleted, with all ExceptionCache entries that were cleaned concurrently. - // That similarly implies that CAS operations on ExceptionCache entries do not - // suffer from ABA problems as unlinking and deletion is separated by a global - // handshake operation. - ExceptionCache* prev = nullptr; - ExceptionCache* curr = exception_cache_acquire(); - - while (curr != nullptr) { - ExceptionCache* next = curr->next(); - - if (!curr->exception_type()->is_loader_alive()) { - if (prev == nullptr) { - // Try to clean head; this is contended by concurrent inserts, that - // both lazily clean the head, and insert entries at the head. If - // the CAS fails, the operation is restarted. - if (Atomic::cmpxchg(&_exception_cache, curr, next) != curr) { - prev = nullptr; - curr = exception_cache_acquire(); - continue; - } - } else { - // It is impossible to during cleanup connect the next pointer to - // an ExceptionCache that has not been published before a safepoint - // prior to the cleanup. Therefore, release is not required. - prev->set_next(next); - } - // prev stays the same. - - CodeCache::release_exception_cache(curr); - } else { - prev = curr; - } - - curr = next; - } -} - -// public method for accessing the exception cache -// These are the public access methods. -address CompiledMethod::handler_for_exception_and_pc(Handle exception, address pc) { - // We never grab a lock to read the exception cache, so we may - // have false negatives. This is okay, as it can only happen during - // the first few exception lookups for a given nmethod. - ExceptionCache* ec = exception_cache_acquire(); - while (ec != nullptr) { - address ret_val; - if ((ret_val = ec->match(exception,pc)) != nullptr) { - return ret_val; - } - ec = ec->next(); - } - return nullptr; -} - -void CompiledMethod::add_handler_for_exception_and_pc(Handle exception, address pc, address handler) { - // There are potential race conditions during exception cache updates, so we - // must own the ExceptionCache_lock before doing ANY modifications. Because - // we don't lock during reads, it is possible to have several threads attempt - // to update the cache with the same data. We need to check for already inserted - // copies of the current data before adding it. - - MutexLocker ml(ExceptionCache_lock); - ExceptionCache* target_entry = exception_cache_entry_for_exception(exception); - - if (target_entry == nullptr || !target_entry->add_address_and_handler(pc,handler)) { - target_entry = new ExceptionCache(exception,pc,handler); - add_exception_cache_entry(target_entry); - } -} - -// private method for handling exception cache -// These methods are private, and used to manipulate the exception cache -// directly. -ExceptionCache* CompiledMethod::exception_cache_entry_for_exception(Handle exception) { - ExceptionCache* ec = exception_cache_acquire(); - while (ec != nullptr) { - if (ec->match_exception_with_space(exception)) { - return ec; - } - ec = ec->next(); - } - return nullptr; -} - -//-------------end of code for ExceptionCache-------------- - -bool CompiledMethod::is_at_poll_return(address pc) { - RelocIterator iter(this, pc, pc+1); - while (iter.next()) { - if (iter.type() == relocInfo::poll_return_type) - return true; - } - return false; -} - - -bool CompiledMethod::is_at_poll_or_poll_return(address pc) { - RelocIterator iter(this, pc, pc+1); - while (iter.next()) { - relocInfo::relocType t = iter.type(); - if (t == relocInfo::poll_return_type || t == relocInfo::poll_type) - return true; - } - return false; -} - -void CompiledMethod::verify_oop_relocations() { - // Ensure sure that the code matches the current oop values - RelocIterator iter(this, nullptr, nullptr); - while (iter.next()) { - if (iter.type() == relocInfo::oop_type) { - oop_Relocation* reloc = iter.oop_reloc(); - if (!reloc->oop_is_immediate()) { - reloc->verify_oop_relocation(); - } - } - } -} - - -ScopeDesc* CompiledMethod::scope_desc_at(address pc) { - PcDesc* pd = pc_desc_at(pc); - guarantee(pd != nullptr, "scope must be present"); - return new ScopeDesc(this, pd); -} - -ScopeDesc* CompiledMethod::scope_desc_near(address pc) { - PcDesc* pd = pc_desc_near(pc); - guarantee(pd != nullptr, "scope must be present"); - return new ScopeDesc(this, pd); -} - -address CompiledMethod::oops_reloc_begin() const { - // If the method is not entrant then a JMP is plastered over the - // first few bytes. If an oop in the old code was there, that oop - // should not get GC'd. Skip the first few bytes of oops on - // not-entrant methods. - if (frame_complete_offset() != CodeOffsets::frame_never_safe && - code_begin() + frame_complete_offset() > - verified_entry_point() + NativeJump::instruction_size) - { - // If we have a frame_complete_offset after the native jump, then there - // is no point trying to look for oops before that. This is a requirement - // for being allowed to scan oops concurrently. - return code_begin() + frame_complete_offset(); - } - - // It is not safe to read oops concurrently using entry barriers, if their - // location depend on whether the nmethod is entrant or not. - // assert(BarrierSet::barrier_set()->barrier_set_nmethod() == nullptr, "Not safe oop scan"); - - address low_boundary = verified_entry_point(); - if (!is_in_use() && is_nmethod()) { - low_boundary += NativeJump::instruction_size; - // %%% Note: On SPARC we patch only a 4-byte trap, not a full NativeJump. - // This means that the low_boundary is going to be a little too high. - // This shouldn't matter, since oops of non-entrant methods are never used. - // In fact, why are we bothering to look at oops in a non-entrant method?? - } - return low_boundary; -} - -// Method that knows how to preserve outgoing arguments at call. This method must be -// called with a frame corresponding to a Java invoke -void CompiledMethod::preserve_callee_argument_oops(frame fr, const RegisterMap *reg_map, OopClosure* f) { - if (method() == nullptr) { - return; - } - - // handle the case of an anchor explicitly set in continuation code that doesn't have a callee - JavaThread* thread = reg_map->thread(); - if (thread->has_last_Java_frame() && fr.sp() == thread->last_Java_sp()) { - return; - } - - if (!method()->is_native()) { - address pc = fr.pc(); - bool has_receiver, has_appendix; - Symbol* signature; - - // The method attached by JIT-compilers should be used, if present. - // Bytecode can be inaccurate in such case. - Method* callee = attached_method_before_pc(pc); - if (callee != nullptr) { - has_receiver = !(callee->access_flags().is_static()); - has_appendix = false; - signature = callee->signature(); - } else { - SimpleScopeDesc ssd(this, pc); - - Bytecode_invoke call(methodHandle(Thread::current(), ssd.method()), ssd.bci()); - has_receiver = call.has_receiver(); - has_appendix = call.has_appendix(); - signature = call.signature(); - } - - fr.oops_compiled_arguments_do(signature, has_receiver, has_appendix, reg_map, f); - } else if (method()->is_continuation_enter_intrinsic()) { - // This method only calls Continuation.enter() - Symbol* signature = vmSymbols::continuationEnter_signature(); - fr.oops_compiled_arguments_do(signature, false, false, reg_map, f); - } -} - -Method* CompiledMethod::attached_method(address call_instr) { - assert(code_contains(call_instr), "not part of the nmethod"); - RelocIterator iter(this, call_instr, call_instr + 1); - while (iter.next()) { - if (iter.addr() == call_instr) { - switch(iter.type()) { - case relocInfo::static_call_type: return iter.static_call_reloc()->method_value(); - case relocInfo::opt_virtual_call_type: return iter.opt_virtual_call_reloc()->method_value(); - case relocInfo::virtual_call_type: return iter.virtual_call_reloc()->method_value(); - default: break; - } - } - } - return nullptr; // not found -} - -Method* CompiledMethod::attached_method_before_pc(address pc) { - if (NativeCall::is_call_before(pc)) { - NativeCall* ncall = nativeCall_before(pc); - return attached_method(ncall->instruction_address()); - } - return nullptr; // not a call -} - -void CompiledMethod::clear_inline_caches() { - assert(SafepointSynchronize::is_at_safepoint(), "clearing of IC's only allowed at safepoint"); - RelocIterator iter(this); - while (iter.next()) { - iter.reloc()->clear_inline_cache(); - } -} - -#ifdef ASSERT -// Check class_loader is alive for this bit of metadata. -class CheckClass : public MetadataClosure { - void do_metadata(Metadata* md) { - Klass* klass = nullptr; - if (md->is_klass()) { - klass = ((Klass*)md); - } else if (md->is_method()) { - klass = ((Method*)md)->method_holder(); - } else if (md->is_methodData()) { - klass = ((MethodData*)md)->method()->method_holder(); - } else { - md->print(); - ShouldNotReachHere(); - } - assert(klass->is_loader_alive(), "must be alive"); - } -}; -#endif // ASSERT - - -static void clean_ic_if_metadata_is_dead(CompiledIC *ic) { - ic->clean_metadata(); -} - -// Clean references to unloaded nmethods at addr from this one, which is not unloaded. -template -static void clean_if_nmethod_is_unloaded(CallsiteT* callsite, CompiledMethod* from, - bool clean_all) { - CodeBlob* cb = CodeCache::find_blob(callsite->destination()); - if (!cb->is_compiled()) { - return; - } - CompiledMethod* cm = cb->as_compiled_method(); - if (clean_all || !cm->is_in_use() || cm->is_unloading() || cm->method()->code() != cm) { - callsite->set_to_clean(); - } -} - -// Cleans caches in nmethods that point to either classes that are unloaded -// or nmethods that are unloaded. -// -// Can be called either in parallel by G1 currently or after all -// nmethods are unloaded. Return postponed=true in the parallel case for -// inline caches found that point to nmethods that are not yet visited during -// the do_unloading walk. -void CompiledMethod::unload_nmethod_caches(bool unloading_occurred) { - ResourceMark rm; - - // Exception cache only needs to be called if unloading occurred - if (unloading_occurred) { - clean_exception_cache(); - } - - cleanup_inline_caches_impl(unloading_occurred, false); - -#ifdef ASSERT - // Check that the metadata embedded in the nmethod is alive - CheckClass check_class; - metadata_do(&check_class); -#endif -} - -void CompiledMethod::run_nmethod_entry_barrier() { - BarrierSetNMethod* bs_nm = BarrierSet::barrier_set()->barrier_set_nmethod(); - if (bs_nm != nullptr) { - // We want to keep an invariant that nmethods found through iterations of a Thread's - // nmethods found in safepoints have gone through an entry barrier and are not armed. - // By calling this nmethod entry barrier, it plays along and acts - // like any other nmethod found on the stack of a thread (fewer surprises). - nmethod* nm = as_nmethod_or_null(); - if (nm != nullptr && bs_nm->is_armed(nm)) { - bool alive = bs_nm->nmethod_entry_barrier(nm); - assert(alive, "should be alive"); - } - } -} - -// Only called by whitebox test -void CompiledMethod::cleanup_inline_caches_whitebox() { - assert_locked_or_safepoint(CodeCache_lock); - CompiledICLocker ic_locker(this); - cleanup_inline_caches_impl(false /* unloading_occurred */, true /* clean_all */); -} - -address* CompiledMethod::orig_pc_addr(const frame* fr) { - return (address*) ((address)fr->unextended_sp() + orig_pc_offset()); -} - -// Called to clean up after class unloading for live nmethods -void CompiledMethod::cleanup_inline_caches_impl(bool unloading_occurred, bool clean_all) { - assert(CompiledICLocker::is_safe(this), "mt unsafe call"); - ResourceMark rm; - - // Find all calls in an nmethod and clear the ones that point to bad nmethods. - RelocIterator iter(this, oops_reloc_begin()); - bool is_in_static_stub = false; - while(iter.next()) { - - switch (iter.type()) { - - case relocInfo::virtual_call_type: - if (unloading_occurred) { - // If class unloading occurred we first clear ICs where the cached metadata - // is referring to an unloaded klass or method. - clean_ic_if_metadata_is_dead(CompiledIC_at(&iter)); - } - - clean_if_nmethod_is_unloaded(CompiledIC_at(&iter), this, clean_all); - break; - - case relocInfo::opt_virtual_call_type: - case relocInfo::static_call_type: - clean_if_nmethod_is_unloaded(CompiledDirectCall::at(iter.reloc()), this, clean_all); - break; - - case relocInfo::static_stub_type: { - is_in_static_stub = true; - break; - } - - case relocInfo::metadata_type: { - // Only the metadata relocations contained in static/opt virtual call stubs - // contains the Method* passed to c2i adapters. It is the only metadata - // relocation that needs to be walked, as it is the one metadata relocation - // that violates the invariant that all metadata relocations have an oop - // in the compiled method (due to deferred resolution and code patching). - - // This causes dead metadata to remain in compiled methods that are not - // unloading. Unless these slippery metadata relocations of the static - // stubs are at least cleared, subsequent class redefinition operations - // will access potentially free memory, and JavaThread execution - // concurrent to class unloading may call c2i adapters with dead methods. - if (!is_in_static_stub) { - // The first metadata relocation after a static stub relocation is the - // metadata relocation of the static stub used to pass the Method* to - // c2i adapters. - continue; - } - is_in_static_stub = false; - if (is_unloading()) { - // If the nmethod itself is dying, then it may point at dead metadata. - // Nobody should follow that metadata; it is strictly unsafe. - continue; - } - metadata_Relocation* r = iter.metadata_reloc(); - Metadata* md = r->metadata_value(); - if (md != nullptr && md->is_method()) { - Method* method = static_cast(md); - if (!method->method_holder()->is_loader_alive()) { - Atomic::store(r->metadata_addr(), (Method*)nullptr); - - if (!r->metadata_is_immediate()) { - r->fix_metadata_relocation(); - } - } - } - break; - } - - default: - break; - } - } -} - -address CompiledMethod::continuation_for_implicit_exception(address pc, bool for_div0_check) { - // Exception happened outside inline-cache check code => we are inside - // an active nmethod => use cpc to determine a return address - int exception_offset = int(pc - code_begin()); - int cont_offset = ImplicitExceptionTable(this).continuation_offset( exception_offset ); -#ifdef ASSERT - if (cont_offset == 0) { - Thread* thread = Thread::current(); - ResourceMark rm(thread); - CodeBlob* cb = CodeCache::find_blob(pc); - assert(cb != nullptr && cb == this, ""); - - // Keep tty output consistent. To avoid ttyLocker, we buffer in stream, and print all at once. - stringStream ss; - ss.print_cr("implicit exception happened at " INTPTR_FORMAT, p2i(pc)); - print_on(&ss); - method()->print_codes_on(&ss); - print_code_on(&ss); - print_pcs_on(&ss); - tty->print("%s", ss.as_string()); // print all at once - } -#endif - if (cont_offset == 0) { - // Let the normal error handling report the exception - return nullptr; - } - if (cont_offset == exception_offset) { -#if INCLUDE_JVMCI - Deoptimization::DeoptReason deopt_reason = for_div0_check ? Deoptimization::Reason_div0_check : Deoptimization::Reason_null_check; - JavaThread *thread = JavaThread::current(); - thread->set_jvmci_implicit_exception_pc(pc); - thread->set_pending_deoptimization(Deoptimization::make_trap_request(deopt_reason, - Deoptimization::Action_reinterpret)); - return (SharedRuntime::deopt_blob()->implicit_exception_uncommon_trap()); -#else - ShouldNotReachHere(); -#endif - } - return code_begin() + cont_offset; -} - -class HasEvolDependency : public MetadataClosure { - bool _has_evol_dependency; - public: - HasEvolDependency() : _has_evol_dependency(false) {} - void do_metadata(Metadata* md) { - if (md->is_method()) { - Method* method = (Method*)md; - if (method->is_old()) { - _has_evol_dependency = true; - } - } - } - bool has_evol_dependency() const { return _has_evol_dependency; } -}; - -bool CompiledMethod::has_evol_metadata() { - // Check the metadata in relocIter and CompiledIC and also deoptimize - // any nmethod that has reference to old methods. - HasEvolDependency check_evol; - metadata_do(&check_evol); - if (check_evol.has_evol_dependency() && log_is_enabled(Debug, redefine, class, nmethod)) { - ResourceMark rm; - log_debug(redefine, class, nmethod) - ("Found evol dependency of nmethod %s.%s(%s) compile_id=%d on in nmethod metadata", - _method->method_holder()->external_name(), - _method->name()->as_C_string(), - _method->signature()->as_C_string(), - compile_id()); - } - return check_evol.has_evol_dependency(); -} diff --git a/src/hotspot/share/code/compiledMethod.hpp b/src/hotspot/share/code/compiledMethod.hpp deleted file mode 100644 index 42d68bda554..00000000000 --- a/src/hotspot/share/code/compiledMethod.hpp +++ /dev/null @@ -1,415 +0,0 @@ -/* - * 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. - * - */ - -#ifndef SHARE_CODE_COMPILEDMETHOD_HPP -#define SHARE_CODE_COMPILEDMETHOD_HPP - -#include "code/codeBlob.hpp" -#include "code/pcDesc.hpp" -#include "oops/metadata.hpp" -#include "oops/method.hpp" - -class Dependencies; -class ExceptionHandlerTable; -class ImplicitExceptionTable; -class AbstractCompiler; -class xmlStream; -class CompiledDirectCall; -class NativeCallWrapper; -class ScopeDesc; -class CompiledIC; -class MetadataClosure; - -// This class is used internally by nmethods, to cache -// exception/pc/handler information. - -class ExceptionCache : public CHeapObj { - friend class VMStructs; - private: - enum { cache_size = 16 }; - Klass* _exception_type; - address _pc[cache_size]; - address _handler[cache_size]; - volatile int _count; - ExceptionCache* volatile _next; - ExceptionCache* _purge_list_next; - - inline address pc_at(int index); - void set_pc_at(int index, address a) { assert(index >= 0 && index < cache_size,""); _pc[index] = a; } - - inline address handler_at(int index); - void set_handler_at(int index, address a) { assert(index >= 0 && index < cache_size,""); _handler[index] = a; } - - inline int count(); - // increment_count is only called under lock, but there may be concurrent readers. - void increment_count(); - - public: - - ExceptionCache(Handle exception, address pc, address handler); - - Klass* exception_type() { return _exception_type; } - ExceptionCache* next(); - void set_next(ExceptionCache *ec); - ExceptionCache* purge_list_next() { return _purge_list_next; } - void set_purge_list_next(ExceptionCache *ec) { _purge_list_next = ec; } - - address match(Handle exception, address pc); - bool match_exception_with_space(Handle exception) ; - address test_address(address addr); - bool add_address_and_handler(address addr, address handler) ; -}; - -class nmethod; - -// cache pc descs found in earlier inquiries -class PcDescCache { - friend class VMStructs; - private: - enum { cache_size = 4 }; - // The array elements MUST be volatile! Several threads may modify - // and read from the cache concurrently. find_pc_desc_internal has - // returned wrong results. C++ compiler (namely xlC12) may duplicate - // C++ field accesses if the elements are not volatile. - typedef PcDesc* PcDescPtr; - volatile PcDescPtr _pc_descs[cache_size]; // last cache_size pc_descs found - public: - PcDescCache() { debug_only(_pc_descs[0] = nullptr); } - void reset_to(PcDesc* initial_pc_desc); - PcDesc* find_pc_desc(int pc_offset, bool approximate); - void add_pc_desc(PcDesc* pc_desc); - PcDesc* last_pc_desc() { return _pc_descs[0]; } -}; - -class PcDescSearch { -private: - address _code_begin; - PcDesc* _lower; - PcDesc* _upper; -public: - PcDescSearch(address code, PcDesc* lower, PcDesc* upper) : - _code_begin(code), _lower(lower), _upper(upper) - { - } - - address code_begin() const { return _code_begin; } - PcDesc* scopes_pcs_begin() const { return _lower; } - PcDesc* scopes_pcs_end() const { return _upper; } -}; - -class PcDescContainer { -private: - PcDescCache _pc_desc_cache; -public: - PcDescContainer() {} - - PcDesc* find_pc_desc_internal(address pc, bool approximate, const PcDescSearch& search); - void reset_to(PcDesc* initial_pc_desc) { _pc_desc_cache.reset_to(initial_pc_desc); } - - PcDesc* find_pc_desc(address pc, bool approximate, const PcDescSearch& search) { - address base_address = search.code_begin(); - PcDesc* desc = _pc_desc_cache.last_pc_desc(); - if (desc != nullptr && desc->pc_offset() == pc - base_address) { - return desc; - } - return find_pc_desc_internal(pc, approximate, search); - } -}; - - -class CompiledMethod : public CodeBlob { - friend class VMStructs; - friend class DeoptimizationScope; - void init_defaults(); -protected: - enum DeoptimizationStatus : u1 { - not_marked, - deoptimize, - deoptimize_noupdate, - deoptimize_done - }; - - volatile DeoptimizationStatus _deoptimization_status; // Used for stack deoptimization - // Used to track in which deoptimize handshake this method will be deoptimized. - uint64_t _deoptimization_generation; - - // set during construction - unsigned int _has_unsafe_access:1; // May fault due to unsafe access. - unsigned int _has_method_handle_invokes:1; // Has this method MethodHandle invokes? - unsigned int _has_wide_vectors:1; // Preserve wide vectors at safepoints - unsigned int _has_monitors:1; // Fastpath monitor detection for continuations - - Method* _method; - address _scopes_data_begin; - // All deoptee's will resume execution at this location described by - // this address. - address _deopt_handler_begin; - // All deoptee's at a MethodHandle call site will resume execution - // at this location described by this offset. - address _deopt_mh_handler_begin; - - PcDescContainer _pc_desc_container; - ExceptionCache * volatile _exception_cache; - - void* _gc_data; - - virtual void purge(bool free_code_cache_data, bool unregister_nmethod) = 0; - -private: - DeoptimizationStatus deoptimization_status() const { - return Atomic::load(&_deoptimization_status); - } - -protected: - CompiledMethod(Method* method, const char* name, CompilerType type, const CodeBlobLayout& layout, int frame_complete_offset, int frame_size, ImmutableOopMapSet* oop_maps, bool caller_must_gc_arguments, bool compiled); - CompiledMethod(Method* method, const char* name, CompilerType type, int size, int header_size, CodeBuffer* cb, int frame_complete_offset, int frame_size, OopMapSet* oop_maps, bool caller_must_gc_arguments, bool compiled); - -public: - // Only used by unit test. - CompiledMethod() {} - - template - T* gc_data() const { return reinterpret_cast(_gc_data); } - template - void set_gc_data(T* gc_data) { _gc_data = reinterpret_cast(gc_data); } - - bool has_unsafe_access() const { return _has_unsafe_access; } - void set_has_unsafe_access(bool z) { _has_unsafe_access = z; } - - bool has_monitors() const { return _has_monitors; } - void set_has_monitors(bool z) { _has_monitors = z; } - - bool has_method_handle_invokes() const { return _has_method_handle_invokes; } - void set_has_method_handle_invokes(bool z) { _has_method_handle_invokes = z; } - - bool has_wide_vectors() const { return _has_wide_vectors; } - void set_has_wide_vectors(bool z) { _has_wide_vectors = z; } - - enum : signed char { not_installed = -1, // in construction, only the owner doing the construction is - // allowed to advance state - in_use = 0, // executable nmethod - not_used = 1, // not entrant, but revivable - not_entrant = 2, // marked for deoptimization but activations may still exist - }; - - virtual bool is_in_use() const = 0; - virtual int comp_level() const = 0; - virtual int compile_id() const = 0; - - virtual address verified_entry_point() const = 0; - virtual void log_identity(xmlStream* log) const = 0; - virtual void log_state_change() const = 0; - virtual bool make_not_used() = 0; - virtual bool make_not_entrant() = 0; - virtual bool make_entrant() = 0; - virtual address entry_point() const = 0; - virtual bool is_osr_method() const = 0; - virtual int osr_entry_bci() const = 0; - Method* method() const { return _method; } - virtual void print_pcs_on(outputStream* st) = 0; - bool is_native_method() const { return _method != nullptr && _method->is_native(); } - bool is_java_method() const { return _method != nullptr && !_method->is_native(); } - - // ScopeDesc retrieval operation - PcDesc* pc_desc_at(address pc) { return find_pc_desc(pc, false); } - // pc_desc_near returns the first PcDesc at or after the given pc. - PcDesc* pc_desc_near(address pc) { return find_pc_desc(pc, true); } - - // ScopeDesc for an instruction - ScopeDesc* scope_desc_at(address pc); - ScopeDesc* scope_desc_near(address pc); - - bool is_at_poll_return(address pc); - bool is_at_poll_or_poll_return(address pc); - - bool is_marked_for_deoptimization() const { return deoptimization_status() != not_marked; } - bool has_been_deoptimized() const { return deoptimization_status() == deoptimize_done; } - void set_deoptimized_done(); - - virtual void make_deoptimized() { assert(false, "not supported"); }; - - bool update_recompile_counts() const { - // Update recompile counts when either the update is explicitly requested (deoptimize) - // or the nmethod is not marked for deoptimization at all (not_marked). - // The latter happens during uncommon traps when deoptimized nmethod is made not entrant. - DeoptimizationStatus status = deoptimization_status(); - return status != deoptimize_noupdate && status != deoptimize_done; - } - - // tells whether frames described by this nmethod can be deoptimized - // note: native wrappers cannot be deoptimized. - bool can_be_deoptimized() const { return is_java_method(); } - - virtual oop oop_at(int index) const = 0; - virtual Metadata* metadata_at(int index) const = 0; - - address scopes_data_begin() const { return _scopes_data_begin; } - virtual address scopes_data_end() const = 0; - int scopes_data_size() const { return int(scopes_data_end() - scopes_data_begin()); } - - virtual PcDesc* scopes_pcs_begin() const = 0; - virtual PcDesc* scopes_pcs_end() const = 0; - int scopes_pcs_size() const { return int((intptr_t) scopes_pcs_end() - (intptr_t) scopes_pcs_begin()); } - - address insts_begin() const { return code_begin(); } - address insts_end() const { return stub_begin(); } - // Returns true if a given address is in the 'insts' section. The method - // insts_contains_inclusive() is end-inclusive. - bool insts_contains(address addr) const { return insts_begin() <= addr && addr < insts_end(); } - bool insts_contains_inclusive(address addr) const { return insts_begin() <= addr && addr <= insts_end(); } - - int insts_size() const { return int(insts_end() - insts_begin()); } - - virtual address consts_begin() const = 0; - virtual address consts_end() const = 0; - bool consts_contains(address addr) const { return consts_begin() <= addr && addr < consts_end(); } - int consts_size() const { return int(consts_end() - consts_begin()); } - - virtual int skipped_instructions_size() const = 0; - - virtual address stub_begin() const = 0; - virtual address stub_end() const = 0; - bool stub_contains(address addr) const { return stub_begin() <= addr && addr < stub_end(); } - int stub_size() const { return int(stub_end() - stub_begin()); } - - virtual address handler_table_begin() const = 0; - virtual address handler_table_end() const = 0; - bool handler_table_contains(address addr) const { return handler_table_begin() <= addr && addr < handler_table_end(); } - int handler_table_size() const { return int(handler_table_end() - handler_table_begin()); } - - virtual address exception_begin() const = 0; - - virtual address nul_chk_table_begin() const = 0; - virtual address nul_chk_table_end() const = 0; - bool nul_chk_table_contains(address addr) const { return nul_chk_table_begin() <= addr && addr < nul_chk_table_end(); } - int nul_chk_table_size() const { return int(nul_chk_table_end() - nul_chk_table_begin()); } - - virtual oop* oop_addr_at(int index) const = 0; - virtual Metadata** metadata_addr_at(int index) const = 0; - -protected: - // Exception cache support - // Note: _exception_cache may be read and cleaned concurrently. - ExceptionCache* exception_cache() const { return _exception_cache; } - ExceptionCache* exception_cache_acquire() const; - void set_exception_cache(ExceptionCache *ec) { _exception_cache = ec; } - -public: - address handler_for_exception_and_pc(Handle exception, address pc); - void add_handler_for_exception_and_pc(Handle exception, address pc, address handler); - void clean_exception_cache(); - - void add_exception_cache_entry(ExceptionCache* new_entry); - ExceptionCache* exception_cache_entry_for_exception(Handle exception); - - // MethodHandle - bool is_method_handle_return(address return_pc); - address deopt_mh_handler_begin() const { return _deopt_mh_handler_begin; } - - address deopt_handler_begin() const { return _deopt_handler_begin; } - address* deopt_handler_begin_addr() { return &_deopt_handler_begin; } - // Deopt - // Return true is the PC is one would expect if the frame is being deopted. - inline bool is_deopt_pc(address pc); - inline bool is_deopt_mh_entry(address pc); - inline bool is_deopt_entry(address pc); - - // Accessor/mutator for the original pc of a frame before a frame was deopted. - address get_original_pc(const frame* fr) { return *orig_pc_addr(fr); } - void set_original_pc(const frame* fr, address pc) { *orig_pc_addr(fr) = pc; } - - virtual int orig_pc_offset() = 0; - -private: - address* orig_pc_addr(const frame* fr); - -public: - virtual const char* compile_kind() const = 0; - virtual int get_state() const = 0; - - const char* state() const; - - bool inlinecache_check_contains(address addr) const { - return (addr >= code_begin() && addr < verified_entry_point()); - } - - void preserve_callee_argument_oops(frame fr, const RegisterMap *reg_map, OopClosure* f); - - // implicit exceptions support - address continuation_for_implicit_div0_exception(address pc) { return continuation_for_implicit_exception(pc, true); } - address continuation_for_implicit_null_exception(address pc) { return continuation_for_implicit_exception(pc, false); } - - static address get_deopt_original_pc(const frame* fr); - - // Inline cache support for class unloading and nmethod unloading - private: - void cleanup_inline_caches_impl(bool unloading_occurred, bool clean_all); - - address continuation_for_implicit_exception(address pc, bool for_div0_check); - - public: - // Serial version used by whitebox test - void cleanup_inline_caches_whitebox(); - - virtual void clear_inline_caches(); - - // Execute nmethod barrier code, as if entering through nmethod call. - void run_nmethod_entry_barrier(); - - void verify_oop_relocations(); - - bool has_evol_metadata(); - - // Fast breakpoint support. Tells if this compiled method is - // dependent on the given method. Returns true if this nmethod - // corresponds to the given method as well. - virtual bool is_dependent_on_method(Method* dependee) = 0; - - virtual address call_instruction_address(address pc) const = 0; - - Method* attached_method(address call_pc); - Method* attached_method_before_pc(address pc); - - virtual void metadata_do(MetadataClosure* f) = 0; - - // GC support - protected: - address oops_reloc_begin() const; - - public: - // GC unloading support - // Cleans unloaded klasses and unloaded nmethods in inline caches - - virtual bool is_unloading() = 0; - - void unload_nmethod_caches(bool class_unloading_occurred); - virtual void do_unloading(bool unloading_occurred) = 0; - -private: - PcDesc* find_pc_desc(address pc, bool approximate) { - return _pc_desc_container.find_pc_desc(pc, approximate, PcDescSearch(code_begin(), scopes_pcs_begin(), scopes_pcs_end())); - } -}; - -#endif // SHARE_CODE_COMPILEDMETHOD_HPP diff --git a/src/hotspot/share/code/debugInfo.cpp b/src/hotspot/share/code/debugInfo.cpp index 4cc94dd13e7..5376e8ade9b 100644 --- a/src/hotspot/share/code/debugInfo.cpp +++ b/src/hotspot/share/code/debugInfo.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 @@ -53,15 +53,9 @@ void DebugInfoWriteStream::write_metadata(Metadata* h) { } oop DebugInfoReadStream::read_oop() { - nmethod* nm = const_cast(code())->as_nmethod_or_null(); - oop o; - if (nm != nullptr) { - // Despite these oops being found inside nmethods that are on-stack, - // they are not kept alive by all GCs (e.g. G1 and Shenandoah). - o = nm->oop_at_phantom(read_int()); - } else { - o = code()->oop_at(read_int()); - } + // Despite these oops being found inside nmethods that are on-stack, + // they are not kept alive by all GCs (e.g. G1 and Shenandoah). + oop o = code()->oop_at_phantom(read_int()); assert(oopDesc::is_oop_or_null(o), "oop only"); return o; } @@ -250,14 +244,13 @@ ObjectValue* ObjectMergeValue::select(frame& fr, RegisterMap& reg_map) { // the description of the scalar replaced object. if (selector == -1) { StackValue* sv_merge_pointer = StackValue::create_stack_value(&fr, ®_map, _merge_pointer); - _selected = new ObjectValue(id()); + _selected = new ObjectValue(id(), nullptr, false); // Retrieve the pointer to the real object and use it as if we had // allocated it during the deoptimization _selected->set_value(sv_merge_pointer->get_obj()()); - // No need to rematerialize - return nullptr; + return _selected; } else { assert(selector < _possible_objects.length(), "sanity"); _selected = (ObjectValue*) _possible_objects.at(selector); diff --git a/src/hotspot/share/code/debugInfo.hpp b/src/hotspot/share/code/debugInfo.hpp index 1214059294d..6aba5b67cb6 100644 --- a/src/hotspot/share/code/debugInfo.hpp +++ b/src/hotspot/share/code/debugInfo.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 @@ -133,29 +133,24 @@ class ObjectValue: public ScopeValue { GrowableArray _field_values; Handle _value; bool _visited; + bool _is_scalar_replaced; // Whether this ObjectValue describes an object scalar replaced or just + // an object (possibly null) participating in an allocation merge. bool _is_root; // Will be true if this object is referred to // as a local/expression/monitor in the JVMs. // Otherwise false, meaning it's just a candidate // in an object allocation merge. public: - ObjectValue(int id, ScopeValue* klass) + ObjectValue(int id, ScopeValue* klass = nullptr, bool is_scalar_replaced = true) : _id(id) , _klass(klass) , _field_values() , _value() , _visited(false) + , _is_scalar_replaced(is_scalar_replaced) , _is_root(true) { - assert(klass->is_constant_oop(), "should be constant java mirror oop"); + assert(klass == nullptr || klass->is_constant_oop(), "should be constant java mirror oop"); } - ObjectValue(int id) - : _id(id) - , _klass(nullptr) - , _field_values() - , _value() - , _visited(false) - , _is_root(true) {} - // Accessors bool is_object() const { return true; } int id() const { return _id; } @@ -165,12 +160,14 @@ class ObjectValue: public ScopeValue { virtual int field_size() { return _field_values.length(); } virtual Handle value() const { return _value; } bool is_visited() const { return _visited; } + bool is_scalar_replaced() const { return _is_scalar_replaced; } bool is_root() const { return _is_root; } - void set_id(int id) { _id = id; } + void set_id(int id) { _id = id; } virtual void set_value(oop value); - void set_visited(bool visited) { _visited = visited; } - void set_root(bool root) { _is_root = root; } + void set_visited(bool visited) { _visited = visited; } + void set_is_scalar_replaced(bool scd) { _is_scalar_replaced = scd; } + void set_root(bool root) { _is_root = root; } // Serialization of debugging information void read_object(DebugInfoReadStream* stream); @@ -208,14 +205,14 @@ class ObjectMergeValue: public ObjectValue { ObjectValue* _selected; public: ObjectMergeValue(int id, ScopeValue* merge_pointer, ScopeValue* selector) - : ObjectValue(id) + : ObjectValue(id, nullptr, false) , _selector(selector) , _merge_pointer(merge_pointer) , _possible_objects() , _selected(nullptr) {} ObjectMergeValue(int id) - : ObjectValue(id) + : ObjectValue(id, nullptr, false) , _selector(nullptr) , _merge_pointer(nullptr) , _possible_objects() @@ -372,11 +369,11 @@ class MonitorValue: public ResourceObj { class DebugInfoReadStream : public CompressedReadStream { private: - const CompiledMethod* _code; - const CompiledMethod* code() const { return _code; } + const nmethod* _code; + const nmethod* code() const { return _code; } GrowableArray* _obj_pool; public: - DebugInfoReadStream(const CompiledMethod* code, int offset, GrowableArray* obj_pool = nullptr) : + DebugInfoReadStream(const nmethod* code, int offset, GrowableArray* obj_pool = nullptr) : CompressedReadStream(code->scopes_data_begin(), offset) { _code = code; _obj_pool = obj_pool; diff --git a/src/hotspot/share/code/debugInfoRec.cpp b/src/hotspot/share/code/debugInfoRec.cpp index 15353bf2872..85be80dbf0b 100644 --- a/src/hotspot/share/code/debugInfoRec.cpp +++ b/src/hotspot/share/code/debugInfoRec.cpp @@ -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 @@ -175,7 +175,7 @@ void DebugInformationRecorder::add_non_safepoint(int pc_offset) { void DebugInformationRecorder::add_new_pc_offset(int pc_offset) { assert(_pcs_length == 0 || last_pc()->pc_offset() < pc_offset, - "must specify a new, larger pc offset"); + "must specify a new, larger pc offset: %d >= %d", last_pc()->pc_offset(), pc_offset); // add the pcdesc if (_pcs_length == _pcs_size) { diff --git a/src/hotspot/share/code/exceptionHandlerTable.cpp b/src/hotspot/share/code/exceptionHandlerTable.cpp index 8bcf5a43953..aedeb0e9e04 100644 --- a/src/hotspot/share/code/exceptionHandlerTable.cpp +++ b/src/hotspot/share/code/exceptionHandlerTable.cpp @@ -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 @@ -65,9 +65,9 @@ ExceptionHandlerTable::ExceptionHandlerTable(int initial_size) { } -ExceptionHandlerTable::ExceptionHandlerTable(const CompiledMethod* cm) { - _table = (HandlerTableEntry*)cm->handler_table_begin(); - _length = cm->handler_table_size() / sizeof(HandlerTableEntry); +ExceptionHandlerTable::ExceptionHandlerTable(const nmethod* nm) { + _table = (HandlerTableEntry*)nm->handler_table_begin(); + _length = nm->handler_table_size() / sizeof(HandlerTableEntry); _size = 0; // no space allocated by ExceptionHandlerTable! } @@ -98,9 +98,9 @@ void ExceptionHandlerTable::add_subtable( } -void ExceptionHandlerTable::copy_to(CompiledMethod* cm) { - assert(size_in_bytes() == cm->handler_table_size(), "size of space allocated in compiled method incorrect"); - copy_bytes_to(cm->handler_table_begin()); +void ExceptionHandlerTable::copy_to(nmethod* nm) { + assert(size_in_bytes() == nm->handler_table_size(), "size of space allocated in compiled method incorrect"); + copy_bytes_to(nm->handler_table_begin()); } void ExceptionHandlerTable::copy_bytes_to(address addr) { @@ -215,7 +215,7 @@ void ImplicitExceptionTable::print(address base) const { } } -ImplicitExceptionTable::ImplicitExceptionTable(const CompiledMethod* nm) { +ImplicitExceptionTable::ImplicitExceptionTable(const nmethod* nm) { if (nm->nul_chk_table_size() == 0) { _len = 0; _data = nullptr; diff --git a/src/hotspot/share/code/exceptionHandlerTable.hpp b/src/hotspot/share/code/exceptionHandlerTable.hpp index f1dcab657ff..083dc430111 100644 --- a/src/hotspot/share/code/exceptionHandlerTable.hpp +++ b/src/hotspot/share/code/exceptionHandlerTable.hpp @@ -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 @@ -99,7 +99,7 @@ class ExceptionHandlerTable { ExceptionHandlerTable(int initial_size = 8); // (run-time) construction from nmethod - ExceptionHandlerTable(const CompiledMethod* nm); + ExceptionHandlerTable(const nmethod* nm); // (compile-time) add entries void add_subtable( @@ -116,7 +116,7 @@ class ExceptionHandlerTable { // nmethod support int size_in_bytes() const { return align_up(_length * (int)sizeof(HandlerTableEntry), oopSize); } - void copy_to(CompiledMethod* nm); + void copy_to(nmethod* nm); void copy_bytes_to(address addr); // lookup @@ -150,7 +150,7 @@ class ImplicitExceptionTable { public: ImplicitExceptionTable( ) : _size(0), _len(0), _data(0) { } // (run-time) construction from nmethod - ImplicitExceptionTable( const CompiledMethod *nm ); + ImplicitExceptionTable(const nmethod *nm); void set_size( uint size ); void append( uint exec_off, uint cont_off ); diff --git a/src/hotspot/share/code/nmethod.cpp b/src/hotspot/share/code/nmethod.cpp index 2755df32513..51ba872b3ac 100644 --- a/src/hotspot/share/code/nmethod.cpp +++ b/src/hotspot/share/code/nmethod.cpp @@ -26,10 +26,9 @@ #include "asm/assembler.inline.hpp" #include "code/codeCache.hpp" #include "code/compiledIC.hpp" -#include "code/compiledMethod.inline.hpp" #include "code/dependencies.hpp" #include "code/nativeInst.hpp" -#include "code/nmethod.hpp" +#include "code/nmethod.inline.hpp" #include "code/scopeDesc.hpp" #include "compiler/abstractCompiler.hpp" #include "compiler/compilationLog.hpp" @@ -44,7 +43,7 @@ #include "gc/shared/barrierSetNMethod.hpp" #include "gc/shared/classUnloadingContext.hpp" #include "gc/shared/collectedHeap.hpp" -#include "interpreter/bytecode.hpp" +#include "interpreter/bytecode.inline.hpp" #include "jvm.h" #include "logging/log.hpp" #include "logging/logStream.hpp" @@ -98,9 +97,9 @@ Symbol* name = m->name(); \ Symbol* signature = m->signature(); \ HOTSPOT_COMPILED_METHOD_UNLOAD( \ - (char *) klass_name->bytes(), klass_name->utf8_length(), \ - (char *) name->bytes(), name->utf8_length(), \ - (char *) signature->bytes(), signature->utf8_length()); \ + (char *) klass_name->bytes(), klass_name->utf8_length(), \ + (char *) name->bytes(), name->utf8_length(), \ + (char *) signature->bytes(), signature->utf8_length()); \ } \ } @@ -138,6 +137,9 @@ struct java_nmethod_stats_struct { uint oops_size; uint metadata_size; + uint size_gt_32k; + int size_max; + void note_nmethod(nmethod* nm) { nmethod_count += 1; total_size += nm->size(); @@ -156,27 +158,33 @@ struct java_nmethod_stats_struct { speculations_size += nm->speculations_size(); jvmci_data_size += nm->jvmci_data_size(); #endif + int short_pos_max = ((1<<15) - 1); + if (nm->size() > short_pos_max) size_gt_32k++; + if (nm->size() > size_max) size_max = nm->size(); } void print_nmethod_stats(const char* name) { if (nmethod_count == 0) return; tty->print_cr("Statistics for %u bytecoded nmethods for %s:", nmethod_count, name); - if (total_size != 0) tty->print_cr(" total in heap = %u", total_size); - if (nmethod_count != 0) tty->print_cr(" header = " SIZE_FORMAT, nmethod_count * sizeof(nmethod)); - if (relocation_size != 0) tty->print_cr(" relocation = %u", relocation_size); - if (consts_size != 0) tty->print_cr(" constants = %u", consts_size); - if (insts_size != 0) tty->print_cr(" main code = %u", insts_size); - if (stub_size != 0) tty->print_cr(" stub code = %u", stub_size); - if (oops_size != 0) tty->print_cr(" oops = %u", oops_size); - if (metadata_size != 0) tty->print_cr(" metadata = %u", metadata_size); - if (scopes_data_size != 0) tty->print_cr(" scopes data = %u", scopes_data_size); - if (scopes_pcs_size != 0) tty->print_cr(" scopes pcs = %u", scopes_pcs_size); - if (dependencies_size != 0) tty->print_cr(" dependencies = %u", dependencies_size); - if (handler_table_size != 0) tty->print_cr(" handler table = %u", handler_table_size); - if (nul_chk_table_size != 0) tty->print_cr(" nul chk table = %u", nul_chk_table_size); + if (total_size != 0) tty->print_cr(" total in heap = %u (100%%)", total_size); + uint header_size = (uint)(nmethod_count * sizeof(nmethod)); + if (nmethod_count != 0) tty->print_cr(" header = %u (%f%%)", header_size, (header_size * 100.0f)/total_size); + if (relocation_size != 0) tty->print_cr(" relocation = %u (%f%%)", relocation_size, (relocation_size * 100.0f)/total_size); + if (consts_size != 0) tty->print_cr(" constants = %u (%f%%)", consts_size, (consts_size * 100.0f)/total_size); + if (insts_size != 0) tty->print_cr(" main code = %u (%f%%)", insts_size, (insts_size * 100.0f)/total_size); + if (stub_size != 0) tty->print_cr(" stub code = %u (%f%%)", stub_size, (stub_size * 100.0f)/total_size); + if (oops_size != 0) tty->print_cr(" oops = %u (%f%%)", oops_size, (oops_size * 100.0f)/total_size); + if (metadata_size != 0) tty->print_cr(" metadata = %u (%f%%)", metadata_size, (metadata_size * 100.0f)/total_size); + if (scopes_data_size != 0) tty->print_cr(" scopes data = %u (%f%%)", scopes_data_size, (scopes_data_size * 100.0f)/total_size); + if (scopes_pcs_size != 0) tty->print_cr(" scopes pcs = %u (%f%%)", scopes_pcs_size, (scopes_pcs_size * 100.0f)/total_size); + if (dependencies_size != 0) tty->print_cr(" dependencies = %u (%f%%)", dependencies_size, (dependencies_size * 100.0f)/total_size); + if (handler_table_size != 0) tty->print_cr(" handler table = %u (%f%%)", handler_table_size, (handler_table_size * 100.0f)/total_size); + if (nul_chk_table_size != 0) tty->print_cr(" nul chk table = %u (%f%%)", nul_chk_table_size, (nul_chk_table_size * 100.0f)/total_size); #if INCLUDE_JVMCI - if (speculations_size != 0) tty->print_cr(" speculations = %u", speculations_size); - if (jvmci_data_size != 0) tty->print_cr(" JVMCI data = %u", jvmci_data_size); + if (speculations_size != 0) tty->print_cr(" speculations = %u (%f%%)", speculations_size, (speculations_size * 100.0f)/total_size); + if (jvmci_data_size != 0) tty->print_cr(" JVMCI data = %u (%f%%)", jvmci_data_size, (jvmci_data_size * 100.0f)/total_size); #endif + if (size_gt_32k != 0) tty->print_cr(" size > 32k = %u", size_gt_32k); + if (size_max != 0) tty->print_cr(" max size = %d", size_max); } }; @@ -417,6 +425,558 @@ static int adjust_pcs_size(int pcs_size) { return nsize; } +bool nmethod::is_method_handle_return(address return_pc) { + if (!has_method_handle_invokes()) return false; + PcDesc* pd = pc_desc_at(return_pc); + if (pd == nullptr) + return false; + return pd->is_method_handle_invoke(); +} + +// Returns a string version of the method state. +const char* nmethod::state() const { + int state = get_state(); + switch (state) { + case not_installed: + return "not installed"; + case in_use: + return "in use"; + case not_entrant: + return "not_entrant"; + default: + fatal("unexpected method state: %d", state); + return nullptr; + } +} + +void nmethod::set_deoptimized_done() { + ConditionalMutexLocker ml(NMethodState_lock, !NMethodState_lock->owned_by_self(), Mutex::_no_safepoint_check_flag); + if (_deoptimization_status != deoptimize_done) { // can't go backwards + Atomic::store(&_deoptimization_status, deoptimize_done); + } +} + +ExceptionCache* nmethod::exception_cache_acquire() const { + return Atomic::load_acquire(&_exception_cache); +} + +void nmethod::add_exception_cache_entry(ExceptionCache* new_entry) { + assert(ExceptionCache_lock->owned_by_self(),"Must hold the ExceptionCache_lock"); + assert(new_entry != nullptr,"Must be non null"); + assert(new_entry->next() == nullptr, "Must be null"); + + for (;;) { + ExceptionCache *ec = exception_cache(); + if (ec != nullptr) { + Klass* ex_klass = ec->exception_type(); + if (!ex_klass->is_loader_alive()) { + // We must guarantee that entries are not inserted with new next pointer + // edges to ExceptionCache entries with dead klasses, due to bad interactions + // with concurrent ExceptionCache cleanup. Therefore, the inserts roll + // the head pointer forward to the first live ExceptionCache, so that the new + // next pointers always point at live ExceptionCaches, that are not removed due + // to concurrent ExceptionCache cleanup. + ExceptionCache* next = ec->next(); + if (Atomic::cmpxchg(&_exception_cache, ec, next) == ec) { + CodeCache::release_exception_cache(ec); + } + continue; + } + ec = exception_cache(); + if (ec != nullptr) { + new_entry->set_next(ec); + } + } + if (Atomic::cmpxchg(&_exception_cache, ec, new_entry) == ec) { + return; + } + } +} + +void nmethod::clean_exception_cache() { + // For each nmethod, only a single thread may call this cleanup function + // at the same time, whether called in STW cleanup or concurrent cleanup. + // Note that if the GC is processing exception cache cleaning in a concurrent phase, + // then a single writer may contend with cleaning up the head pointer to the + // first ExceptionCache node that has a Klass* that is alive. That is fine, + // as long as there is no concurrent cleanup of next pointers from concurrent writers. + // And the concurrent writers do not clean up next pointers, only the head. + // Also note that concurrent readers will walk through Klass* pointers that are not + // alive. That does not cause ABA problems, because Klass* is deleted after + // a handshake with all threads, after all stale ExceptionCaches have been + // unlinked. That is also when the CodeCache::exception_cache_purge_list() + // is deleted, with all ExceptionCache entries that were cleaned concurrently. + // That similarly implies that CAS operations on ExceptionCache entries do not + // suffer from ABA problems as unlinking and deletion is separated by a global + // handshake operation. + ExceptionCache* prev = nullptr; + ExceptionCache* curr = exception_cache_acquire(); + + while (curr != nullptr) { + ExceptionCache* next = curr->next(); + + if (!curr->exception_type()->is_loader_alive()) { + if (prev == nullptr) { + // Try to clean head; this is contended by concurrent inserts, that + // both lazily clean the head, and insert entries at the head. If + // the CAS fails, the operation is restarted. + if (Atomic::cmpxchg(&_exception_cache, curr, next) != curr) { + prev = nullptr; + curr = exception_cache_acquire(); + continue; + } + } else { + // It is impossible to during cleanup connect the next pointer to + // an ExceptionCache that has not been published before a safepoint + // prior to the cleanup. Therefore, release is not required. + prev->set_next(next); + } + // prev stays the same. + + CodeCache::release_exception_cache(curr); + } else { + prev = curr; + } + + curr = next; + } +} + +// public method for accessing the exception cache +// These are the public access methods. +address nmethod::handler_for_exception_and_pc(Handle exception, address pc) { + // We never grab a lock to read the exception cache, so we may + // have false negatives. This is okay, as it can only happen during + // the first few exception lookups for a given nmethod. + ExceptionCache* ec = exception_cache_acquire(); + while (ec != nullptr) { + address ret_val; + if ((ret_val = ec->match(exception,pc)) != nullptr) { + return ret_val; + } + ec = ec->next(); + } + return nullptr; +} + +void nmethod::add_handler_for_exception_and_pc(Handle exception, address pc, address handler) { + // There are potential race conditions during exception cache updates, so we + // must own the ExceptionCache_lock before doing ANY modifications. Because + // we don't lock during reads, it is possible to have several threads attempt + // to update the cache with the same data. We need to check for already inserted + // copies of the current data before adding it. + + MutexLocker ml(ExceptionCache_lock); + ExceptionCache* target_entry = exception_cache_entry_for_exception(exception); + + if (target_entry == nullptr || !target_entry->add_address_and_handler(pc,handler)) { + target_entry = new ExceptionCache(exception,pc,handler); + add_exception_cache_entry(target_entry); + } +} + +// private method for handling exception cache +// These methods are private, and used to manipulate the exception cache +// directly. +ExceptionCache* nmethod::exception_cache_entry_for_exception(Handle exception) { + ExceptionCache* ec = exception_cache_acquire(); + while (ec != nullptr) { + if (ec->match_exception_with_space(exception)) { + return ec; + } + ec = ec->next(); + } + return nullptr; +} + +bool nmethod::is_at_poll_return(address pc) { + RelocIterator iter(this, pc, pc+1); + while (iter.next()) { + if (iter.type() == relocInfo::poll_return_type) + return true; + } + return false; +} + + +bool nmethod::is_at_poll_or_poll_return(address pc) { + RelocIterator iter(this, pc, pc+1); + while (iter.next()) { + relocInfo::relocType t = iter.type(); + if (t == relocInfo::poll_return_type || t == relocInfo::poll_type) + return true; + } + return false; +} + +void nmethod::verify_oop_relocations() { + // Ensure sure that the code matches the current oop values + RelocIterator iter(this, nullptr, nullptr); + while (iter.next()) { + if (iter.type() == relocInfo::oop_type) { + oop_Relocation* reloc = iter.oop_reloc(); + if (!reloc->oop_is_immediate()) { + reloc->verify_oop_relocation(); + } + } + } +} + + +ScopeDesc* nmethod::scope_desc_at(address pc) { + PcDesc* pd = pc_desc_at(pc); + guarantee(pd != nullptr, "scope must be present"); + return new ScopeDesc(this, pd); +} + +ScopeDesc* nmethod::scope_desc_near(address pc) { + PcDesc* pd = pc_desc_near(pc); + guarantee(pd != nullptr, "scope must be present"); + return new ScopeDesc(this, pd); +} + +address nmethod::oops_reloc_begin() const { + // If the method is not entrant then a JMP is plastered over the + // first few bytes. If an oop in the old code was there, that oop + // should not get GC'd. Skip the first few bytes of oops on + // not-entrant methods. + if (frame_complete_offset() != CodeOffsets::frame_never_safe && + code_begin() + frame_complete_offset() > + verified_entry_point() + NativeJump::instruction_size) + { + // If we have a frame_complete_offset after the native jump, then there + // is no point trying to look for oops before that. This is a requirement + // for being allowed to scan oops concurrently. + return code_begin() + frame_complete_offset(); + } + + // It is not safe to read oops concurrently using entry barriers, if their + // location depend on whether the nmethod is entrant or not. + // assert(BarrierSet::barrier_set()->barrier_set_nmethod() == nullptr, "Not safe oop scan"); + + address low_boundary = verified_entry_point(); + if (!is_in_use()) { + low_boundary += NativeJump::instruction_size; + // %%% Note: On SPARC we patch only a 4-byte trap, not a full NativeJump. + // This means that the low_boundary is going to be a little too high. + // This shouldn't matter, since oops of non-entrant methods are never used. + // In fact, why are we bothering to look at oops in a non-entrant method?? + } + return low_boundary; +} + +// Method that knows how to preserve outgoing arguments at call. This method must be +// called with a frame corresponding to a Java invoke +void nmethod::preserve_callee_argument_oops(frame fr, const RegisterMap *reg_map, OopClosure* f) { + if (method() == nullptr) { + return; + } + + // handle the case of an anchor explicitly set in continuation code that doesn't have a callee + JavaThread* thread = reg_map->thread(); + if (thread->has_last_Java_frame() && fr.sp() == thread->last_Java_sp()) { + return; + } + + if (!method()->is_native()) { + address pc = fr.pc(); + bool has_receiver, has_appendix; + Symbol* signature; + + // The method attached by JIT-compilers should be used, if present. + // Bytecode can be inaccurate in such case. + Method* callee = attached_method_before_pc(pc); + if (callee != nullptr) { + has_receiver = !(callee->access_flags().is_static()); + has_appendix = false; + signature = callee->signature(); + } else { + SimpleScopeDesc ssd(this, pc); + + Bytecode_invoke call(methodHandle(Thread::current(), ssd.method()), ssd.bci()); + has_receiver = call.has_receiver(); + has_appendix = call.has_appendix(); + signature = call.signature(); + } + + fr.oops_compiled_arguments_do(signature, has_receiver, has_appendix, reg_map, f); + } else if (method()->is_continuation_enter_intrinsic()) { + // This method only calls Continuation.enter() + Symbol* signature = vmSymbols::continuationEnter_signature(); + fr.oops_compiled_arguments_do(signature, false, false, reg_map, f); + } +} + +Method* nmethod::attached_method(address call_instr) { + assert(code_contains(call_instr), "not part of the nmethod"); + RelocIterator iter(this, call_instr, call_instr + 1); + while (iter.next()) { + if (iter.addr() == call_instr) { + switch(iter.type()) { + case relocInfo::static_call_type: return iter.static_call_reloc()->method_value(); + case relocInfo::opt_virtual_call_type: return iter.opt_virtual_call_reloc()->method_value(); + case relocInfo::virtual_call_type: return iter.virtual_call_reloc()->method_value(); + default: break; + } + } + } + return nullptr; // not found +} + +Method* nmethod::attached_method_before_pc(address pc) { + if (NativeCall::is_call_before(pc)) { + NativeCall* ncall = nativeCall_before(pc); + return attached_method(ncall->instruction_address()); + } + return nullptr; // not a call +} + +void nmethod::clear_inline_caches() { + assert(SafepointSynchronize::is_at_safepoint(), "clearing of IC's only allowed at safepoint"); + RelocIterator iter(this); + while (iter.next()) { + iter.reloc()->clear_inline_cache(); + } +} + +#ifdef ASSERT +// Check class_loader is alive for this bit of metadata. +class CheckClass : public MetadataClosure { + void do_metadata(Metadata* md) { + Klass* klass = nullptr; + if (md->is_klass()) { + klass = ((Klass*)md); + } else if (md->is_method()) { + klass = ((Method*)md)->method_holder(); + } else if (md->is_methodData()) { + klass = ((MethodData*)md)->method()->method_holder(); + } else { + md->print(); + ShouldNotReachHere(); + } + assert(klass->is_loader_alive(), "must be alive"); + } +}; +#endif // ASSERT + + +static void clean_ic_if_metadata_is_dead(CompiledIC *ic) { + ic->clean_metadata(); +} + +// Clean references to unloaded nmethods at addr from this one, which is not unloaded. +template +static void clean_if_nmethod_is_unloaded(CallsiteT* callsite, nmethod* from, + bool clean_all) { + CodeBlob* cb = CodeCache::find_blob(callsite->destination()); + if (!cb->is_nmethod()) { + return; + } + nmethod* nm = cb->as_nmethod(); + if (clean_all || !nm->is_in_use() || nm->is_unloading() || nm->method()->code() != nm) { + callsite->set_to_clean(); + } +} + +// Cleans caches in nmethods that point to either classes that are unloaded +// or nmethods that are unloaded. +// +// Can be called either in parallel by G1 currently or after all +// nmethods are unloaded. Return postponed=true in the parallel case for +// inline caches found that point to nmethods that are not yet visited during +// the do_unloading walk. +void nmethod::unload_nmethod_caches(bool unloading_occurred) { + ResourceMark rm; + + // Exception cache only needs to be called if unloading occurred + if (unloading_occurred) { + clean_exception_cache(); + } + + cleanup_inline_caches_impl(unloading_occurred, false); + +#ifdef ASSERT + // Check that the metadata embedded in the nmethod is alive + CheckClass check_class; + metadata_do(&check_class); +#endif +} + +void nmethod::run_nmethod_entry_barrier() { + BarrierSetNMethod* bs_nm = BarrierSet::barrier_set()->barrier_set_nmethod(); + if (bs_nm != nullptr) { + // We want to keep an invariant that nmethods found through iterations of a Thread's + // nmethods found in safepoints have gone through an entry barrier and are not armed. + // By calling this nmethod entry barrier, it plays along and acts + // like any other nmethod found on the stack of a thread (fewer surprises). + nmethod* nm = this; + if (bs_nm->is_armed(nm)) { + bool alive = bs_nm->nmethod_entry_barrier(nm); + assert(alive, "should be alive"); + } + } +} + +// Only called by whitebox test +void nmethod::cleanup_inline_caches_whitebox() { + assert_locked_or_safepoint(CodeCache_lock); + CompiledICLocker ic_locker(this); + cleanup_inline_caches_impl(false /* unloading_occurred */, true /* clean_all */); +} + +address* nmethod::orig_pc_addr(const frame* fr) { + return (address*) ((address)fr->unextended_sp() + orig_pc_offset()); +} + +// Called to clean up after class unloading for live nmethods +void nmethod::cleanup_inline_caches_impl(bool unloading_occurred, bool clean_all) { + assert(CompiledICLocker::is_safe(this), "mt unsafe call"); + ResourceMark rm; + + // Find all calls in an nmethod and clear the ones that point to bad nmethods. + RelocIterator iter(this, oops_reloc_begin()); + bool is_in_static_stub = false; + while(iter.next()) { + + switch (iter.type()) { + + case relocInfo::virtual_call_type: + if (unloading_occurred) { + // If class unloading occurred we first clear ICs where the cached metadata + // is referring to an unloaded klass or method. + clean_ic_if_metadata_is_dead(CompiledIC_at(&iter)); + } + + clean_if_nmethod_is_unloaded(CompiledIC_at(&iter), this, clean_all); + break; + + case relocInfo::opt_virtual_call_type: + case relocInfo::static_call_type: + clean_if_nmethod_is_unloaded(CompiledDirectCall::at(iter.reloc()), this, clean_all); + break; + + case relocInfo::static_stub_type: { + is_in_static_stub = true; + break; + } + + case relocInfo::metadata_type: { + // Only the metadata relocations contained in static/opt virtual call stubs + // contains the Method* passed to c2i adapters. It is the only metadata + // relocation that needs to be walked, as it is the one metadata relocation + // that violates the invariant that all metadata relocations have an oop + // in the compiled method (due to deferred resolution and code patching). + + // This causes dead metadata to remain in compiled methods that are not + // unloading. Unless these slippery metadata relocations of the static + // stubs are at least cleared, subsequent class redefinition operations + // will access potentially free memory, and JavaThread execution + // concurrent to class unloading may call c2i adapters with dead methods. + if (!is_in_static_stub) { + // The first metadata relocation after a static stub relocation is the + // metadata relocation of the static stub used to pass the Method* to + // c2i adapters. + continue; + } + is_in_static_stub = false; + if (is_unloading()) { + // If the nmethod itself is dying, then it may point at dead metadata. + // Nobody should follow that metadata; it is strictly unsafe. + continue; + } + metadata_Relocation* r = iter.metadata_reloc(); + Metadata* md = r->metadata_value(); + if (md != nullptr && md->is_method()) { + Method* method = static_cast(md); + if (!method->method_holder()->is_loader_alive()) { + Atomic::store(r->metadata_addr(), (Method*)nullptr); + + if (!r->metadata_is_immediate()) { + r->fix_metadata_relocation(); + } + } + } + break; + } + + default: + break; + } + } +} + +address nmethod::continuation_for_implicit_exception(address pc, bool for_div0_check) { + // Exception happened outside inline-cache check code => we are inside + // an active nmethod => use cpc to determine a return address + int exception_offset = int(pc - code_begin()); + int cont_offset = ImplicitExceptionTable(this).continuation_offset( exception_offset ); +#ifdef ASSERT + if (cont_offset == 0) { + Thread* thread = Thread::current(); + ResourceMark rm(thread); + CodeBlob* cb = CodeCache::find_blob(pc); + assert(cb != nullptr && cb == this, ""); + + // Keep tty output consistent. To avoid ttyLocker, we buffer in stream, and print all at once. + stringStream ss; + ss.print_cr("implicit exception happened at " INTPTR_FORMAT, p2i(pc)); + print_on(&ss); + method()->print_codes_on(&ss); + print_code_on(&ss); + print_pcs_on(&ss); + tty->print("%s", ss.as_string()); // print all at once + } +#endif + if (cont_offset == 0) { + // Let the normal error handling report the exception + return nullptr; + } + if (cont_offset == exception_offset) { +#if INCLUDE_JVMCI + Deoptimization::DeoptReason deopt_reason = for_div0_check ? Deoptimization::Reason_div0_check : Deoptimization::Reason_null_check; + JavaThread *thread = JavaThread::current(); + thread->set_jvmci_implicit_exception_pc(pc); + thread->set_pending_deoptimization(Deoptimization::make_trap_request(deopt_reason, + Deoptimization::Action_reinterpret)); + return (SharedRuntime::deopt_blob()->implicit_exception_uncommon_trap()); +#else + ShouldNotReachHere(); +#endif + } + return code_begin() + cont_offset; +} + +class HasEvolDependency : public MetadataClosure { + bool _has_evol_dependency; + public: + HasEvolDependency() : _has_evol_dependency(false) {} + void do_metadata(Metadata* md) { + if (md->is_method()) { + Method* method = (Method*)md; + if (method->is_old()) { + _has_evol_dependency = true; + } + } + } + bool has_evol_dependency() const { return _has_evol_dependency; } +}; + +bool nmethod::has_evol_metadata() { + // Check the metadata in relocIter and CompiledIC and also deoptimize + // any nmethod that has reference to old methods. + HasEvolDependency check_evol; + metadata_do(&check_evol); + if (check_evol.has_evol_dependency() && log_is_enabled(Debug, redefine, class, nmethod)) { + ResourceMark rm; + log_debug(redefine, class, nmethod) + ("Found evol dependency of nmethod %s.%s(%s) compile_id=%d on in nmethod metadata", + _method->method_holder()->external_name(), + _method->name()->as_C_string(), + _method->signature()->as_C_string(), + compile_id()); + } + return check_evol.has_evol_dependency(); +} int nmethod::total_size() const { return @@ -440,16 +1000,28 @@ const char* nmethod::compile_kind() const { return nullptr; } +const char* nmethod::compiler_name() const { + return compilertype2name(_compiler_type); +} + // Fill in default values for various flag fields void nmethod::init_defaults() { + // avoid uninitialized fields, even for short time periods + _exception_cache = nullptr; + + _has_unsafe_access = 0; + _has_method_handle_invokes = 0; + _has_wide_vectors = 0; + _has_monitors = 0; + _state = not_installed; _has_flushed_dependencies = 0; _load_reported = false; // jvmti state - _oops_do_mark_link = nullptr; - _osr_link = nullptr; + _oops_do_mark_link = nullptr; + _osr_link = nullptr; #if INCLUDE_RTM_OPT - _rtm_state = NoRTM; + _rtm_state = NoRTM; #endif } @@ -639,18 +1211,19 @@ nmethod::nmethod( ByteSize basic_lock_owner_sp_offset, ByteSize basic_lock_sp_offset, OopMapSet* oop_maps ) - : CompiledMethod(method, "native nmethod", type, nmethod_size, sizeof(nmethod), code_buffer, offsets->value(CodeOffsets::Frame_Complete), frame_size, oop_maps, false, true), + : CodeBlob("native nmethod", CodeBlobKind::Nmethod, code_buffer, nmethod_size, sizeof(nmethod), + offsets->value(CodeOffsets::Frame_Complete), frame_size, oop_maps, false), + _deoptimization_generation(0), + _method(method), + _gc_data(nullptr), _compiled_ic_data(nullptr), _is_unlinked(false), _native_receiver_sp_offset(basic_lock_owner_sp_offset), _native_basic_lock_sp_offset(basic_lock_sp_offset), - _is_unloading_state(0) + _is_unloading_state(0), + _deoptimization_status(not_marked) { { - int scopes_data_offset = 0; - int deoptimize_offset = 0; - int deoptimize_mh_offset = 0; - debug_only(NoSafepointVerifier nsv;) assert_locked_or_safepoint(CodeCache_lock); @@ -661,14 +1234,16 @@ nmethod::nmethod( // values something that will never match a pc like the nmethod vtable entry _exception_offset = 0; _orig_pc_offset = 0; + _deopt_handler_offset = 0; + _deopt_mh_handler_offset = 0; _gc_epoch = CodeCache::gc_epoch(); _consts_offset = content_offset() + code_buffer->total_offset_of(code_buffer->consts()); _stub_offset = content_offset() + code_buffer->total_offset_of(code_buffer->stubs()); _oops_offset = data_offset(); _metadata_offset = _oops_offset + align_up(code_buffer->total_oop_size(), oopSize); - scopes_data_offset = _metadata_offset + align_up(code_buffer->total_metadata_size(), wordSize); - _scopes_pcs_offset = scopes_data_offset; + _scopes_data_offset = _metadata_offset + align_up(code_buffer->total_metadata_size(), wordSize); + _scopes_pcs_offset = _scopes_data_offset; _dependencies_offset = _scopes_pcs_offset; _handler_table_offset = _dependencies_offset; _nul_chk_table_offset = _handler_table_offset; @@ -681,6 +1256,7 @@ nmethod::nmethod( _nmethod_end_offset = _nul_chk_table_offset; #endif _compile_id = compile_id; + _compiler_type = type; _entry_point = code_begin() + offsets->value(CodeOffsets::Entry); _verified_entry_point = code_begin() + offsets->value(CodeOffsets::Verified_Entry); _osr_entry_point = nullptr; @@ -689,10 +1265,6 @@ nmethod::nmethod( _exception_offset = code_offset() + offsets->value(CodeOffsets::Exceptions); - _scopes_data_begin = (address) this + scopes_data_offset; - _deopt_handler_begin = (address) this + deoptimize_offset; - _deopt_mh_handler_begin = (address) this + deoptimize_mh_offset; - code_buffer->copy_code_and_locs_to(this); code_buffer->copy_values_to(this); @@ -784,51 +1356,54 @@ nmethod::nmethod( JVMCINMethodData* jvmci_data #endif ) - : CompiledMethod(method, "nmethod", type, nmethod_size, sizeof(nmethod), code_buffer, offsets->value(CodeOffsets::Frame_Complete), frame_size, oop_maps, false, true), + : CodeBlob("nmethod", CodeBlobKind::Nmethod, code_buffer, nmethod_size, sizeof(nmethod), + offsets->value(CodeOffsets::Frame_Complete), frame_size, oop_maps, false), + _deoptimization_generation(0), + _method(method), + _gc_data(nullptr), _compiled_ic_data(nullptr), _is_unlinked(false), _native_receiver_sp_offset(in_ByteSize(-1)), _native_basic_lock_sp_offset(in_ByteSize(-1)), - _is_unloading_state(0) + _is_unloading_state(0), + _deoptimization_status(not_marked) { assert(debug_info->oop_recorder() == code_buffer->oop_recorder(), "shared OR"); { debug_only(NoSafepointVerifier nsv;) assert_locked_or_safepoint(CodeCache_lock); - _deopt_handler_begin = (address) this; - _deopt_mh_handler_begin = (address) this; - init_defaults(); - _entry_bci = entry_bci; - _compile_id = compile_id; - _comp_level = comp_level; - _orig_pc_offset = orig_pc_offset; - _gc_epoch = CodeCache::gc_epoch(); + _entry_bci = entry_bci; + _compile_id = compile_id; + _compiler_type = type; + _comp_level = comp_level; + _orig_pc_offset = orig_pc_offset; + _gc_epoch = CodeCache::gc_epoch(); // Section offsets - _consts_offset = content_offset() + code_buffer->total_offset_of(code_buffer->consts()); - _stub_offset = content_offset() + code_buffer->total_offset_of(code_buffer->stubs()); + _consts_offset = content_offset() + code_buffer->total_offset_of(code_buffer->consts()); + _stub_offset = content_offset() + code_buffer->total_offset_of(code_buffer->stubs()); set_ctable_begin(header_begin() + _consts_offset); - _skipped_instructions_size = code_buffer->total_skipped_instructions_size(); + _skipped_instructions_size = code_buffer->total_skipped_instructions_size(); #if INCLUDE_JVMCI if (compiler->is_jvmci()) { // JVMCI might not produce any stub sections if (offsets->value(CodeOffsets::Exceptions) != -1) { - _exception_offset = code_offset() + offsets->value(CodeOffsets::Exceptions); + _exception_offset = code_offset() + offsets->value(CodeOffsets::Exceptions); } else { - _exception_offset = -1; + _exception_offset = -1; } if (offsets->value(CodeOffsets::Deopt) != -1) { - _deopt_handler_begin = (address) this + code_offset() + offsets->value(CodeOffsets::Deopt); + _deopt_handler_offset = code_offset() + offsets->value(CodeOffsets::Deopt); } else { - _deopt_handler_begin = nullptr; + _deopt_handler_offset = -1; } if (offsets->value(CodeOffsets::DeoptMH) != -1) { - _deopt_mh_handler_begin = (address) this + code_offset() + offsets->value(CodeOffsets::DeoptMH); + _deopt_mh_handler_offset = code_offset() + offsets->value(CodeOffsets::DeoptMH); } else { - _deopt_mh_handler_begin = nullptr; + _deopt_mh_handler_offset = -1; } } else #endif @@ -837,25 +1412,25 @@ nmethod::nmethod( assert(offsets->value(CodeOffsets::Exceptions) != -1, "must be set"); assert(offsets->value(CodeOffsets::Deopt ) != -1, "must be set"); - _exception_offset = _stub_offset + offsets->value(CodeOffsets::Exceptions); - _deopt_handler_begin = (address) this + _stub_offset + offsets->value(CodeOffsets::Deopt); + _exception_offset = _stub_offset + offsets->value(CodeOffsets::Exceptions); + _deopt_handler_offset = _stub_offset + offsets->value(CodeOffsets::Deopt); if (offsets->value(CodeOffsets::DeoptMH) != -1) { - _deopt_mh_handler_begin = (address) this + _stub_offset + offsets->value(CodeOffsets::DeoptMH); + _deopt_mh_handler_offset = _stub_offset + offsets->value(CodeOffsets::DeoptMH); } else { - _deopt_mh_handler_begin = nullptr; + _deopt_mh_handler_offset = -1; } } if (offsets->value(CodeOffsets::UnwindHandler) != -1) { - _unwind_handler_offset = code_offset() + offsets->value(CodeOffsets::UnwindHandler); + _unwind_handler_offset = code_offset() + offsets->value(CodeOffsets::UnwindHandler); } else { _unwind_handler_offset = -1; } _oops_offset = data_offset(); _metadata_offset = _oops_offset + align_up(code_buffer->total_oop_size(), oopSize); - int scopes_data_offset = _metadata_offset + align_up(code_buffer->total_metadata_size(), wordSize); + _scopes_data_offset = _metadata_offset + align_up(code_buffer->total_metadata_size(), wordSize); - _scopes_pcs_offset = scopes_data_offset + align_up(debug_info->data_size (), oopSize); + _scopes_pcs_offset = _scopes_data_offset + align_up(debug_info->data_size (), oopSize); _dependencies_offset = _scopes_pcs_offset + adjust_pcs_size(debug_info->pcs_size()); _handler_table_offset = _dependencies_offset + align_up((int)dependencies->size_in_bytes(), oopSize); _nul_chk_table_offset = _handler_table_offset + align_up(handler_table->size_in_bytes(), oopSize); @@ -871,7 +1446,6 @@ nmethod::nmethod( _verified_entry_point = code_begin() + offsets->value(CodeOffsets::Verified_Entry); _osr_entry_point = code_begin() + offsets->value(CodeOffsets::OSR_Entry); _exception_cache = nullptr; - _scopes_data_begin = (address) this + scopes_data_offset; _pc_desc_container.reset_to(scopes_pcs_begin()); @@ -1294,7 +1868,7 @@ void nmethod::inc_decompile_count() { bool nmethod::try_transition(signed char new_state_int) { signed char new_state = new_state_int; - assert_lock_strong(CompiledMethod_lock); + assert_lock_strong(NMethodState_lock); signed char old_state = _state; if (old_state >= new_state) { // Ensure monotonicity of transitions. @@ -1357,7 +1931,7 @@ bool nmethod::make_not_entrant() { { // Enter critical section. Does not block for safepoint. - ConditionalMutexLocker ml(CompiledMethod_lock, !CompiledMethod_lock->owned_by_self(), Mutex::_no_safepoint_check_flag); + ConditionalMutexLocker ml(NMethodState_lock, !NMethodState_lock->owned_by_self(), Mutex::_no_safepoint_check_flag); if (Atomic::load(&_state) == not_entrant) { // another thread already performed this transition so nothing @@ -1400,7 +1974,7 @@ bool nmethod::make_not_entrant() { // Remove nmethod from method. unlink_from_method(); - } // leave critical region under CompiledMethod_lock + } // leave critical region under NMethodState_lock #if INCLUDE_JVMCI // Invalidate can't occur while holding the Patching lock @@ -1430,7 +2004,7 @@ void nmethod::unlink() { flush_dependencies(); - // unlink_from_method will take the CompiledMethod_lock. + // unlink_from_method will take the NMethodState_lock. // In this case we don't strictly need it when unlinking nmethods from // the Method, because it is only concurrently unlinked by // the entry barrier, which acquires the per nmethod lock. @@ -1509,7 +2083,7 @@ oop nmethod::oop_at_phantom(int index) const { void nmethod::flush_dependencies() { if (!has_flushed_dependencies()) { - set_has_flushed_dependencies(); + set_has_flushed_dependencies(true); for (Dependencies::DepStream deps(this); deps.next(); ) { if (deps.type() == Dependencies::call_site_target_value) { // CallSite dependencies are managed on per-CallSite instance basis. @@ -2026,7 +2600,7 @@ void nmethod::copy_scopes_pcs(PcDesc* pcs, int count) { break; } } - assert(has_method_handle_invokes() == (_deopt_mh_handler_begin != nullptr), "must have deopt mh handler"); + assert(has_method_handle_invokes() == (_deopt_mh_handler_offset != -1), "must have deopt mh handler"); int size = count * sizeof(PcDesc); assert(scopes_pcs_size() >= size, "oob"); @@ -2243,7 +2817,7 @@ void nmethod::verify() { nmethod* nm = CodeCache::find_nmethod(verified_entry_point()); if (nm != this) { - fatal("findNMethod did not find this nmethod (" INTPTR_FORMAT ")", p2i(this)); + fatal("find_nmethod did not find this nmethod (" INTPTR_FORMAT ")", p2i(this)); } for (PcDesc* p = scopes_pcs_begin(); p < scopes_pcs_end(); p++) { @@ -2326,7 +2900,7 @@ void nmethod::verify_scopes() { if (method()->is_native()) return; // Ignore stub methods. // iterate through all interrupt point // and verify the debug information is valid. - RelocIterator iter((nmethod*)this); + RelocIterator iter(this); while (iter.next()) { address stub = nullptr; switch (iter.type()) { @@ -2989,8 +3563,8 @@ const char* nmethod::nmethod_section_label(address pos) const { if (pos == consts_begin() && pos != insts_begin()) label = "[Constants]"; // Check stub_code before checking exception_handler or deopt_handler. if (pos == this->stub_begin()) label = "[Stub Code]"; - if (JVMCI_ONLY(_exception_offset >= 0 &&) pos == exception_begin()) label = "[Exception Handler]"; - if (JVMCI_ONLY(_deopt_handler_begin != nullptr &&) pos == deopt_handler_begin()) label = "[Deopt Handler Code]"; + if (JVMCI_ONLY(_exception_offset >= 0 &&) pos == exception_begin()) label = "[Exception Handler]"; + if (JVMCI_ONLY(_deopt_handler_offset != -1 &&) pos == deopt_handler_begin()) label = "[Deopt Handler Code]"; return label; } diff --git a/src/hotspot/share/code/nmethod.hpp b/src/hotspot/share/code/nmethod.hpp index 2993db21305..e4552992f4b 100644 --- a/src/hotspot/share/code/nmethod.hpp +++ b/src/hotspot/share/code/nmethod.hpp @@ -25,15 +25,122 @@ #ifndef SHARE_CODE_NMETHOD_HPP #define SHARE_CODE_NMETHOD_HPP -#include "code/compiledMethod.hpp" - +#include "code/codeBlob.hpp" +#include "code/pcDesc.hpp" +#include "oops/metadata.hpp" +#include "oops/method.hpp" + +class AbstractCompiler; +class CompiledDirectCall; +class CompiledIC; class CompiledICData; class CompileTask; class DepChange; +class Dependencies; class DirectiveSet; class DebugInformationRecorder; +class ExceptionHandlerTable; +class ImplicitExceptionTable; class JvmtiThreadState; +class MetadataClosure; +class NativeCallWrapper; class OopIterateClosure; +class ScopeDesc; +class xmlStream; + +// This class is used internally by nmethods, to cache +// exception/pc/handler information. + +class ExceptionCache : public CHeapObj { + friend class VMStructs; + private: + enum { cache_size = 16 }; + Klass* _exception_type; + address _pc[cache_size]; + address _handler[cache_size]; + volatile int _count; + ExceptionCache* volatile _next; + ExceptionCache* _purge_list_next; + + inline address pc_at(int index); + void set_pc_at(int index, address a) { assert(index >= 0 && index < cache_size,""); _pc[index] = a; } + + inline address handler_at(int index); + void set_handler_at(int index, address a) { assert(index >= 0 && index < cache_size,""); _handler[index] = a; } + + inline int count(); + // increment_count is only called under lock, but there may be concurrent readers. + void increment_count(); + + public: + + ExceptionCache(Handle exception, address pc, address handler); + + Klass* exception_type() { return _exception_type; } + ExceptionCache* next(); + void set_next(ExceptionCache *ec); + ExceptionCache* purge_list_next() { return _purge_list_next; } + void set_purge_list_next(ExceptionCache *ec) { _purge_list_next = ec; } + + address match(Handle exception, address pc); + bool match_exception_with_space(Handle exception) ; + address test_address(address addr); + bool add_address_and_handler(address addr, address handler) ; +}; + +// cache pc descs found in earlier inquiries +class PcDescCache { + friend class VMStructs; + private: + enum { cache_size = 4 }; + // The array elements MUST be volatile! Several threads may modify + // and read from the cache concurrently. find_pc_desc_internal has + // returned wrong results. C++ compiler (namely xlC12) may duplicate + // C++ field accesses if the elements are not volatile. + typedef PcDesc* PcDescPtr; + volatile PcDescPtr _pc_descs[cache_size]; // last cache_size pc_descs found + public: + PcDescCache() { debug_only(_pc_descs[0] = nullptr); } + void reset_to(PcDesc* initial_pc_desc); + PcDesc* find_pc_desc(int pc_offset, bool approximate); + void add_pc_desc(PcDesc* pc_desc); + PcDesc* last_pc_desc() { return _pc_descs[0]; } +}; + +class PcDescSearch { +private: + address _code_begin; + PcDesc* _lower; + PcDesc* _upper; +public: + PcDescSearch(address code, PcDesc* lower, PcDesc* upper) : + _code_begin(code), _lower(lower), _upper(upper) + { + } + + address code_begin() const { return _code_begin; } + PcDesc* scopes_pcs_begin() const { return _lower; } + PcDesc* scopes_pcs_end() const { return _upper; } +}; + +class PcDescContainer { +private: + PcDescCache _pc_desc_cache; +public: + PcDescContainer() {} + + PcDesc* find_pc_desc_internal(address pc, bool approximate, const PcDescSearch& search); + void reset_to(PcDesc* initial_pc_desc) { _pc_desc_cache.reset_to(initial_pc_desc); } + + PcDesc* find_pc_desc(address pc, bool approximate, const PcDescSearch& search) { + address base_address = search.code_begin(); + PcDesc* desc = _pc_desc_cache.last_pc_desc(); + if (desc != nullptr && desc->pc_offset() == pc - base_address) { + return desc; + } + return find_pc_desc_internal(pc, approximate, search); + } +}; // nmethods (native methods) are the compiled code versions of Java methods. // @@ -65,131 +172,32 @@ class FailedSpeculation; class JVMCINMethodData; #endif -class nmethod : public CompiledMethod { +class nmethod : public CodeBlob { friend class VMStructs; friend class JVMCIVMStructs; friend class CodeCache; // scavengable oops friend class JVMCINMethodData; + friend class DeoptimizationScope; private: + // Used to track in which deoptimize handshake this method will be deoptimized. + uint64_t _deoptimization_generation; + uint64_t _gc_epoch; + Method* _method; + // To support simple linked-list chaining of nmethods: nmethod* _osr_link; // from InstanceKlass::osr_nmethods_head - // STW two-phase nmethod root processing helpers. - // - // When determining liveness of a given nmethod to do code cache unloading, - // some collectors need to do different things depending on whether the nmethods - // need to absolutely be kept alive during root processing; "strong"ly reachable - // nmethods are known to be kept alive at root processing, but the liveness of - // "weak"ly reachable ones is to be determined later. - // - // We want to allow strong and weak processing of nmethods by different threads - // at the same time without heavy synchronization. Additional constraints are - // to make sure that every nmethod is processed a minimal amount of time, and - // nmethods themselves are always iterated at most once at a particular time. - // - // Note that strong processing work must be a superset of weak processing work - // for this code to work. - // - // We store state and claim information in the _oops_do_mark_link member, using - // the two LSBs for the state and the remaining upper bits for linking together - // nmethods that were already visited. - // The last element is self-looped, i.e. points to itself to avoid some special - // "end-of-list" sentinel value. - // - // _oops_do_mark_link special values: - // - // _oops_do_mark_link == nullptr: the nmethod has not been visited at all yet, i.e. - // is Unclaimed. - // - // For other values, its lowest two bits indicate the following states of the nmethod: - // - // weak_request (WR): the nmethod has been claimed by a thread for weak processing - // weak_done (WD): weak processing has been completed for this nmethod. - // strong_request (SR): the nmethod has been found to need strong processing while - // being weak processed. - // strong_done (SD): strong processing has been completed for this nmethod . - // - // The following shows the _only_ possible progressions of the _oops_do_mark_link - // pointer. - // - // Given - // N as the nmethod - // X the current next value of _oops_do_mark_link - // - // Unclaimed (C)-> N|WR (C)-> X|WD: the nmethod has been processed weakly by - // a single thread. - // Unclaimed (C)-> N|WR (C)-> X|WD (O)-> X|SD: after weak processing has been - // completed (as above) another thread found that the nmethod needs strong - // processing after all. - // Unclaimed (C)-> N|WR (O)-> N|SR (C)-> X|SD: during weak processing another - // thread finds that the nmethod needs strong processing, marks it as such and - // terminates. The original thread completes strong processing. - // Unclaimed (C)-> N|SD (C)-> X|SD: the nmethod has been processed strongly from - // the beginning by a single thread. - // - // "|" describes the concatenation of bits in _oops_do_mark_link. - // - // The diagram also describes the threads responsible for changing the nmethod to - // the next state by marking the _transition_ with (C) and (O), which mean "current" - // and "other" thread respectively. - // - struct oops_do_mark_link; // Opaque data type. - - // States used for claiming nmethods during root processing. - static const uint claim_weak_request_tag = 0; - static const uint claim_weak_done_tag = 1; - static const uint claim_strong_request_tag = 2; - static const uint claim_strong_done_tag = 3; + PcDescContainer _pc_desc_container; + ExceptionCache* volatile _exception_cache; - static oops_do_mark_link* mark_link(nmethod* nm, uint tag) { - assert(tag <= claim_strong_done_tag, "invalid tag %u", tag); - assert(is_aligned(nm, 4), "nmethod pointer must have zero lower two LSB"); - return (oops_do_mark_link*)(((uintptr_t)nm & ~0x3) | tag); - } - - static uint extract_state(oops_do_mark_link* link) { - return (uint)((uintptr_t)link & 0x3); - } - - static nmethod* extract_nmethod(oops_do_mark_link* link) { - return (nmethod*)((uintptr_t)link & ~0x3); - } - - void oops_do_log_change(const char* state); - - static bool oops_do_has_weak_request(oops_do_mark_link* next) { - return extract_state(next) == claim_weak_request_tag; - } + void* _gc_data; - static bool oops_do_has_any_strong_state(oops_do_mark_link* next) { - return extract_state(next) >= claim_strong_request_tag; - } - - // Attempt Unclaimed -> N|WR transition. Returns true if successful. - bool oops_do_try_claim_weak_request(); - - // Attempt Unclaimed -> N|SD transition. Returns the current link. - oops_do_mark_link* oops_do_try_claim_strong_done(); - // Attempt N|WR -> X|WD transition. Returns nullptr if successful, X otherwise. - nmethod* oops_do_try_add_to_list_as_weak_done(); - - // Attempt X|WD -> N|SR transition. Returns the current link. - oops_do_mark_link* oops_do_try_add_strong_request(oops_do_mark_link* next); - // Attempt X|WD -> X|SD transition. Returns true if successful. - bool oops_do_try_claim_weak_done_as_strong_done(oops_do_mark_link* next); - - // Do the N|SD -> X|SD transition. - void oops_do_add_to_list_as_strong_done(); - - // Sets this nmethod as strongly claimed (as part of N|SD -> X|SD and N|SR -> X|SD - // transitions). - void oops_do_set_strong_done(nmethod* old_head); - - static nmethod* volatile _oops_do_mark_nmethods; + struct oops_do_mark_link; // Opaque data type. + static nmethod* volatile _oops_do_mark_nmethods; oops_do_mark_link* volatile _oops_do_mark_link; // offsets for entry points @@ -198,13 +206,18 @@ class nmethod : public CompiledMethod { address _osr_entry_point; // entry point for on stack replacement CompiledICData* _compiled_ic_data; - bool _is_unlinked; // Shared fields for all nmethod's int _entry_bci; // != InvocationEntryBci if this nmethod is an on-stack replacement method // Offsets for different nmethod parts int _exception_offset; + // All deoptee's will resume execution at this location described by + // this offset. + int _deopt_handler_offset; + // All deoptee's at a MethodHandle call site will resume execution + // at this location described by this offset. + int _deopt_mh_handler_offset; // Offset of the unwind handler if it exists int _unwind_handler_offset; @@ -222,14 +235,17 @@ class nmethod : public CompiledMethod { int _jvmci_data_offset; #endif int _nmethod_end_offset; - - int code_offset() const { return int(code_begin() - header_begin()); } + int _skipped_instructions_size; // location in frame (offset for sp) that deopt can store the original // pc during a deopt. int _orig_pc_offset; - int _compile_id; // which compilation made this nmethod + int _compile_id; // which compilation made this nmethod + + CompilerType _compiler_type; // which compiler made this nmethod (u1) + + bool _is_unlinked; #if INCLUDE_RTM_OPT // RTM state at compile time. Used during deoptimization to decide @@ -248,21 +264,36 @@ class nmethod : public CompiledMethod { ByteSize _native_receiver_sp_offset; ByteSize _native_basic_lock_sp_offset; - CompLevel _comp_level; // compilation level + CompLevel _comp_level; // compilation level (s1) // Local state used to keep track of whether unloading is happening or not volatile uint8_t _is_unloading_state; - // protected by CodeCache_lock - bool _has_flushed_dependencies; // Used for maintenance of dependencies (CodeCache_lock) - // used by jvmti to track if an event has been posted for this nmethod. bool _load_reported; - // Protected by CompiledMethod_lock - volatile signed char _state; // {not_installed, in_use, not_used, not_entrant} + // Protected by NMethodState_lock + volatile signed char _state; // {not_installed, in_use, not_entrant} + + // set during construction + uint8_t _has_unsafe_access:1, // May fault due to unsafe access. + _has_method_handle_invokes:1,// Has this method MethodHandle invokes? + _has_wide_vectors:1, // Preserve wide vectors at safepoints + _has_monitors:1, // Fastpath monitor detection for continuations + _has_flushed_dependencies:1; // Used for maintenance of dependencies (under CodeCache_lock) + + enum DeoptimizationStatus : u1 { + not_marked, + deoptimize, + deoptimize_noupdate, + deoptimize_done + }; - int _skipped_instructions_size; + volatile DeoptimizationStatus _deoptimization_status; // Used for stack deoptimization + + DeoptimizationStatus deoptimization_status() const { + return Atomic::load(&_deoptimization_status); + } // For native wrappers nmethod(Method* method, @@ -302,6 +333,7 @@ class nmethod : public CompiledMethod { // helper methods void* operator new(size_t size, int nmethod_size, int comp_level) throw(); + // For method handle intrinsics: Try MethodNonProfiled, MethodProfiled and NonNMethod. // Attention: Only allow NonNMethod space for special nmethods which don't need to be // findable by nmethod iterators! In particular, they must not contain oops! @@ -322,13 +354,121 @@ class nmethod : public CompiledMethod { // Initialize fields to their default values void init_defaults(); - // Offsets - int content_offset() const { return int(content_begin() - header_begin()); } - int data_offset() const { return _data_offset; } + PcDesc* find_pc_desc(address pc, bool approximate) { + return _pc_desc_container.find_pc_desc(pc, approximate, PcDescSearch(code_begin(), scopes_pcs_begin(), scopes_pcs_end())); + } + + // STW two-phase nmethod root processing helpers. + // + // When determining liveness of a given nmethod to do code cache unloading, + // some collectors need to do different things depending on whether the nmethods + // need to absolutely be kept alive during root processing; "strong"ly reachable + // nmethods are known to be kept alive at root processing, but the liveness of + // "weak"ly reachable ones is to be determined later. + // + // We want to allow strong and weak processing of nmethods by different threads + // at the same time without heavy synchronization. Additional constraints are + // to make sure that every nmethod is processed a minimal amount of time, and + // nmethods themselves are always iterated at most once at a particular time. + // + // Note that strong processing work must be a superset of weak processing work + // for this code to work. + // + // We store state and claim information in the _oops_do_mark_link member, using + // the two LSBs for the state and the remaining upper bits for linking together + // nmethods that were already visited. + // The last element is self-looped, i.e. points to itself to avoid some special + // "end-of-list" sentinel value. + // + // _oops_do_mark_link special values: + // + // _oops_do_mark_link == nullptr: the nmethod has not been visited at all yet, i.e. + // is Unclaimed. + // + // For other values, its lowest two bits indicate the following states of the nmethod: + // + // weak_request (WR): the nmethod has been claimed by a thread for weak processing + // weak_done (WD): weak processing has been completed for this nmethod. + // strong_request (SR): the nmethod has been found to need strong processing while + // being weak processed. + // strong_done (SD): strong processing has been completed for this nmethod . + // + // The following shows the _only_ possible progressions of the _oops_do_mark_link + // pointer. + // + // Given + // N as the nmethod + // X the current next value of _oops_do_mark_link + // + // Unclaimed (C)-> N|WR (C)-> X|WD: the nmethod has been processed weakly by + // a single thread. + // Unclaimed (C)-> N|WR (C)-> X|WD (O)-> X|SD: after weak processing has been + // completed (as above) another thread found that the nmethod needs strong + // processing after all. + // Unclaimed (C)-> N|WR (O)-> N|SR (C)-> X|SD: during weak processing another + // thread finds that the nmethod needs strong processing, marks it as such and + // terminates. The original thread completes strong processing. + // Unclaimed (C)-> N|SD (C)-> X|SD: the nmethod has been processed strongly from + // the beginning by a single thread. + // + // "|" describes the concatenation of bits in _oops_do_mark_link. + // + // The diagram also describes the threads responsible for changing the nmethod to + // the next state by marking the _transition_ with (C) and (O), which mean "current" + // and "other" thread respectively. + // + + // States used for claiming nmethods during root processing. + static const uint claim_weak_request_tag = 0; + static const uint claim_weak_done_tag = 1; + static const uint claim_strong_request_tag = 2; + static const uint claim_strong_done_tag = 3; + + static oops_do_mark_link* mark_link(nmethod* nm, uint tag) { + assert(tag <= claim_strong_done_tag, "invalid tag %u", tag); + assert(is_aligned(nm, 4), "nmethod pointer must have zero lower two LSB"); + return (oops_do_mark_link*)(((uintptr_t)nm & ~0x3) | tag); + } + + static uint extract_state(oops_do_mark_link* link) { + return (uint)((uintptr_t)link & 0x3); + } + + static nmethod* extract_nmethod(oops_do_mark_link* link) { + return (nmethod*)((uintptr_t)link & ~0x3); + } + + void oops_do_log_change(const char* state); - address header_end() const { return (address) header_begin() + header_size(); } + static bool oops_do_has_weak_request(oops_do_mark_link* next) { + return extract_state(next) == claim_weak_request_tag; + } - public: + static bool oops_do_has_any_strong_state(oops_do_mark_link* next) { + return extract_state(next) >= claim_strong_request_tag; + } + + // Attempt Unclaimed -> N|WR transition. Returns true if successful. + bool oops_do_try_claim_weak_request(); + + // Attempt Unclaimed -> N|SD transition. Returns the current link. + oops_do_mark_link* oops_do_try_claim_strong_done(); + // Attempt N|WR -> X|WD transition. Returns nullptr if successful, X otherwise. + nmethod* oops_do_try_add_to_list_as_weak_done(); + + // Attempt X|WD -> N|SR transition. Returns the current link. + oops_do_mark_link* oops_do_try_add_strong_request(oops_do_mark_link* next); + // Attempt X|WD -> X|SD transition. Returns true if successful. + bool oops_do_try_claim_weak_done_as_strong_done(oops_do_mark_link* next); + + // Do the N|SD -> X|SD transition. + void oops_do_add_to_list_as_strong_done(); + + // Sets this nmethod as strongly claimed (as part of N|SD -> X|SD and N|SR -> X|SD + // transitions). + void oops_do_set_strong_done(nmethod* old_head); + +public: // create nmethod with entry_bci static nmethod* new_nmethod(const methodHandle& method, int compile_id, @@ -351,14 +491,6 @@ class nmethod : public CompiledMethod { #endif ); - // Only used for unit tests. - nmethod() - : CompiledMethod(), - _native_receiver_sp_offset(in_ByteSize(-1)), - _native_basic_lock_sp_offset(in_ByteSize(-1)), - _is_unloading_state(0) {} - - static nmethod* new_native_nmethod(const methodHandle& method, int compile_id, CodeBuffer *code_buffer, @@ -370,86 +502,126 @@ class nmethod : public CompiledMethod { OopMapSet* oop_maps, int exception_handler = -1); - // type info - bool is_nmethod() const { return true; } - bool is_osr_method() const { return _entry_bci != InvocationEntryBci; } + Method* method () const { return _method; } + bool is_native_method() const { return _method != nullptr && _method->is_native(); } + bool is_java_method () const { return _method != nullptr && !_method->is_native(); } + bool is_osr_method () const { return _entry_bci != InvocationEntryBci; } + + // Compiler task identification. Note that all OSR methods + // are numbered in an independent sequence if CICountOSR is true, + // and native method wrappers are also numbered independently if + // CICountNative is true. + int compile_id() const { return _compile_id; } + const char* compile_kind() const; + + inline bool is_compiled_by_c1 () const { return _compiler_type == compiler_c1; } + inline bool is_compiled_by_c2 () const { return _compiler_type == compiler_c2; } + inline bool is_compiled_by_jvmci() const { return _compiler_type == compiler_jvmci; } + CompilerType compiler_type () const { return _compiler_type; } + const char* compiler_name () const; // boundaries for different parts - address consts_begin () const { return header_begin() + _consts_offset ; } - address consts_end () const { return code_begin() ; } - address stub_begin () const { return header_begin() + _stub_offset ; } - address stub_end () const { return header_begin() + _oops_offset ; } - address exception_begin () const { return header_begin() + _exception_offset ; } - address unwind_handler_begin () const { return _unwind_handler_offset != -1 ? (header_begin() + _unwind_handler_offset) : nullptr; } - oop* oops_begin () const { return (oop*) (header_begin() + _oops_offset) ; } - oop* oops_end () const { return (oop*) (header_begin() + _metadata_offset) ; } - - Metadata** metadata_begin () const { return (Metadata**) (header_begin() + _metadata_offset) ; } - Metadata** metadata_end () const { return (Metadata**) _scopes_data_begin; } - - address scopes_data_end () const { return header_begin() + _scopes_pcs_offset ; } - PcDesc* scopes_pcs_begin () const { return (PcDesc*)(header_begin() + _scopes_pcs_offset ); } - PcDesc* scopes_pcs_end () const { return (PcDesc*)(header_begin() + _dependencies_offset) ; } - address dependencies_begin () const { return header_begin() + _dependencies_offset ; } - address dependencies_end () const { return header_begin() + _handler_table_offset ; } - address handler_table_begin () const { return header_begin() + _handler_table_offset ; } - address handler_table_end () const { return header_begin() + _nul_chk_table_offset ; } - address nul_chk_table_begin () const { return header_begin() + _nul_chk_table_offset ; } - - int skipped_instructions_size () const { return _skipped_instructions_size ; } + address consts_begin () const { return header_begin() + _consts_offset ; } + address consts_end () const { return header_begin() + code_offset() ; } + address insts_begin () const { return header_begin() + code_offset() ; } + address insts_end () const { return header_begin() + _stub_offset ; } + address stub_begin () const { return header_begin() + _stub_offset ; } + address stub_end () const { return header_begin() + _oops_offset ; } + address exception_begin () const { return header_begin() + _exception_offset ; } + address deopt_handler_begin () const { return header_begin() + _deopt_handler_offset ; } + address deopt_mh_handler_begin() const { return header_begin() + _deopt_mh_handler_offset ; } + address unwind_handler_begin () const { return _unwind_handler_offset != -1 ? (header_begin() + _unwind_handler_offset) : nullptr; } + oop* oops_begin () const { return (oop*) (header_begin() + _oops_offset) ; } + oop* oops_end () const { return (oop*) (header_begin() + _metadata_offset) ; } + + Metadata** metadata_begin () const { return (Metadata**) (header_begin() + _metadata_offset) ; } + Metadata** metadata_end () const { return (Metadata**) (header_begin() + _scopes_data_offset) ; } + + address scopes_data_begin () const { return header_begin() + _scopes_data_offset ; } + address scopes_data_end () const { return header_begin() + _scopes_pcs_offset ; } + PcDesc* scopes_pcs_begin () const { return (PcDesc*)(header_begin() + _scopes_pcs_offset) ; } + PcDesc* scopes_pcs_end () const { return (PcDesc*)(header_begin() + _dependencies_offset) ; } + address dependencies_begin () const { return header_begin() + _dependencies_offset ; } + address dependencies_end () const { return header_begin() + _handler_table_offset ; } + address handler_table_begin () const { return header_begin() + _handler_table_offset ; } + address handler_table_end () const { return header_begin() + _nul_chk_table_offset ; } + address nul_chk_table_begin () const { return header_begin() + _nul_chk_table_offset ; } #if INCLUDE_JVMCI - address nul_chk_table_end () const { return header_begin() + _speculations_offset ; } - address speculations_begin () const { return header_begin() + _speculations_offset ; } - address speculations_end () const { return header_begin() + _jvmci_data_offset ; } - address jvmci_data_begin () const { return header_begin() + _jvmci_data_offset ; } - address jvmci_data_end () const { return header_begin() + _nmethod_end_offset ; } + address nul_chk_table_end () const { return header_begin() + _speculations_offset ; } + address speculations_begin () const { return header_begin() + _speculations_offset ; } + address speculations_end () const { return header_begin() + _jvmci_data_offset ; } + address jvmci_data_begin () const { return header_begin() + _jvmci_data_offset ; } + address jvmci_data_end () const { return header_begin() + _nmethod_end_offset ; } #else - address nul_chk_table_end () const { return header_begin() + _nmethod_end_offset ; } + address nul_chk_table_end () const { return header_begin() + _nmethod_end_offset ; } #endif // Sizes - int oops_size () const { return int((address) oops_end () - (address) oops_begin ()); } - int metadata_size () const { return int((address) metadata_end () - (address) metadata_begin ()); } - int dependencies_size () const { return int( dependencies_end () - dependencies_begin ()); } + int consts_size () const { return int( consts_end () - consts_begin ()); } + int insts_size () const { return int( insts_end () - insts_begin ()); } + int stub_size () const { return int( stub_end () - stub_begin ()); } + int oops_size () const { return int((address) oops_end () - (address) oops_begin ()); } + int metadata_size () const { return int((address) metadata_end () - (address) metadata_begin ()); } + int scopes_data_size () const { return int( scopes_data_end () - scopes_data_begin ()); } + int scopes_pcs_size () const { return int((intptr_t)scopes_pcs_end () - (intptr_t)scopes_pcs_begin ()); } + int dependencies_size () const { return int( dependencies_end () - dependencies_begin ()); } + int handler_table_size() const { return int( handler_table_end() - handler_table_begin()); } + int nul_chk_table_size() const { return int( nul_chk_table_end() - nul_chk_table_begin()); } #if INCLUDE_JVMCI - int speculations_size () const { return int( speculations_end () - speculations_begin ()); } - int jvmci_data_size () const { return int( jvmci_data_end () - jvmci_data_begin ()); } + int speculations_size () const { return int( speculations_end () - speculations_begin ()); } + int jvmci_data_size () const { return int( jvmci_data_end () - jvmci_data_begin ()); } #endif int oops_count() const { assert(oops_size() % oopSize == 0, ""); return (oops_size() / oopSize) + 1; } int metadata_count() const { assert(metadata_size() % wordSize == 0, ""); return (metadata_size() / wordSize) + 1; } - int total_size () const; + int skipped_instructions_size () const { return _skipped_instructions_size; } + int total_size() const; // Containment - bool oops_contains (oop* addr) const { return oops_begin () <= addr && addr < oops_end (); } - bool metadata_contains (Metadata** addr) const { return metadata_begin () <= addr && addr < metadata_end (); } - bool scopes_data_contains (address addr) const { return scopes_data_begin () <= addr && addr < scopes_data_end (); } - bool scopes_pcs_contains (PcDesc* addr) const { return scopes_pcs_begin () <= addr && addr < scopes_pcs_end (); } + bool consts_contains (address addr) const { return consts_begin () <= addr && addr < consts_end (); } + // Returns true if a given address is in the 'insts' section. The method + // insts_contains_inclusive() is end-inclusive. + bool insts_contains (address addr) const { return insts_begin () <= addr && addr < insts_end (); } + bool insts_contains_inclusive(address addr) const { return insts_begin () <= addr && addr <= insts_end (); } + bool stub_contains (address addr) const { return stub_begin () <= addr && addr < stub_end (); } + bool oops_contains (oop* addr) const { return oops_begin () <= addr && addr < oops_end (); } + bool metadata_contains (Metadata** addr) const { return metadata_begin () <= addr && addr < metadata_end (); } + bool scopes_data_contains (address addr) const { return scopes_data_begin () <= addr && addr < scopes_data_end (); } + bool scopes_pcs_contains (PcDesc* addr) const { return scopes_pcs_begin () <= addr && addr < scopes_pcs_end (); } + bool handler_table_contains (address addr) const { return handler_table_begin() <= addr && addr < handler_table_end(); } + bool nul_chk_table_contains (address addr) const { return nul_chk_table_begin() <= addr && addr < nul_chk_table_end(); } // entry points - address entry_point() const { return _entry_point; } // normal entry point - address verified_entry_point() const { return _verified_entry_point; } // if klass is correct + address entry_point() const { return _entry_point; } // normal entry point + address verified_entry_point() const { return _verified_entry_point; } // if klass is correct + + enum : signed char { not_installed = -1, // in construction, only the owner doing the construction is + // allowed to advance state + in_use = 0, // executable nmethod + not_entrant = 1 // marked for deoptimization but activations may still exist + }; // flag accessing and manipulation - bool is_not_installed() const { return _state == not_installed; } - bool is_in_use() const { return _state <= in_use; } - bool is_not_entrant() const { return _state == not_entrant; } + bool is_not_installed() const { return _state == not_installed; } + bool is_in_use() const { return _state <= in_use; } + bool is_not_entrant() const { return _state == not_entrant; } + int get_state() const { return _state; } void clear_unloading_state(); // Heuristically deduce an nmethod isn't worth keeping around bool is_cold(); - virtual bool is_unloading(); - virtual void do_unloading(bool unloading_occurred); + bool is_unloading(); + void do_unloading(bool unloading_occurred); - bool is_unlinked() const { return _is_unlinked; } - void set_is_unlinked() { assert(!_is_unlinked, "already unlinked"); _is_unlinked = true; } + bool is_unlinked() const { return _is_unlinked; } + void set_is_unlinked() { assert(!_is_unlinked, "already unlinked"); _is_unlinked = true; } #if INCLUDE_RTM_OPT // rtm state accessing and manipulating - RTMState rtm_state() const { return _rtm_state; } - void set_rtm_state(RTMState state) { _rtm_state = state; } + RTMState rtm_state() const { return _rtm_state; } + void set_rtm_state(RTMState state) { _rtm_state = state; } #endif bool make_in_use() { @@ -462,23 +634,51 @@ class nmethod : public CompiledMethod { bool make_not_entrant(); bool make_not_used() { return make_not_entrant(); } - int get_state() const { - return _state; + bool is_marked_for_deoptimization() const { return deoptimization_status() != not_marked; } + bool has_been_deoptimized() const { return deoptimization_status() == deoptimize_done; } + void set_deoptimized_done(); + + bool update_recompile_counts() const { + // Update recompile counts when either the update is explicitly requested (deoptimize) + // or the nmethod is not marked for deoptimization at all (not_marked). + // The latter happens during uncommon traps when deoptimized nmethod is made not entrant. + DeoptimizationStatus status = deoptimization_status(); + return status != deoptimize_noupdate && status != deoptimize_done; } + // tells whether frames described by this nmethod can be deoptimized + // note: native wrappers cannot be deoptimized. + bool can_be_deoptimized() const { return is_java_method(); } + bool has_dependencies() { return dependencies_size() != 0; } void print_dependencies_on(outputStream* out) PRODUCT_RETURN; void flush_dependencies(); - bool has_flushed_dependencies() { return _has_flushed_dependencies; } - void set_has_flushed_dependencies() { + + template + T* gc_data() const { return reinterpret_cast(_gc_data); } + template + void set_gc_data(T* gc_data) { _gc_data = reinterpret_cast(gc_data); } + + bool has_unsafe_access() const { return _has_unsafe_access; } + void set_has_unsafe_access(bool z) { _has_unsafe_access = z; } + + bool has_monitors() const { return _has_monitors; } + void set_has_monitors(bool z) { _has_monitors = z; } + + bool has_method_handle_invokes() const { return _has_method_handle_invokes; } + void set_has_method_handle_invokes(bool z) { _has_method_handle_invokes = z; } + + bool has_wide_vectors() const { return _has_wide_vectors; } + void set_has_wide_vectors(bool z) { _has_wide_vectors = z; } + + bool has_flushed_dependencies() const { return _has_flushed_dependencies; } + void set_has_flushed_dependencies(bool z) { assert(!has_flushed_dependencies(), "should only happen once"); - _has_flushed_dependencies = 1; + _has_flushed_dependencies = z; } int comp_level() const { return _comp_level; } - void unlink_from_method(); - // Support for oops in scopes and relocs: // Note: index 0 is reserved for null. oop oop_at(int index) const; @@ -491,7 +691,7 @@ class nmethod : public CompiledMethod { // Support for meta data in scopes and relocs: // Note: index 0 is reserved for null. - Metadata* metadata_at(int index) const { return index == 0 ? nullptr: *metadata_addr_at(index); } + Metadata* metadata_at(int index) const { return index == 0 ? nullptr: *metadata_addr_at(index); } Metadata** metadata_addr_at(int index) const { // for GC // relocation indexes are biased by 1 (because 0 is reserved) assert(index > 0 && index <= metadata_count(), "must be a valid non-zero index"); @@ -506,10 +706,85 @@ class nmethod : public CompiledMethod { void fix_oop_relocations(address begin, address end, bool initialize_immediates); inline void initialize_immediate_oop(oop* dest, jobject handle); +protected: + address oops_reloc_begin() const; + public: void fix_oop_relocations(address begin, address end) { fix_oop_relocations(begin, end, false); } void fix_oop_relocations() { fix_oop_relocations(nullptr, nullptr, false); } + bool is_at_poll_return(address pc); + bool is_at_poll_or_poll_return(address pc); + +protected: + // Exception cache support + // Note: _exception_cache may be read and cleaned concurrently. + ExceptionCache* exception_cache() const { return _exception_cache; } + ExceptionCache* exception_cache_acquire() const; + void set_exception_cache(ExceptionCache *ec) { _exception_cache = ec; } + +public: + address handler_for_exception_and_pc(Handle exception, address pc); + void add_handler_for_exception_and_pc(Handle exception, address pc, address handler); + void clean_exception_cache(); + + void add_exception_cache_entry(ExceptionCache* new_entry); + ExceptionCache* exception_cache_entry_for_exception(Handle exception); + + + // MethodHandle + bool is_method_handle_return(address return_pc); + // Deopt + // Return true is the PC is one would expect if the frame is being deopted. + inline bool is_deopt_pc(address pc); + inline bool is_deopt_mh_entry(address pc); + inline bool is_deopt_entry(address pc); + + // Accessor/mutator for the original pc of a frame before a frame was deopted. + address get_original_pc(const frame* fr) { return *orig_pc_addr(fr); } + void set_original_pc(const frame* fr, address pc) { *orig_pc_addr(fr) = pc; } + + const char* state() const; + + bool inlinecache_check_contains(address addr) const { + return (addr >= code_begin() && addr < verified_entry_point()); + } + + void preserve_callee_argument_oops(frame fr, const RegisterMap *reg_map, OopClosure* f) override; + + // implicit exceptions support + address continuation_for_implicit_div0_exception(address pc) { return continuation_for_implicit_exception(pc, true); } + address continuation_for_implicit_null_exception(address pc) { return continuation_for_implicit_exception(pc, false); } + + // Inline cache support for class unloading and nmethod unloading + private: + void cleanup_inline_caches_impl(bool unloading_occurred, bool clean_all); + + address continuation_for_implicit_exception(address pc, bool for_div0_check); + + public: + // Serial version used by whitebox test + void cleanup_inline_caches_whitebox(); + + void clear_inline_caches(); + + // Execute nmethod barrier code, as if entering through nmethod call. + void run_nmethod_entry_barrier(); + + void verify_oop_relocations(); + + bool has_evol_metadata(); + + Method* attached_method(address call_pc); + Method* attached_method_before_pc(address pc); + + // GC unloading support + // Cleans unloaded klasses and unloaded nmethods in inline caches + + void unload_nmethod_caches(bool class_unloading_occurred); + + void unlink_from_method(); + // On-stack replacement support int osr_entry_bci() const { assert(is_osr_method(), "wrong kind of nmethod"); return _entry_bci; } address osr_entry() const { assert(is_osr_method(), "wrong kind of nmethod"); return _osr_entry_point; } @@ -524,7 +799,7 @@ class nmethod : public CompiledMethod { void unlink(); // Deallocate this nmethod - called by the GC - void purge(bool free_code_cache_data, bool unregister_nmethod); + void purge(bool free_code_cache_data, bool unregister_nmethod) override; // See comment at definition of _last_seen_on_stack void mark_as_maybe_on_stack(); @@ -549,7 +824,6 @@ class nmethod : public CompiledMethod { } #endif - public: void oops_do(OopClosure* f) { oops_do(f, false); } void oops_do(OopClosure* f, bool allow_dead); @@ -591,6 +865,15 @@ class nmethod : public CompiledMethod { void set_load_reported() { _load_reported = true; } public: + // ScopeDesc retrieval operation + PcDesc* pc_desc_at(address pc) { return find_pc_desc(pc, false); } + // pc_desc_near returns the first PcDesc at or after the given pc. + PcDesc* pc_desc_near(address pc) { return find_pc_desc(pc, true); } + + // ScopeDesc for an instruction + ScopeDesc* scope_desc_at(address pc); + ScopeDesc* scope_desc_near(address pc); + // copying of debugging information void copy_scopes_pcs(PcDesc* pcs, int count); void copy_scopes_data(address buffer, int size); @@ -604,7 +887,7 @@ class nmethod : public CompiledMethod { void post_compiled_method_load_event(JvmtiThreadState* state = nullptr); // verify operations - void verify(); + void verify() override; void verify_scopes(); void verify_interrupt_point(address interrupt_point, bool is_inline_cache); @@ -616,8 +899,8 @@ class nmethod : public CompiledMethod { void decode(outputStream* st) const { decode2(st); } // just delegate here. // printing support - void print() const; - void print(outputStream* st) const; + void print() const override; + void print(outputStream* st) const; void print_code(); #if defined(SUPPORT_DATA_STRUCTS) @@ -626,7 +909,7 @@ class nmethod : public CompiledMethod { void print_pcs_on(outputStream* st); void print_scopes() { print_scopes_on(tty); } void print_scopes_on(outputStream* st) PRODUCT_RETURN; - void print_value_on(outputStream* st) const; + void print_value_on(outputStream* st) const override; void print_handler_table(); void print_nul_chk_table(); void print_recorded_oop(int log_n, int index); @@ -646,7 +929,7 @@ class nmethod : public CompiledMethod { void print_nmethod(bool print_code); // need to re-define this from CodeBlob else the overload hides it - virtual void print_on(outputStream* st) const { CodeBlob::print_on(st); } + void print_on(outputStream* st) const override { CodeBlob::print_on(st); } void print_on(outputStream* st, const char* msg) const; // Logging @@ -655,7 +938,7 @@ class nmethod : public CompiledMethod { void log_state_change() const; // Prints block-level comments, including nmethod specific block labels: - virtual void print_block_comment(outputStream* stream, address block_begin) const { + void print_block_comment(outputStream* stream, address block_begin) const override { #if defined(SUPPORT_ASSEMBLY) || defined(SUPPORT_ABSTRACT_ASSEMBLY) print_nmethod_labels(stream, block_begin); CodeBlob::print_block_comment(stream, block_begin); @@ -670,13 +953,6 @@ class nmethod : public CompiledMethod { // Prints a comment for one native instruction (reloc info, pc desc) void print_code_comment_on(outputStream* st, int column, address begin, address end); - // Compiler task identification. Note that all OSR methods - // are numbered in an independent sequence if CICountOSR is true, - // and native method wrappers are also numbered independently if - // CICountNative is true. - virtual int compile_id() const { return _compile_id; } - const char* compile_kind() const; - // tells if this compiled method is dependent on the given changes, // and the changes have invalidated it bool check_dependency_on(DepChange& changes); @@ -684,7 +960,7 @@ class nmethod : public CompiledMethod { // Fast breakpoint support. Tells if this compiled method is // dependent on the given method. Returns true if this nmethod // corresponds to the given method as well. - virtual bool is_dependent_on_method(Method* dependee); + bool is_dependent_on_method(Method* dependee); // JVMTI's GetLocalInstance() support ByteSize native_receiver_sp_offset() { @@ -699,11 +975,11 @@ class nmethod : public CompiledMethod { static ByteSize osr_entry_point_offset() { return byte_offset_of(nmethod, _osr_entry_point); } static ByteSize state_offset() { return byte_offset_of(nmethod, _state); } - virtual void metadata_do(MetadataClosure* f); + void metadata_do(MetadataClosure* f); address call_instruction_address(address pc) const; - virtual void make_deoptimized(); + void make_deoptimized(); void finalize_relocations(); }; diff --git a/src/hotspot/share/code/compiledMethod.inline.hpp b/src/hotspot/share/code/nmethod.inline.hpp similarity index 67% rename from src/hotspot/share/code/compiledMethod.inline.hpp rename to src/hotspot/share/code/nmethod.inline.hpp index a5f768fc973..4af4d3ffaed 100644 --- a/src/hotspot/share/code/compiledMethod.inline.hpp +++ b/src/hotspot/share/code/nmethod.inline.hpp @@ -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 @@ -22,19 +22,19 @@ * */ -#ifndef SHARE_CODE_COMPILEDMETHOD_INLINE_HPP -#define SHARE_CODE_COMPILEDMETHOD_INLINE_HPP +#ifndef SHARE_CODE_NMETHOD_INLINE_HPP +#define SHARE_CODE_NMETHOD_INLINE_HPP -#include "code/compiledMethod.hpp" +#include "code/nmethod.hpp" #include "code/nativeInst.hpp" #include "runtime/atomic.hpp" #include "runtime/frame.hpp" -inline bool CompiledMethod::is_deopt_pc(address pc) { return is_deopt_entry(pc) || is_deopt_mh_entry(pc); } +inline bool nmethod::is_deopt_pc(address pc) { return is_deopt_entry(pc) || is_deopt_mh_entry(pc); } // When using JVMCI the address might be off by the size of a call instruction. -inline bool CompiledMethod::is_deopt_entry(address pc) { +inline bool nmethod::is_deopt_entry(address pc) { return pc == deopt_handler_begin() #if INCLUDE_JVMCI || (is_compiled_by_jvmci() && pc == (deopt_handler_begin() + NativeCall::instruction_size)) @@ -42,7 +42,7 @@ inline bool CompiledMethod::is_deopt_entry(address pc) { ; } -inline bool CompiledMethod::is_deopt_mh_entry(address pc) { +inline bool nmethod::is_deopt_mh_entry(address pc) { return pc == deopt_mh_handler_begin() #if INCLUDE_JVMCI || (is_compiled_by_jvmci() && pc == (deopt_mh_handler_begin() + NativeCall::instruction_size)) @@ -50,24 +50,6 @@ inline bool CompiledMethod::is_deopt_mh_entry(address pc) { ; } -// ----------------------------------------------------------------------------- -// CompiledMethod::get_deopt_original_pc -// -// Return the original PC for the given PC if: -// (a) the given PC belongs to a nmethod and -// (b) it is a deopt PC - -inline address CompiledMethod::get_deopt_original_pc(const frame* fr) { - if (fr->cb() == nullptr) return nullptr; - - CompiledMethod* cm = fr->cb()->as_compiled_method_or_null(); - if (cm != nullptr && cm->is_deopt_pc(fr->pc())) - return cm->get_original_pc(fr); - - return nullptr; -} - - // class ExceptionCache methods inline int ExceptionCache::count() { return Atomic::load_acquire(&_count); } @@ -86,4 +68,4 @@ address ExceptionCache::handler_at(int index) { inline void ExceptionCache::increment_count() { Atomic::release_store(&_count, _count + 1); } -#endif // SHARE_CODE_COMPILEDMETHOD_INLINE_HPP +#endif // SHARE_CODE_NMETHOD_INLINE_HPP diff --git a/src/hotspot/share/code/pcDesc.cpp b/src/hotspot/share/code/pcDesc.cpp index c6ee8c69521..241eee03a9c 100644 --- a/src/hotspot/share/code/pcDesc.cpp +++ b/src/hotspot/share/code/pcDesc.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 @@ -36,11 +36,11 @@ PcDesc::PcDesc(int pc_offset, int scope_decode_offset, int obj_decode_offset) { _flags = 0; } -address PcDesc::real_pc(const CompiledMethod* code) const { +address PcDesc::real_pc(const nmethod* code) const { return code->code_begin() + pc_offset(); } -void PcDesc::print_on(outputStream* st, CompiledMethod* code) { +void PcDesc::print_on(outputStream* st, nmethod* code) { #ifndef PRODUCT ResourceMark rm; st->print_cr("PcDesc(pc=" PTR_FORMAT " offset=%x bits=%x):", p2i(real_pc(code)), pc_offset(), _flags); @@ -57,7 +57,7 @@ void PcDesc::print_on(outputStream* st, CompiledMethod* code) { #endif } -bool PcDesc::verify(CompiledMethod* code) { +bool PcDesc::verify(nmethod* code) { //Unimplemented(); return true; } diff --git a/src/hotspot/share/code/pcDesc.hpp b/src/hotspot/share/code/pcDesc.hpp index 4ec1db4ff06..8048c3909c7 100644 --- a/src/hotspot/share/code/pcDesc.hpp +++ b/src/hotspot/share/code/pcDesc.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2022, 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 @@ -29,7 +29,7 @@ // PcDescs map a physical PC (given as offset from start of nmethod) to // the corresponding source scope and byte code index. -class CompiledMethod; +class nmethod; class PcDesc { friend class VMStructs; @@ -102,11 +102,11 @@ class PcDesc { void set_arg_escape(bool z) { set_flag(PCDESC_arg_escape, z); } // Returns the real pc - address real_pc(const CompiledMethod* code) const; + address real_pc(const nmethod* code) const; - void print(CompiledMethod* code) { print_on(tty, code); } - void print_on(outputStream* st, CompiledMethod* code); - bool verify(CompiledMethod* code); + void print(nmethod* code) { print_on(tty, code); } + void print_on(outputStream* st, nmethod* code); + bool verify(nmethod* code); }; #endif // SHARE_CODE_PCDESC_HPP diff --git a/src/hotspot/share/code/relocInfo.cpp b/src/hotspot/share/code/relocInfo.cpp index ef908757675..69ff4bc78d6 100644 --- a/src/hotspot/share/code/relocInfo.cpp +++ b/src/hotspot/share/code/relocInfo.cpp @@ -117,13 +117,13 @@ void relocInfo::change_reloc_info_for_address(RelocIterator *itr, address pc, re // ---------------------------------------------------------------------------------------------------- // Implementation of RelocIterator -void RelocIterator::initialize(CompiledMethod* nm, address begin, address limit) { +void RelocIterator::initialize(nmethod* nm, address begin, address limit) { initialize_misc(); if (nm == nullptr && begin != nullptr) { // allow nmethod to be deduced from beginning address CodeBlob* cb = CodeCache::find_blob(begin); - nm = (cb != nullptr) ? cb->as_compiled_method_or_null() : nullptr; + nm = (cb != nullptr) ? cb->as_nmethod_or_null() : nullptr; } guarantee(nm != nullptr, "must be able to deduce nmethod from other arguments"); @@ -633,9 +633,9 @@ address virtual_call_Relocation::cached_value() { } Method* virtual_call_Relocation::method_value() { - CompiledMethod* cm = code(); - if (cm == nullptr) return (Method*)nullptr; - Metadata* m = cm->metadata_at(_method_index); + nmethod* nm = code(); + if (nm == nullptr) return (Method*)nullptr; + Metadata* m = nm->metadata_at(_method_index); assert(m != nullptr || _method_index == 0, "should be non-null for non-zero index"); assert(m == nullptr || m->is_method(), "not a method"); return (Method*)m; @@ -659,9 +659,9 @@ void opt_virtual_call_Relocation::unpack_data() { } Method* opt_virtual_call_Relocation::method_value() { - CompiledMethod* cm = code(); - if (cm == nullptr) return (Method*)nullptr; - Metadata* m = cm->metadata_at(_method_index); + nmethod* nm = code(); + if (nm == nullptr) return (Method*)nullptr; + Metadata* m = nm->metadata_at(_method_index); assert(m != nullptr || _method_index == 0, "should be non-null for non-zero index"); assert(m == nullptr || m->is_method(), "not a method"); return (Method*)m; @@ -689,9 +689,9 @@ address opt_virtual_call_Relocation::static_stub() { } Method* static_call_Relocation::method_value() { - CompiledMethod* cm = code(); - if (cm == nullptr) return (Method*)nullptr; - Metadata* m = cm->metadata_at(_method_index); + nmethod* nm = code(); + if (nm == nullptr) return (Method*)nullptr; + Metadata* m = nm->metadata_at(_method_index); assert(m != nullptr || _method_index == 0, "should be non-null for non-zero index"); assert(m == nullptr || m->is_method(), "not a method"); return (Method*)m; diff --git a/src/hotspot/share/code/relocInfo.hpp b/src/hotspot/share/code/relocInfo.hpp index 5f67f94bdad..9f1db9f4684 100644 --- a/src/hotspot/share/code/relocInfo.hpp +++ b/src/hotspot/share/code/relocInfo.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 @@ -34,11 +34,10 @@ #include -class nmethod; class CodeBlob; -class CompiledMethod; class Metadata; class NativeMovConstReg; +class nmethod; // Types in this file: // relocInfo @@ -571,7 +570,7 @@ class RelocIterator : public StackObj { address _limit; // stop producing relocations after this _addr relocInfo* _current; // the current relocation information relocInfo* _end; // end marker; we're done iterating when _current == _end - CompiledMethod* _code; // compiled method containing _addr + nmethod* _code; // compiled method containing _addr address _addr; // instruction to which the relocation applies short _databuf; // spare buffer for compressed data short* _data; // pointer to the relocation's data @@ -601,13 +600,13 @@ class RelocIterator : public StackObj { void initialize_misc(); - void initialize(CompiledMethod* nm, address begin, address limit); + void initialize(nmethod* nm, address begin, address limit); RelocIterator() { initialize_misc(); } public: // constructor - RelocIterator(CompiledMethod* nm, address begin = nullptr, address limit = nullptr); + RelocIterator(nmethod* nm, address begin = nullptr, address limit = nullptr); RelocIterator(CodeSection* cb, address begin = nullptr, address limit = nullptr); // get next reloc info, return !eos @@ -640,7 +639,7 @@ class RelocIterator : public StackObj { relocType type() const { return current()->type(); } int format() const { return (relocInfo::have_format) ? current()->format() : 0; } address addr() const { return _addr; } - CompiledMethod* code() const { return _code; } + nmethod* code() const { return _code; } short* data() const { return _data; } int datalen() const { return _datalen; } bool has_current() const { return _datalen >= 0; } @@ -827,7 +826,7 @@ class Relocation { public: // accessors which only make sense for a bound Relocation address addr() const { return binding()->addr(); } - CompiledMethod* code() const { return binding()->code(); } + nmethod* code() const { return binding()->code(); } bool addr_in_const() const { return binding()->addr_in_const(); } protected: short* data() const { return binding()->data(); } @@ -1463,7 +1462,7 @@ APPLY_TO_RELOCATIONS(EACH_CASE); #undef EACH_CASE_AUX #undef EACH_CASE -inline RelocIterator::RelocIterator(CompiledMethod* nm, address begin, address limit) { +inline RelocIterator::RelocIterator(nmethod* nm, address begin, address limit) { initialize(nm, begin, limit); } diff --git a/src/hotspot/share/code/scopeDesc.cpp b/src/hotspot/share/code/scopeDesc.cpp index 1bcb762152a..d22d3352f4e 100644 --- a/src/hotspot/share/code/scopeDesc.cpp +++ b/src/hotspot/share/code/scopeDesc.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 @@ -32,7 +32,7 @@ #include "oops/oop.inline.hpp" #include "runtime/handles.inline.hpp" -ScopeDesc::ScopeDesc(const CompiledMethod* code, PcDesc* pd, bool ignore_objects) { +ScopeDesc::ScopeDesc(const nmethod* code, PcDesc* pd, bool ignore_objects) { int obj_decode_offset = ignore_objects ? DebugInformationRecorder::serialized_null : pd->obj_decode_offset(); _code = code; _decode_offset = pd->scope_decode_offset(); @@ -148,9 +148,9 @@ GrowableArray* ScopeDesc::objects_to_rematerialize(frame& frm, Regi if (sv->is_object_merge()) { sv = sv->as_ObjectMergeValue()->select(frm, map); - // If select() returns nullptr, then the object doesn't need to be - // rematerialized. - if (sv == nullptr) { + // 'select(...)' may return an ObjectValue that actually represents a + // non-scalar replaced object participating in a merge. + if (!sv->is_scalar_replaced()) { continue; } } diff --git a/src/hotspot/share/code/scopeDesc.hpp b/src/hotspot/share/code/scopeDesc.hpp index be3ba352070..8e8a876095e 100644 --- a/src/hotspot/share/code/scopeDesc.hpp +++ b/src/hotspot/share/code/scopeDesc.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 @@ -41,7 +41,7 @@ class SimpleScopeDesc : public StackObj { int _bci; public: - SimpleScopeDesc(CompiledMethod* code, address pc) { + SimpleScopeDesc(nmethod* code, address pc) { PcDesc* pc_desc = code->pc_desc_at(pc); assert(pc_desc != nullptr, "Must be able to find matching PcDesc"); // save this here so we only have to look up the PcDesc once @@ -61,7 +61,7 @@ class SimpleScopeDesc : public StackObj { class ScopeDesc : public ResourceObj { public: // Constructor - ScopeDesc(const CompiledMethod* code, PcDesc* pd, bool ignore_objects = false); + ScopeDesc(const nmethod* code, PcDesc* pd, bool ignore_objects = false); // Direct access to scope ScopeDesc* at_offset(int decode_offset) { return new ScopeDesc(this, decode_offset); } @@ -120,7 +120,7 @@ class ScopeDesc : public ResourceObj { GrowableArray* _objects; // Nmethod information - const CompiledMethod* _code; + const nmethod* _code; // Decoding operations void decode_body(); diff --git a/src/hotspot/share/compiler/compilationPolicy.cpp b/src/hotspot/share/compiler/compilationPolicy.cpp index 57173ed621c..4fcd9b5bde4 100644 --- a/src/hotspot/share/compiler/compilationPolicy.cpp +++ b/src/hotspot/share/compiler/compilationPolicy.cpp @@ -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 @@ -212,7 +212,7 @@ bool CompilationPolicy::force_comp_at_level_simple(const methodHandle& method) { } CompLevel CompilationPolicy::comp_level(Method* method) { - CompiledMethod *nm = method->code(); + nmethod *nm = method->code(); if (nm != nullptr && nm->is_in_use()) { return (CompLevel)nm->comp_level(); } @@ -708,7 +708,7 @@ void CompilationPolicy::reprofile(ScopeDesc* trap_scope, bool is_osr) { } nmethod* CompilationPolicy::event(const methodHandle& method, const methodHandle& inlinee, - int branch_bci, int bci, CompLevel comp_level, CompiledMethod* nm, TRAPS) { + int branch_bci, int bci, CompLevel comp_level, nmethod* nm, TRAPS) { if (PrintTieredEvents) { print_event(bci == InvocationEntryBci ? CALL : LOOP, method(), inlinee(), bci, comp_level); } @@ -1137,7 +1137,7 @@ CompLevel CompilationPolicy::loop_event(const methodHandle& method, CompLevel cu // Handle the invocation event. void CompilationPolicy::method_invocation_event(const methodHandle& mh, const methodHandle& imh, - CompLevel level, CompiledMethod* nm, TRAPS) { + CompLevel level, nmethod* nm, TRAPS) { if (should_create_mdo(mh, level)) { create_mdo(mh, THREAD); } @@ -1152,7 +1152,7 @@ void CompilationPolicy::method_invocation_event(const methodHandle& mh, const me // Handle the back branch event. Notice that we can compile the method // with a regular entry from here. void CompilationPolicy::method_back_branch_event(const methodHandle& mh, const methodHandle& imh, - int bci, CompLevel level, CompiledMethod* nm, TRAPS) { + int bci, CompLevel level, nmethod* nm, TRAPS) { if (should_create_mdo(mh, level)) { create_mdo(mh, THREAD); } diff --git a/src/hotspot/share/compiler/compilationPolicy.hpp b/src/hotspot/share/compiler/compilationPolicy.hpp index f7f7f593c26..3ec60cd89c7 100644 --- a/src/hotspot/share/compiler/compilationPolicy.hpp +++ b/src/hotspot/share/compiler/compilationPolicy.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 @@ -235,9 +235,9 @@ class CompilationPolicy : AllStatic { // Get a compilation level for a given method. static CompLevel comp_level(Method* method); static void method_invocation_event(const methodHandle& method, const methodHandle& inlinee, - CompLevel level, CompiledMethod* nm, TRAPS); + CompLevel level, nmethod* nm, TRAPS); static void method_back_branch_event(const methodHandle& method, const methodHandle& inlinee, - int bci, CompLevel level, CompiledMethod* nm, TRAPS); + int bci, CompLevel level, nmethod* nm, TRAPS); static void set_increase_threshold_at_ratio() { _increase_threshold_at_ratio = 100 / (100 - (double)IncreaseFirstTierCompileThresholdAt); } static void set_start_time(jlong t) { _start_time = t; } @@ -265,7 +265,7 @@ class CompilationPolicy : AllStatic { // Return initial compile level to use with Xcomp (depends on compilation mode). static void reprofile(ScopeDesc* trap_scope, bool is_osr); static nmethod* event(const methodHandle& method, const methodHandle& inlinee, - int branch_bci, int bci, CompLevel comp_level, CompiledMethod* nm, TRAPS); + int branch_bci, int bci, CompLevel comp_level, nmethod* nm, TRAPS); // Select task is called by CompileBroker. We should return a task or nullptr. static CompileTask* select_task(CompileQueue* compile_queue); // Tell the runtime if we think a given method is adequately profiled. diff --git a/src/hotspot/share/compiler/compileBroker.cpp b/src/hotspot/share/compiler/compileBroker.cpp index 7adb4dfc587..a41718d5831 100644 --- a/src/hotspot/share/compiler/compileBroker.cpp +++ b/src/hotspot/share/compiler/compileBroker.cpp @@ -1376,11 +1376,10 @@ nmethod* CompileBroker::compile_method(const methodHandle& method, int osr_bci, if (osr_bci == InvocationEntryBci) { // standard compilation - CompiledMethod* method_code = method->code(); - if (method_code != nullptr && method_code->is_nmethod() - && (compile_reason != CompileTask::Reason_DirectivesChanged)) { + nmethod* method_code = method->code(); + if (method_code != nullptr && (compile_reason != CompileTask::Reason_DirectivesChanged)) { if (compilation_is_complete(method, osr_bci, comp_level)) { - return (nmethod*) method_code; + return method_code; } } if (method->is_not_compilable(comp_level)) { @@ -1481,12 +1480,7 @@ nmethod* CompileBroker::compile_method(const methodHandle& method, int osr_bci, // return requested nmethod // We accept a higher level osr method if (osr_bci == InvocationEntryBci) { - CompiledMethod* code = method->code(); - if (code == nullptr) { - return (nmethod*) code; - } else { - return code->as_nmethod_or_null(); - } + return method->code(); } return method->lookup_osr_nmethod_for(osr_bci, comp_level, false); } @@ -1511,7 +1505,7 @@ bool CompileBroker::compilation_is_complete(const methodHandle& method, if (method->is_not_compilable(comp_level)) { return true; } else { - CompiledMethod* result = method->code(); + nmethod* result = method->code(); if (result == nullptr) return false; return comp_level == result->comp_level(); } diff --git a/src/hotspot/share/compiler/oopMap.cpp b/src/hotspot/share/compiler/oopMap.cpp index 6ab8970a795..09b9feee3db 100644 --- a/src/hotspot/share/compiler/oopMap.cpp +++ b/src/hotspot/share/compiler/oopMap.cpp @@ -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 @@ -498,7 +498,6 @@ static void update_register_map1(const ImmutableOopMap* oopmap, const frame* fr, VMReg reg = omv.content_reg(); address loc = fr->oopmapreg_to_location(omv.reg(), reg_map); reg_map->set_location(reg, loc); - //DEBUG_ONLY(nof_callee++;) } } } @@ -520,15 +519,7 @@ void ImmutableOopMap::update_register_map(const frame *fr, RegisterMap *reg_map) // Scan through oopmap and find location of all callee-saved registers // (we do not do update in place, since info could be overwritten) - DEBUG_ONLY(int nof_callee = 0;) update_register_map1(this, fr, reg_map); - - // Check that runtime stubs save all callee-saved registers -#ifdef COMPILER2 - assert(cb == nullptr || cb->is_compiled_by_c1() || cb->is_compiled_by_jvmci() || !cb->is_runtime_stub() || - (nof_callee >= SAVED_ON_ENTRY_REG_COUNT || nof_callee >= C_SAVED_ON_ENTRY_REG_COUNT), - "must save all"); -#endif // COMPILER2 } const ImmutableOopMap* OopMapSet::find_map(const frame *fr) { diff --git a/src/hotspot/share/gc/g1/g1BlockOffsetTable.cpp b/src/hotspot/share/gc/g1/g1BlockOffsetTable.cpp index 4847ef50d21..18ab40174d6 100644 --- a/src/hotspot/share/gc/g1/g1BlockOffsetTable.cpp +++ b/src/hotspot/share/gc/g1/g1BlockOffsetTable.cpp @@ -31,10 +31,6 @@ #include "oops/oop.inline.hpp" #include "runtime/java.hpp" -////////////////////////////////////////////////////////////////////// -// G1BlockOffsetTable -////////////////////////////////////////////////////////////////////// - G1BlockOffsetTable::G1BlockOffsetTable(MemRegion heap, G1RegionToSpaceMapper* storage) : _reserved(heap), _offset_base(nullptr) { @@ -62,14 +58,6 @@ void G1BlockOffsetTable::check_address(uint8_t* addr, const char* msg) const { } #endif // ASSERT -////////////////////////////////////////////////////////////////////// -// G1BlockOffsetTablePart -////////////////////////////////////////////////////////////////////// - -G1BlockOffsetTablePart::G1BlockOffsetTablePart(G1BlockOffsetTable* array, HeapRegion* hr) : - _bot(array), - _hr(hr) {} - // Write the backskip value for each region. // // offset @@ -102,10 +90,9 @@ G1BlockOffsetTablePart::G1BlockOffsetTablePart(G1BlockOffsetTable* array, HeapRe // Move back N (e.g., 8) entries and repeat with the // value of the new entry // -void G1BlockOffsetTablePart::set_remainder_to_point_to_start_incl(uint8_t* start_card, uint8_t* end_card) { +void G1BlockOffsetTable::set_remainder_to_point_to_start_incl(uint8_t* start_card, uint8_t* end_card) { assert(start_card <= end_card, "precondition"); - assert(start_card > _bot->entry_for_addr(_hr->bottom()), "Cannot be first card"); - assert(_bot->offset_array(start_card-1) < CardTable::card_size_in_words(), + assert(offset_array(start_card-1) < CardTable::card_size_in_words(), "Offset card has an unexpected value"); uint8_t* start_card_for_region = start_card; uint8_t offset = UINT8_MAX; @@ -116,11 +103,11 @@ void G1BlockOffsetTablePart::set_remainder_to_point_to_start_incl(uint8_t* start uint8_t* reach = start_card - 1 + (BOTConstants::power_to_cards_back(i+1) - 1); offset = CardTable::card_size_in_words() + i; if (reach >= end_card) { - _bot->set_offset_array(start_card_for_region, end_card, offset); + set_offset_array(start_card_for_region, end_card, offset); start_card_for_region = reach + 1; break; } - _bot->set_offset_array(start_card_for_region, reach, offset); + set_offset_array(start_card_for_region, reach, offset); start_card_for_region = reach + 1; } assert(start_card_for_region > end_card, "Sanity check"); @@ -131,36 +118,36 @@ void G1BlockOffsetTablePart::set_remainder_to_point_to_start_incl(uint8_t* start // The card-interval [start_card, end_card] is a closed interval; this // is an expensive check -- use with care and only under protection of // suitable flag. -void G1BlockOffsetTablePart::check_all_cards(uint8_t* start_card, uint8_t* end_card) const { +void G1BlockOffsetTable::check_all_cards(uint8_t* start_card, uint8_t* end_card) const { if (end_card < start_card) { return; } - guarantee(_bot->offset_array(start_card) == CardTable::card_size_in_words(), "Wrong value in second card"); + guarantee(offset_array(start_card) == CardTable::card_size_in_words(), "Wrong value in second card"); for (uint8_t* c = start_card + 1; c <= end_card; c++ /* yeah! */) { - uint8_t entry = _bot->offset_array(c); + uint8_t entry = offset_array(c); if ((unsigned)(c - start_card) > BOTConstants::power_to_cards_back(1)) { guarantee(entry > CardTable::card_size_in_words(), "Should be in logarithmic region - " "entry: %u, " "_array->offset_array(c): %u, " "N_words: %u", - (uint)entry, (uint)_bot->offset_array(c), CardTable::card_size_in_words()); + (uint)entry, (uint)offset_array(c), CardTable::card_size_in_words()); } size_t backskip = BOTConstants::entry_to_cards_back(entry); uint8_t* landing_card = c - backskip; guarantee(landing_card >= (start_card - 1), "Inv"); if (landing_card >= start_card) { - guarantee(_bot->offset_array(landing_card) <= entry, + guarantee(offset_array(landing_card) <= entry, "Monotonicity - landing_card offset: %u, " "entry: %u", - (uint)_bot->offset_array(landing_card), (uint)entry); + (uint)offset_array(landing_card), (uint)entry); } else { guarantee(landing_card == start_card - 1, "Tautology"); // Note that N_words is the maximum offset value - guarantee(_bot->offset_array(landing_card) < CardTable::card_size_in_words(), + guarantee(offset_array(landing_card) < CardTable::card_size_in_words(), "landing card offset: %u, " "N_words: %u", - (uint)_bot->offset_array(landing_card), (uint)CardTable::card_size_in_words()); + (uint)offset_array(landing_card), (uint)CardTable::card_size_in_words()); } } } @@ -176,10 +163,9 @@ void G1BlockOffsetTablePart::check_all_cards(uint8_t* start_card, uint8_t* end_c // ( ^ ] // blk_start // -void G1BlockOffsetTablePart::update_for_block_work(HeapWord* blk_start, - HeapWord* blk_end) { +void G1BlockOffsetTable::update_for_block_work(HeapWord* blk_start, HeapWord* blk_end) { HeapWord* const cur_card_boundary = align_up_by_card_size(blk_start); - uint8_t* const offset_card = _bot->entry_for_addr(cur_card_boundary); + uint8_t* const offset_card = entry_for_addr(cur_card_boundary); assert(blk_start != nullptr && blk_end > blk_start, "phantom block"); @@ -191,16 +177,16 @@ void G1BlockOffsetTablePart::update_for_block_work(HeapWord* blk_start, "reference must be into the heap"); assert(G1CollectedHeap::heap()->is_in_reserved(blk_end - 1), "limit must be within the heap"); - assert(cur_card_boundary == _bot->addr_for_entry(offset_card), + assert(cur_card_boundary == addr_for_entry(offset_card), "Block offset table entry must agree with cur_card_boundary"); // Mark the card that holds the offset into the block. - _bot->set_offset_array(offset_card, cur_card_boundary, blk_start); + set_offset_array(offset_card, cur_card_boundary, blk_start); // We need to now mark the subsequent cards that this block spans. // Index of card on which the block ends. - uint8_t* end_card = _bot->entry_for_addr(blk_end - 1); + uint8_t* end_card = entry_for_addr(blk_end - 1); // Are there more cards left to be updated? if (offset_card + 1 <= end_card) { @@ -210,54 +196,53 @@ void G1BlockOffsetTablePart::update_for_block_work(HeapWord* blk_start, #ifdef ASSERT // Calculate new_card_boundary this way because end_index // may be the last valid index in the covered region. - HeapWord* new_card_boundary = _bot->addr_for_entry(end_card) + CardTable::card_size_in_words(); + HeapWord* new_card_boundary = addr_for_entry(end_card) + CardTable::card_size_in_words(); assert(new_card_boundary >= blk_end, "postcondition"); // The offset can be 0 if the block starts on a boundary. That // is checked by an assertion above. - uint8_t* previous_card = _bot->entry_for_addr(blk_start); - HeapWord* boundary = _bot->addr_for_entry(previous_card); - assert((_bot->offset_array(offset_card) == 0 && blk_start == boundary) || - (_bot->offset_array(offset_card) > 0 && _bot->offset_array(offset_card) < CardTable::card_size_in_words()), + uint8_t* previous_card = entry_for_addr(blk_start); + HeapWord* boundary = addr_for_entry(previous_card); + assert((offset_array(offset_card) == 0 && blk_start == boundary) || + (offset_array(offset_card) > 0 && offset_array(offset_card) < CardTable::card_size_in_words()), "offset array should have been set - " "index offset: %u, " "blk_start: " PTR_FORMAT ", " "boundary: " PTR_FORMAT, - (uint)_bot->offset_array(offset_card), + (uint)offset_array(offset_card), p2i(blk_start), p2i(boundary)); for (uint8_t* j = offset_card + 1; j <= end_card; j++) { - assert(_bot->offset_array(j) > 0 && - _bot->offset_array(j) <= - (uint8_t) (CardTable::card_size_in_words() + BOTConstants::N_powers - 1), + assert(offset_array(j) > 0 && + offset_array(j) <= (uint8_t) (CardTable::card_size_in_words() + BOTConstants::N_powers - 1), "offset array should have been set - " "%u not > 0 OR %u not <= %u", - (uint) _bot->offset_array(j), - (uint) _bot->offset_array(j), + (uint) offset_array(j), + (uint) offset_array(j), (uint) (CardTable::card_size_in_words() + BOTConstants::N_powers - 1)); } #endif } -void G1BlockOffsetTablePart::verify() const { - assert(_hr->bottom() < _hr->top(), "Only non-empty regions should be verified."); - uint8_t* start_card = _bot->entry_for_addr(_hr->bottom()); - uint8_t* end_card = _bot->entry_for_addr(_hr->top() - 1); +void G1BlockOffsetTable::verify(const HeapRegion* hr) const { + assert(hr->bottom() < hr->top(), "Only non-empty regions should be verified."); + uint8_t* start_card = entry_for_addr(hr->bottom()); + uint8_t* end_card = entry_for_addr(hr->top() - 1); for (uint8_t* current_card = start_card; current_card < end_card; current_card++) { - uint8_t entry = _bot->offset_array(current_card); + uint8_t entry = offset_array(current_card); if (entry < CardTable::card_size_in_words()) { // The entry should point to an object before the current card. Verify that // it is possible to walk from that object in to the current card by just // iterating over the objects following it. - HeapWord* card_address = _bot->addr_for_entry(current_card); + HeapWord* card_address = addr_for_entry(current_card); HeapWord* obj_end = card_address - entry; while (obj_end < card_address) { HeapWord* obj = obj_end; - size_t obj_size = _hr->block_size(obj); + size_t obj_size = hr->block_size(obj); obj_end = obj + obj_size; - guarantee(obj_end > obj && obj_end <= _hr->top(), + guarantee(obj_end > obj && obj_end <= hr->top(), "Invalid object end. obj: " PTR_FORMAT " obj_size: " SIZE_FORMAT " obj_end: " PTR_FORMAT " top: " PTR_FORMAT, - p2i(obj), obj_size, p2i(obj_end), p2i(_hr->top())); + p2i(obj), obj_size, p2i(obj_end), p2i(hr->top())); } } else { // Because we refine the BOT based on which cards are dirty there is not much we can verify here. @@ -271,32 +256,10 @@ void G1BlockOffsetTablePart::verify() const { "Going backwards beyond the start_card. start_card: " SIZE_FORMAT " current_card: " SIZE_FORMAT " backskip: " SIZE_FORMAT, p2i(start_card), p2i(current_card), backskip); - HeapWord* backskip_address = _bot->addr_for_entry(current_card - backskip); - guarantee(backskip_address >= _hr->bottom(), + HeapWord* backskip_address = addr_for_entry(current_card - backskip); + guarantee(backskip_address >= hr->bottom(), "Going backwards beyond bottom of the region: bottom: " PTR_FORMAT ", backskip_address: " PTR_FORMAT, - p2i(_hr->bottom()), p2i(backskip_address)); + p2i(hr->bottom()), p2i(backskip_address)); } } } - -#ifndef PRODUCT -void G1BlockOffsetTablePart::print_on(outputStream* out) { - uint8_t* from_card = _bot->entry_for_addr(_hr->bottom()); - uint8_t* to_card = _bot->entry_for_addr(_hr->end()); - out->print_cr(">> BOT for area [" PTR_FORMAT "," PTR_FORMAT ") " - "cards [" SIZE_FORMAT "," SIZE_FORMAT ")", - p2i(_hr->bottom()), p2i(_hr->end()), p2i(from_card), p2i(to_card)); - for (uint8_t* i = from_card; i < to_card; ++i) { - out->print_cr(" entry " SIZE_FORMAT_W(8) " | " PTR_FORMAT " : %3u", - p2i(i), p2i(_bot->addr_for_entry(i)), - (uint) _bot->offset_array(i)); - } -} -#endif // !PRODUCT - -void G1BlockOffsetTablePart::set_for_starts_humongous(HeapWord* obj_top, size_t fill_size) { - update_for_block(_hr->bottom(), obj_top); - if (fill_size > 0) { - update_for_block(obj_top, fill_size); - } -} diff --git a/src/hotspot/share/gc/g1/g1BlockOffsetTable.hpp b/src/hotspot/share/gc/g1/g1BlockOffsetTable.hpp index b8c5cd489a4..4eff09f243e 100644 --- a/src/hotspot/share/gc/g1/g1BlockOffsetTable.hpp +++ b/src/hotspot/share/gc/g1/g1BlockOffsetTable.hpp @@ -33,18 +33,13 @@ #include "utilities/globalDefinitions.hpp" // Forward declarations -class G1BlockOffsetTable; class HeapRegion; // This implementation of "G1BlockOffsetTable" divides the covered region // into "N"-word subregions (where "N" = 2^"LogN". An array with an entry // for each such subregion indicates how far back one must go to find the // start of the chunk that includes the first word of the subregion. -// -// Each G1BlockOffsetTablePart is owned by a HeapRegion. - class G1BlockOffsetTable: public CHeapObj { - friend class G1BlockOffsetTablePart; friend class VMStructs; private: @@ -73,6 +68,19 @@ class G1BlockOffsetTable: public CHeapObj { void check_address(uint8_t* addr, const char* msg) const NOT_DEBUG_RETURN; + // Sets the entries corresponding to the cards starting at "start" and ending + // at "end" to point back to the card before "start"; [start, end] + void set_remainder_to_point_to_start_incl(uint8_t* start, uint8_t* end); + + // Update BOT entries corresponding to the mem range [blk_start, blk_end). + void update_for_block_work(HeapWord* blk_start, HeapWord* blk_end); + + void check_all_cards(uint8_t* left_card, uint8_t* right_card) const NOT_DEBUG_RETURN; + + static HeapWord* align_up_by_card_size(HeapWord* const addr) { + return align_up(addr, CardTable::card_size()); + } + public: // Return the number of slots needed for an offset array @@ -96,35 +104,7 @@ class G1BlockOffsetTable: public CHeapObj { // Mapping from object start array entry to address of first word HeapWord* addr_for_entry(const uint8_t* const p) const; -}; - -class G1BlockOffsetTablePart { - friend class G1BlockOffsetTable; - friend class VMStructs; -private: - // This is the global BlockOffsetTable. - G1BlockOffsetTable* _bot; - - // The region that owns this part of the BOT. - HeapRegion* _hr; - // Sets the entries corresponding to the cards starting at "start" and ending - // at "end" to point back to the card before "start"; [start, end] - void set_remainder_to_point_to_start_incl(uint8_t* start, uint8_t* end); - - // Update BOT entries corresponding to the mem range [blk_start, blk_end). - void update_for_block_work(HeapWord* blk_start, HeapWord* blk_end); - - void check_all_cards(uint8_t* left_card, uint8_t* right_card) const NOT_DEBUG_RETURN; - - static HeapWord* align_up_by_card_size(HeapWord* const addr) { - return align_up(addr, CardTable::card_size()); - } - - void update_for_block(HeapWord* blk_start, size_t size) { - update_for_block(blk_start, blk_start + size); - } -public: static bool is_crossing_card_boundary(HeapWord* const obj_start, HeapWord* const obj_end) { HeapWord* cur_card_boundary = align_up_by_card_size(obj_start); @@ -132,10 +112,7 @@ class G1BlockOffsetTablePart { return obj_end > cur_card_boundary; } - // The elements of the array are initialized to zero. - G1BlockOffsetTablePart(G1BlockOffsetTable* array, HeapRegion* hr); - - void verify() const; + void verify(const HeapRegion* hr) const; // Returns the address of the start of the block reaching into the card containing // "addr". @@ -146,10 +123,6 @@ class G1BlockOffsetTablePart { update_for_block_work(blk_start, blk_end); } } - - void set_for_starts_humongous(HeapWord* obj_top, size_t fill_size); - - void print_on(outputStream* out) PRODUCT_RETURN; }; #endif // SHARE_GC_G1_G1BLOCKOFFSETTABLE_HPP diff --git a/src/hotspot/share/gc/g1/g1BlockOffsetTable.inline.hpp b/src/hotspot/share/gc/g1/g1BlockOffsetTable.inline.hpp index 4737d5b7f93..ba2348e38b2 100644 --- a/src/hotspot/share/gc/g1/g1BlockOffsetTable.inline.hpp +++ b/src/hotspot/share/gc/g1/g1BlockOffsetTable.inline.hpp @@ -32,29 +32,20 @@ #include "runtime/atomic.hpp" #include "oops/oop.inline.hpp" -inline HeapWord* G1BlockOffsetTablePart::block_start_reaching_into_card(const void* addr) const { - assert(addr >= _hr->bottom() && addr < _hr->top(), "invalid address"); +inline HeapWord* G1BlockOffsetTable::block_start_reaching_into_card(const void* addr) const { + assert(_reserved.contains(addr), "invalid address"); -#ifdef ASSERT - if (!_hr->is_continues_humongous()) { - // For non-ContinuesHumongous regions, the first obj always starts from bottom. - uint8_t offset = _bot->offset_array(_bot->entry_for_addr(_hr->bottom())); - assert(offset == 0, "Found offset %u instead of 0 for region %u %s", - offset, _hr->hrm_index(), _hr->get_short_type_str()); - } -#endif - - uint8_t* entry = _bot->entry_for_addr(addr); - uint8_t offset = _bot->offset_array(entry); + uint8_t* entry = entry_for_addr(addr); + uint8_t offset = offset_array(entry); while (offset >= CardTable::card_size_in_words()) { // The excess of the offset from N_words indicates a power of Base // to go back by. size_t n_cards_back = BOTConstants::entry_to_cards_back(offset); entry -= n_cards_back; - offset = _bot->offset_array(entry); + offset = offset_array(entry); } assert(offset < CardTable::card_size_in_words(), "offset too large"); - HeapWord* q = _bot->addr_for_entry(entry); + HeapWord* q = addr_for_entry(entry); return q - offset; } diff --git a/src/hotspot/share/gc/g1/g1CodeRootSet.cpp b/src/hotspot/share/gc/g1/g1CodeRootSet.cpp index 135c1bca2e3..4b933d9a85f 100644 --- a/src/hotspot/share/gc/g1/g1CodeRootSet.cpp +++ b/src/hotspot/share/gc/g1/g1CodeRootSet.cpp @@ -152,7 +152,7 @@ class G1CodeRootSetHashTable : public CHeapObj { clean(always_true); } - void iterate_at_safepoint(CodeBlobClosure* blk) { + void iterate_at_safepoint(NMethodClosure* blk) { assert_at_safepoint(); // A lot of code root sets are typically empty. if (is_empty()) { @@ -161,7 +161,7 @@ class G1CodeRootSetHashTable : public CHeapObj { auto do_value = [&] (nmethod** value) { - blk->do_code_blob(*value); + blk->do_nmethod(*value); return true; }; _table_scanner.do_safepoint_scan(do_value); @@ -288,7 +288,7 @@ void G1CodeRootSet::reset_table_scanner() { _table->reset_table_scanner(); } -void G1CodeRootSet::nmethods_do(CodeBlobClosure* blk) const { +void G1CodeRootSet::nmethods_do(NMethodClosure* blk) const { DEBUG_ONLY(_is_iterating = true;) _table->iterate_at_safepoint(blk); DEBUG_ONLY(_is_iterating = false;) @@ -317,14 +317,14 @@ class CleanCallback : public StackObj { }; PointsIntoHRDetectionClosure _detector; - CodeBlobToOopClosure _blobs; + NMethodToOopClosure _nmethod_cl; public: - CleanCallback(HeapRegion* hr) : _detector(hr), _blobs(&_detector, !CodeBlobToOopClosure::FixRelocations) {} + CleanCallback(HeapRegion* hr) : _detector(hr), _nmethod_cl(&_detector, !NMethodToOopClosure::FixRelocations) {} bool operator()(nmethod** value) { _detector._points_into = false; - _blobs.do_code_blob(*value); + _nmethod_cl.do_nmethod(*value); return !_detector._points_into; } }; diff --git a/src/hotspot/share/gc/g1/g1CodeRootSet.hpp b/src/hotspot/share/gc/g1/g1CodeRootSet.hpp index 9c5ccdd1202..a4c425109b2 100644 --- a/src/hotspot/share/gc/g1/g1CodeRootSet.hpp +++ b/src/hotspot/share/gc/g1/g1CodeRootSet.hpp @@ -50,7 +50,7 @@ class G1CodeRootSet { // Prepare for MT iteration. Must be called before nmethods_do. void reset_table_scanner(); - void nmethods_do(CodeBlobClosure* blk) const; + void nmethods_do(NMethodClosure* blk) const; // Remove all nmethods which no longer contain pointers into our "owner" region. void clean(HeapRegion* owner); diff --git a/src/hotspot/share/gc/g1/g1CollectedHeap.cpp b/src/hotspot/share/gc/g1/g1CollectedHeap.cpp index 280aafef069..1384c30d2be 100644 --- a/src/hotspot/share/gc/g1/g1CollectedHeap.cpp +++ b/src/hotspot/share/gc/g1/g1CollectedHeap.cpp @@ -532,7 +532,7 @@ HeapWord* G1CollectedHeap::alloc_archive_region(size_t word_size, HeapWord* pref return start_addr; } -void G1CollectedHeap::populate_archive_regions_bot_part(MemRegion range) { +void G1CollectedHeap::populate_archive_regions_bot(MemRegion range) { assert(!is_init_completed(), "Expect to be called at JVM init time"); iterate_regions_in_range(range, @@ -2518,7 +2518,7 @@ void G1CollectedHeap::unload_classes_and_code(const char* description, BoolObjec ClassUnloadingContext ctx(workers()->active_workers(), false /* unregister_nmethods_during_purge */, - false /* lock_codeblob_free_separately */); + false /* lock_nmethod_free_separately */); { CodeCache::UnlinkingScope scope(is_alive); bool unloading_occurred = SystemDictionary::do_unloading(timer); @@ -2535,7 +2535,7 @@ void G1CollectedHeap::unload_classes_and_code(const char* description, BoolObjec } { GCTraceTime(Debug, gc, phases) t("Free Code Blobs", timer); - ctx.free_code_blobs(); + ctx.free_nmethods(); } { GCTraceTime(Debug, gc, phases) t("Purge Class Loader Data", timer); @@ -3016,24 +3016,22 @@ void G1CollectedHeap::update_used_after_gc(bool evacuation_failed) { } } -class RebuildCodeRootClosure: public CodeBlobClosure { +class RebuildCodeRootClosure: public NMethodClosure { G1CollectedHeap* _g1h; public: RebuildCodeRootClosure(G1CollectedHeap* g1h) : _g1h(g1h) {} - void do_code_blob(CodeBlob* cb) { - nmethod* nm = cb->as_nmethod_or_null(); - if (nm != nullptr) { - _g1h->register_nmethod(nm); - } + void do_nmethod(nmethod* nm) { + assert(nm != nullptr, "Sanity"); + _g1h->register_nmethod(nm); } }; void G1CollectedHeap::rebuild_code_roots() { - RebuildCodeRootClosure blob_cl(this); - CodeCache::blobs_do(&blob_cl); + RebuildCodeRootClosure nmethod_cl(this); + CodeCache::nmethods_do(&nmethod_cl); } void G1CollectedHeap::initialize_serviceability() { diff --git a/src/hotspot/share/gc/g1/g1CollectedHeap.hpp b/src/hotspot/share/gc/g1/g1CollectedHeap.hpp index b4157f16493..3ee77786621 100644 --- a/src/hotspot/share/gc/g1/g1CollectedHeap.hpp +++ b/src/hotspot/share/gc/g1/g1CollectedHeap.hpp @@ -717,9 +717,9 @@ class G1CollectedHeap : public CollectedHeap { // in the CDS archive. HeapWord* alloc_archive_region(size_t word_size, HeapWord* preferred_addr); - // Populate the G1BlockOffsetTablePart for archived regions with the given + // Populate the G1BlockOffsetTable for archived regions with the given // memory range. - void populate_archive_regions_bot_part(MemRegion range); + void populate_archive_regions_bot(MemRegion range); // For the specified range, uncommit the containing G1 regions // which had been allocated by alloc_archive_regions. This should be called diff --git a/src/hotspot/share/gc/g1/g1CollectedHeap.inline.hpp b/src/hotspot/share/gc/g1/g1CollectedHeap.inline.hpp index 513b0a4505b..30ca270e1b5 100644 --- a/src/hotspot/share/gc/g1/g1CollectedHeap.inline.hpp +++ b/src/hotspot/share/gc/g1/g1CollectedHeap.inline.hpp @@ -248,8 +248,8 @@ inline bool G1CollectedHeap::requires_barriers(stackChunkOop obj) const { } inline bool G1CollectedHeap::is_obj_filler(const oop obj) { - Klass* k = obj->klass_raw(); - return k == Universe::fillerArrayKlassObj() || k == vmClasses::FillerObject_klass(); + Klass* k = obj->klass_without_asserts(); + return k == Universe::fillerArrayKlass() || k == vmClasses::FillerObject_klass(); } inline bool G1CollectedHeap::is_obj_dead(const oop obj, const HeapRegion* hr) const { diff --git a/src/hotspot/share/gc/g1/g1FullGCAdjustTask.cpp b/src/hotspot/share/gc/g1/g1FullGCAdjustTask.cpp index 3eca766b2fc..44e41c3cb89 100644 --- a/src/hotspot/share/gc/g1/g1FullGCAdjustTask.cpp +++ b/src/hotspot/share/gc/g1/g1FullGCAdjustTask.cpp @@ -101,7 +101,7 @@ void G1FullGCAdjustTask::work(uint worker_id) { } CLDToOopClosure adjust_cld(&_adjust, ClassLoaderData::_claim_stw_fullgc_adjust); - CodeBlobToOopClosure adjust_code(&_adjust, CodeBlobToOopClosure::FixRelocations); + NMethodToOopClosure adjust_code(&_adjust, NMethodToOopClosure::FixRelocations); _root_processor.process_all_roots(&_adjust, &adjust_cld, &adjust_code); // Now adjust pointers region by region diff --git a/src/hotspot/share/gc/g1/g1FullGCMarkTask.cpp b/src/hotspot/share/gc/g1/g1FullGCMarkTask.cpp index e27439143d9..6a38bc35f4f 100644 --- a/src/hotspot/share/gc/g1/g1FullGCMarkTask.cpp +++ b/src/hotspot/share/gc/g1/g1FullGCMarkTask.cpp @@ -42,7 +42,7 @@ void G1FullGCMarkTask::work(uint worker_id) { Ticks start = Ticks::now(); ResourceMark rm; G1FullGCMarker* marker = collector()->marker(worker_id); - MarkingCodeBlobClosure code_closure(marker->mark_closure(), !CodeBlobToOopClosure::FixRelocations, true /* keepalive nmethods */); + MarkingNMethodClosure code_closure(marker->mark_closure(), !NMethodToOopClosure::FixRelocations, true /* keepalive nmethods */); if (ClassUnloading) { _root_processor.process_strong_roots(marker->mark_closure(), diff --git a/src/hotspot/share/gc/g1/g1GCPhaseTimes.cpp b/src/hotspot/share/gc/g1/g1GCPhaseTimes.cpp index a39a082bc82..29b7c414777 100644 --- a/src/hotspot/share/gc/g1/g1GCPhaseTimes.cpp +++ b/src/hotspot/share/gc/g1/g1GCPhaseTimes.cpp @@ -123,14 +123,14 @@ G1GCPhaseTimes::G1GCPhaseTimes(STWGCTimer* gc_timer, uint max_gc_threads) : _gc_par_phases[MergeLB]->create_thread_work_items("Dirty Cards:", MergeLBDirtyCards); _gc_par_phases[MergeLB]->create_thread_work_items("Skipped Cards:", MergeLBSkippedCards); - _gc_par_phases[CodeRoots]->create_thread_work_items("Scanned Nmethods", CodeRootsScannedNMethods); + _gc_par_phases[CodeRoots]->create_thread_work_items("Scanned Nmethods:", CodeRootsScannedNMethods); - _gc_par_phases[OptCodeRoots]->create_thread_work_items("Scanned Nmethods", CodeRootsScannedNMethods); + _gc_par_phases[OptCodeRoots]->create_thread_work_items("Scanned Nmethods:", CodeRootsScannedNMethods); - _gc_par_phases[MergePSS]->create_thread_work_items("Copied Bytes", MergePSSCopiedBytes); - _gc_par_phases[MergePSS]->create_thread_work_items("LAB Waste", MergePSSLABWasteBytes); - _gc_par_phases[MergePSS]->create_thread_work_items("LAB Undo Waste", MergePSSLABUndoWasteBytes); - _gc_par_phases[MergePSS]->create_thread_work_items("Evac Fail Extra Cards", MergePSSEvacFailExtra); + _gc_par_phases[MergePSS]->create_thread_work_items("Copied Bytes:", MergePSSCopiedBytes); + _gc_par_phases[MergePSS]->create_thread_work_items("LAB Waste:", MergePSSLABWasteBytes); + _gc_par_phases[MergePSS]->create_thread_work_items("LAB Undo Waste:", MergePSSLABUndoWasteBytes); + _gc_par_phases[MergePSS]->create_thread_work_items("Evac Fail Extra Cards:", MergePSSEvacFailExtra); _gc_par_phases[RestoreEvacuationFailedRegions]->create_thread_work_items("Evacuation Failed Regions:", RestoreEvacFailureRegionsEvacFailedNum); _gc_par_phases[RestoreEvacuationFailedRegions]->create_thread_work_items("Pinned Regions:", RestoreEvacFailureRegionsPinnedNum); @@ -141,9 +141,9 @@ G1GCPhaseTimes::G1GCPhaseTimes(STWGCTimer* gc_timer, uint max_gc_threads) : _gc_par_phases[RemoveSelfForwards]->create_thread_work_items("Forward Objects:", RemoveSelfForwardObjectsNum); _gc_par_phases[RemoveSelfForwards]->create_thread_work_items("Forward Bytes:", RemoveSelfForwardObjectsBytes); - _gc_par_phases[EagerlyReclaimHumongousObjects]->create_thread_work_items("Humongous Total", EagerlyReclaimNumTotal); - _gc_par_phases[EagerlyReclaimHumongousObjects]->create_thread_work_items("Humongous Candidates", EagerlyReclaimNumCandidates); - _gc_par_phases[EagerlyReclaimHumongousObjects]->create_thread_work_items("Humongous Reclaimed", EagerlyReclaimNumReclaimed); + _gc_par_phases[EagerlyReclaimHumongousObjects]->create_thread_work_items("Humongous Total:", EagerlyReclaimNumTotal); + _gc_par_phases[EagerlyReclaimHumongousObjects]->create_thread_work_items("Humongous Candidates:", EagerlyReclaimNumCandidates); + _gc_par_phases[EagerlyReclaimHumongousObjects]->create_thread_work_items("Humongous Reclaimed:", EagerlyReclaimNumReclaimed); _gc_par_phases[SampleCollectionSetCandidates] = new WorkerDataArray("SampleCandidates", "Sample CSet Candidates (ms):", max_gc_threads); diff --git a/src/hotspot/share/gc/g1/g1GCPhaseTimes.hpp b/src/hotspot/share/gc/g1/g1GCPhaseTimes.hpp index bae0dfa87a0..40abfd60533 100644 --- a/src/hotspot/share/gc/g1/g1GCPhaseTimes.hpp +++ b/src/hotspot/share/gc/g1/g1GCPhaseTimes.hpp @@ -116,9 +116,9 @@ class G1GCPhaseTimes : public CHeapObj { }; static constexpr const char* GCMergeRSWorkItemsStrings[MergeRSContainersSentinel] = - { "Merged Inline", "Merged ArrayOfCards", "Merged Howl", "Merged Full", - "Merged Howl Inline", "Merged Howl ArrayOfCards", "Merged Howl BitMap", "Merged Howl Full", - "Merged Cards" }; + { "Merged Inline:", "Merged ArrayOfCards:", "Merged Howl:", "Merged Full:", + "Merged Howl Inline:", "Merged Howl ArrayOfCards:", "Merged Howl BitMap:", "Merged Howl Full:", + "Merged Cards:" }; enum GCScanHRWorkItems { ScanHRScannedCards, diff --git a/src/hotspot/share/gc/g1/g1HeapRegion.cpp b/src/hotspot/share/gc/g1/g1HeapRegion.cpp index be012bbc5a6..4583cae2046 100644 --- a/src/hotspot/share/gc/g1/g1HeapRegion.cpp +++ b/src/hotspot/share/gc/g1/g1HeapRegion.cpp @@ -188,7 +188,10 @@ void HeapRegion::set_starts_humongous(HeapWord* obj_top, size_t fill_size) { _type.set_starts_humongous(); _humongous_start_region = this; - _bot_part.set_for_starts_humongous(obj_top, fill_size); + _bot->update_for_block(bottom(), obj_top); + if (fill_size > 0) { + _bot->update_for_block(obj_top, obj_top + fill_size); + } } void HeapRegion::set_continues_humongous(HeapRegion* first_hr) { @@ -219,7 +222,7 @@ HeapRegion::HeapRegion(uint hrm_index, _bottom(mr.start()), _end(mr.end()), _top(nullptr), - _bot_part(bot, this), + _bot(bot), _pre_dummy_top(nullptr), _rem_set(nullptr), _hrm_index(hrm_index), @@ -286,7 +289,7 @@ void HeapRegion::remove_code_root(nmethod* nm) { rem_set()->remove_code_root(nm); } -void HeapRegion::code_roots_do(CodeBlobClosure* blk) const { +void HeapRegion::code_roots_do(NMethodClosure* blk) const { rem_set()->code_roots_do(blk); } @@ -328,28 +331,27 @@ class VerifyCodeRootOopClosure: public OopClosure { bool has_oops_in_region() { return _has_oops_in_region; } }; -class VerifyCodeRootCodeBlobClosure: public CodeBlobClosure { +class VerifyCodeRootNMethodClosure: public NMethodClosure { const HeapRegion* _hr; bool _failures; public: - VerifyCodeRootCodeBlobClosure(const HeapRegion* hr) : + VerifyCodeRootNMethodClosure(const HeapRegion* hr) : _hr(hr), _failures(false) {} - void do_code_blob(CodeBlob* cb) { - nmethod* nm = (cb == nullptr) ? nullptr : cb->as_compiled_method()->as_nmethod_or_null(); - if (nm != nullptr) { - // Verify that the nemthod is live - VerifyCodeRootOopClosure oop_cl(_hr); - nm->oops_do(&oop_cl); - if (!oop_cl.has_oops_in_region()) { - log_error(gc, verify)("region [" PTR_FORMAT "," PTR_FORMAT "] has nmethod " PTR_FORMAT " in its code roots with no pointers into region", - p2i(_hr->bottom()), p2i(_hr->end()), p2i(nm)); - _failures = true; - } else if (oop_cl.failures()) { - log_error(gc, verify)("region [" PTR_FORMAT "," PTR_FORMAT "] has other failures for nmethod " PTR_FORMAT, - p2i(_hr->bottom()), p2i(_hr->end()), p2i(nm)); - _failures = true; - } + void do_nmethod(nmethod* nm) { + assert(nm != nullptr, "Sanity"); + + // Verify that the nmethod is live + VerifyCodeRootOopClosure oop_cl(_hr); + nm->oops_do(&oop_cl); + if (!oop_cl.has_oops_in_region()) { + log_error(gc, verify)("region [" PTR_FORMAT "," PTR_FORMAT "] has nmethod " PTR_FORMAT " in its code roots with no pointers into region", + p2i(_hr->bottom()), p2i(_hr->end()), p2i(nm)); + _failures = true; + } else if (oop_cl.failures()) { + log_error(gc, verify)("region [" PTR_FORMAT "," PTR_FORMAT "] has other failures for nmethod " PTR_FORMAT, + p2i(_hr->bottom()), p2i(_hr->end()), p2i(nm)); + _failures = true; } } @@ -395,10 +397,10 @@ bool HeapRegion::verify_code_roots(VerifyOption vo) const { return has_code_roots; } - VerifyCodeRootCodeBlobClosure cb_cl(this); - code_roots_do(&cb_cl); + VerifyCodeRootNMethodClosure nm_cl(this); + code_roots_do(&nm_cl); - return cb_cl.failures(); + return nm_cl.failures(); } void HeapRegion::print() const { print_on(tty); } @@ -433,39 +435,61 @@ void HeapRegion::print_on(outputStream* st) const { } static bool is_oop_safe(oop obj) { - if (!oopDesc::is_oop(obj)) { - log_error(gc, verify)(PTR_FORMAT " not an oop", p2i(obj)); + // Make a few sanity checks of the class before calling the full-fledged + // is_oop check (which also performs its own klass verification). + Klass* klass = obj->klass_without_asserts(); + + if (klass == nullptr) { + log_error(gc, verify)("Object " PTR_FORMAT " has a null klass", p2i(obj)); return false; } - // Now examine the Klass a little more closely. - Klass* klass = obj->klass_raw(); - - bool is_metaspace_object = Metaspace::contains(klass); - if (!is_metaspace_object) { + if (!Metaspace::contains(klass)) { log_error(gc, verify)("klass " PTR_FORMAT " of object " PTR_FORMAT " " - "not metadata", p2i(klass), p2i(obj)); + "is not in metaspace", p2i(klass), p2i(obj)); return false; - } else if (!klass->is_klass()) { + } + + if (!klass->is_klass()) { log_error(gc, verify)("klass " PTR_FORMAT " of object " PTR_FORMAT " " "not a klass", p2i(klass), p2i(obj)); return false; } + // Now, perform the more in-depth verification of the object. + if (!oopDesc::is_oop(obj)) { + log_error(gc, verify)(PTR_FORMAT " not an oop", p2i(obj)); + return false; + } + return true; } +class G1VerifyFailureCounter { + size_t _count; + +public: + G1VerifyFailureCounter() : _count(0) {} + + // Increases the failure counter and return whether this has been the first failure. + bool record_failure() { + _count++; + return _count == 1; + } + + size_t count() const { return _count; } +}; + // Closure that glues together validity check for oop references (first), // then optionally verifies the remembered set for that reference. class G1VerifyLiveAndRemSetClosure : public BasicOopIterateClosure { - VerifyOption _vo; - oop _containing_obj; - size_t _num_failures; + const VerifyOption _vo; + const oop _containing_obj; + G1VerifyFailureCounter* const _failures; // Increases the failure counter and return whether this has been the first failure. bool record_failure() { - _num_failures++; - return _num_failures == 1; + return _failures->record_failure(); } static void print_object(outputStream* out, oop obj) { @@ -479,18 +503,22 @@ class G1VerifyLiveAndRemSetClosure : public BasicOopIterateClosure { template struct Checker { G1CollectedHeap* _g1h; - G1VerifyLiveAndRemSetClosure* _cl; + G1VerifyFailureCounter* _failures; oop _containing_obj; T* _p; oop _obj; - Checker(G1VerifyLiveAndRemSetClosure* cl, oop containing_obj, T* p, oop obj) : + Checker(G1VerifyFailureCounter* failures, oop containing_obj, T* p, oop obj) : _g1h(G1CollectedHeap::heap()), - _cl(cl), + _failures(failures), _containing_obj(containing_obj), _p(p), _obj(obj) { } + bool record_failure() { + return _failures->record_failure(); + } + void print_containing_obj(outputStream* out, HeapRegion* from) { log_error(gc, verify)("Field " PTR_FORMAT " of obj " PTR_FORMAT " in region " HR_FORMAT, p2i(_p), p2i(_containing_obj), HR_FORMAT_PARAMS(from)); @@ -509,7 +537,8 @@ class G1VerifyLiveAndRemSetClosure : public BasicOopIterateClosure { VerifyOption _vo; bool _is_in_heap; - LiveChecker(G1VerifyLiveAndRemSetClosure* cl, oop containing_obj, T* p, oop obj, VerifyOption vo) : Checker(cl, containing_obj, p, obj) { + LiveChecker(G1VerifyFailureCounter* failures, oop containing_obj, T* p, oop obj, VerifyOption vo) + : Checker(failures, containing_obj, p, obj) { _vo = vo; _is_in_heap = this->_g1h->is_in(obj); } @@ -525,7 +554,7 @@ class G1VerifyLiveAndRemSetClosure : public BasicOopIterateClosure { MutexLocker x(G1RareEvent_lock, Mutex::_no_safepoint_check_flag); - if (this->_cl->record_failure()) { + if (this->record_failure()) { log.error("----------"); } @@ -551,7 +580,8 @@ class G1VerifyLiveAndRemSetClosure : public BasicOopIterateClosure { CardValue _cv_obj; CardValue _cv_field; - RemSetChecker(G1VerifyLiveAndRemSetClosure* cl, oop containing_obj, T* p, oop obj) : Checker(cl, containing_obj, p, obj) { + RemSetChecker(G1VerifyFailureCounter* failures, oop containing_obj, T* p, oop obj) + : Checker(failures, containing_obj, p, obj) { _from = this->_g1h->heap_region_containing(p); _to = this->_g1h->heap_region_containing(obj); @@ -578,7 +608,7 @@ class G1VerifyLiveAndRemSetClosure : public BasicOopIterateClosure { MutexLocker x(G1RareEvent_lock, Mutex::_no_safepoint_check_flag); - if (this->_cl->record_failure()) { + if (this->record_failure()) { log.error("----------"); } log.error("Missing rem set entry:"); @@ -591,10 +621,7 @@ class G1VerifyLiveAndRemSetClosure : public BasicOopIterateClosure { template void do_oop_work(T* p) { - assert(_containing_obj != nullptr, "must be"); - assert(!G1CollectedHeap::heap()->is_obj_dead_cond(_containing_obj, _vo), "Precondition"); - - if (num_failures() >= G1MaxVerifyFailures) { + if (_failures->count() >= G1MaxVerifyFailures) { return; } @@ -604,30 +631,24 @@ class G1VerifyLiveAndRemSetClosure : public BasicOopIterateClosure { } oop obj = CompressedOops::decode_raw_not_null(heap_oop); - LiveChecker live_check(this, _containing_obj, p, obj, _vo); + LiveChecker live_check(_failures, _containing_obj, p, obj, _vo); if (live_check.failed()) { live_check.report_error(); // There is no point in doing remset verification if the reference is bad. return; } - RemSetChecker remset_check(this, _containing_obj, p, obj); + RemSetChecker remset_check(_failures, _containing_obj, p, obj); if (remset_check.failed()) { remset_check.report_error(); } } public: - G1VerifyLiveAndRemSetClosure(G1CollectedHeap* g1h, VerifyOption vo) : - _vo(vo), - _containing_obj(nullptr), - _num_failures(0) { } - - void set_containing_obj(oop const obj) { - _containing_obj = obj; - } - - size_t num_failures() const { return _num_failures; } + G1VerifyLiveAndRemSetClosure(oop containing_obj, VerifyOption vo, G1VerifyFailureCounter* failures) + : _vo(vo), + _containing_obj(containing_obj), + _failures(failures) {} virtual inline void do_oop(narrowOop* p) { do_oop_work(p); } virtual inline void do_oop(oop* p) { do_oop_work(p); } @@ -636,9 +657,7 @@ class G1VerifyLiveAndRemSetClosure : public BasicOopIterateClosure { bool HeapRegion::verify_liveness_and_remset(VerifyOption vo) const { G1CollectedHeap* g1h = G1CollectedHeap::heap(); - G1VerifyLiveAndRemSetClosure cl(g1h, vo); - - size_t other_failures = 0; + G1VerifyFailureCounter failures; HeapWord* p; for (p = bottom(); p < top(); p += block_size(p)) { @@ -649,13 +668,13 @@ bool HeapRegion::verify_liveness_and_remset(VerifyOption vo) const { } if (is_oop_safe(obj)) { - cl.set_containing_obj(obj); + G1VerifyLiveAndRemSetClosure cl(obj, vo, &failures); obj->oop_iterate(&cl); } else { - other_failures++; + failures.record_failure(); } - if ((cl.num_failures() + other_failures) >= G1MaxVerifyFailures) { + if (failures.count() >= G1MaxVerifyFailures) { return true; } } @@ -665,7 +684,7 @@ bool HeapRegion::verify_liveness_and_remset(VerifyOption vo) const { p2i(p), p2i(top())); return true; } - return (cl.num_failures() + other_failures) != 0; + return failures.count() != 0; } bool HeapRegion::verify(VerifyOption vo) const { @@ -678,7 +697,7 @@ bool HeapRegion::verify(VerifyOption vo) const { // Only regions in old generation contain valid BOT. if (!is_empty() && !is_young()) { - _bot_part.verify(); + _bot->verify(this); } if (is_humongous()) { @@ -707,7 +726,7 @@ void HeapRegion::mangle_unused_area() { #endif void HeapRegion::update_bot_for_block(HeapWord* start, HeapWord* end) { - _bot_part.update_for_block(start, end); + _bot->update_for_block(start, end); } void HeapRegion::object_iterate(ObjectClosure* blk) { diff --git a/src/hotspot/share/gc/g1/g1HeapRegion.hpp b/src/hotspot/share/gc/g1/g1HeapRegion.hpp index 9b76d867cc7..dc5cd97a82d 100644 --- a/src/hotspot/share/gc/g1/g1HeapRegion.hpp +++ b/src/hotspot/share/gc/g1/g1HeapRegion.hpp @@ -74,7 +74,7 @@ class HeapRegion : public CHeapObj { HeapWord* volatile _top; - G1BlockOffsetTablePart _bot_part; + G1BlockOffsetTable* _bot; // When we need to retire an allocation region, while other threads // are also concurrently trying to allocate into it, we typically @@ -431,8 +431,6 @@ class HeapRegion : public CHeapObj { inline bool in_collection_set() const; - inline const char* collection_set_candidate_short_type_str() const; - void prepare_remset_for_scan(); // Methods used by the HeapRegionSetBase class and subclasses. @@ -540,9 +538,9 @@ class HeapRegion : public CHeapObj { void add_code_root(nmethod* nm); void remove_code_root(nmethod* nm); - // Applies blk->do_code_blob() to each of the entries in + // Applies blk->do_nmethod() to each of the entries in // the code roots list for this region - void code_roots_do(CodeBlobClosure* blk) const; + void code_roots_do(NMethodClosure* blk) const; uint node_index() const { return _node_index; } void set_node_index(uint node_index) { _node_index = node_index; } diff --git a/src/hotspot/share/gc/g1/g1HeapRegion.inline.hpp b/src/hotspot/share/gc/g1/g1HeapRegion.inline.hpp index e218bb154fa..183579b64d4 100644 --- a/src/hotspot/share/gc/g1/g1HeapRegion.inline.hpp +++ b/src/hotspot/share/gc/g1/g1HeapRegion.inline.hpp @@ -100,12 +100,13 @@ inline HeapWord* HeapRegion::advance_to_block_containing_addr(const void* addr, cur_block = next_block; // Because the BOT is precise, we should never step into the next card // (i.e. crossing the card boundary). - assert(!G1BlockOffsetTablePart::is_crossing_card_boundary(cur_block, (HeapWord*)addr), "must be"); + assert(!G1BlockOffsetTable::is_crossing_card_boundary(cur_block, (HeapWord*)addr), "must be"); } } inline HeapWord* HeapRegion::block_start(const void* addr, HeapWord* const pb) const { - HeapWord* first_block = _bot_part.block_start_reaching_into_card(addr); + assert(addr >= bottom() && addr < top(), "invalid address"); + HeapWord* first_block = _bot->block_start_reaching_into_card(addr); return advance_to_block_containing_addr(addr, pb, first_block); } @@ -262,7 +263,7 @@ inline void HeapRegion::update_bot_for_obj(HeapWord* obj_start, size_t obj_size) HR_FORMAT_PARAMS(this), p2i(obj_start), p2i(obj_end)); - _bot_part.update_for_block(obj_start, obj_end); + _bot->update_for_block(obj_start, obj_end); } inline HeapWord* HeapRegion::parsable_bottom() const { diff --git a/src/hotspot/share/gc/g1/g1HeapRegionRemSet.cpp b/src/hotspot/share/gc/g1/g1HeapRegionRemSet.cpp index 88a3e09bd8e..17134f0da24 100644 --- a/src/hotspot/share/gc/g1/g1HeapRegionRemSet.cpp +++ b/src/hotspot/share/gc/g1/g1HeapRegionRemSet.cpp @@ -119,7 +119,7 @@ void HeapRegionRemSet::bulk_remove_code_roots() { _code_roots.bulk_remove(); } -void HeapRegionRemSet::code_roots_do(CodeBlobClosure* blk) const { +void HeapRegionRemSet::code_roots_do(NMethodClosure* blk) const { _code_roots.nmethods_do(blk); } diff --git a/src/hotspot/share/gc/g1/g1HeapRegionRemSet.hpp b/src/hotspot/share/gc/g1/g1HeapRegionRemSet.hpp index 7e76965835b..fa7aee562c6 100644 --- a/src/hotspot/share/gc/g1/g1HeapRegionRemSet.hpp +++ b/src/hotspot/share/gc/g1/g1HeapRegionRemSet.hpp @@ -40,7 +40,7 @@ class outputStream; class HeapRegionRemSet : public CHeapObj { friend class VMStructs; - // A set of code blobs (nmethods) whose code contains pointers into + // A set of nmethods whose code contains pointers into // the region that owns this RSet. G1CodeRootSet _code_roots; @@ -152,8 +152,8 @@ class HeapRegionRemSet : public CHeapObj { void remove_code_root(nmethod* nm); void bulk_remove_code_roots(); - // Applies blk->do_code_blob() to each of the entries in _code_roots - void code_roots_do(CodeBlobClosure* blk) const; + // Applies blk->do_nmethod() to each of the entries in _code_roots + void code_roots_do(NMethodClosure* blk) const; // Clean out code roots not having an oop pointing into this region any more. void clean_code_roots(HeapRegion* hr); diff --git a/src/hotspot/share/gc/g1/g1HeapVerifier.cpp b/src/hotspot/share/gc/g1/g1HeapVerifier.cpp index d31c8593d6e..199edded0b8 100644 --- a/src/hotspot/share/gc/g1/g1HeapVerifier.cpp +++ b/src/hotspot/share/gc/g1/g1HeapVerifier.cpp @@ -135,19 +135,17 @@ class G1VerifyCodeRootOopClosure: public OopClosure { bool failures() { return _failures; } }; -class G1VerifyCodeRootBlobClosure: public CodeBlobClosure { +class G1VerifyCodeRootNMethodClosure: public NMethodClosure { G1VerifyCodeRootOopClosure* _oop_cl; public: - G1VerifyCodeRootBlobClosure(G1VerifyCodeRootOopClosure* oop_cl): + G1VerifyCodeRootNMethodClosure(G1VerifyCodeRootOopClosure* oop_cl): _oop_cl(oop_cl) {} - void do_code_blob(CodeBlob* cb) { - nmethod* nm = cb->as_nmethod_or_null(); - if (nm != nullptr) { - _oop_cl->set_nmethod(nm); - nm->oops_do(_oop_cl); - } + void do_nmethod(nmethod* nm) { + assert(nm != nullptr, "Sanity"); + _oop_cl->set_nmethod(nm); + nm->oops_do(_oop_cl); } }; @@ -340,7 +338,7 @@ void G1HeapVerifier::verify(VerifyOption vo) { // system dictionary, class loader data graph, the string table // and the nmethods in the code cache. G1VerifyCodeRootOopClosure codeRootsCl(_g1h, &rootsCl, vo); - G1VerifyCodeRootBlobClosure blobsCl(&codeRootsCl); + G1VerifyCodeRootNMethodClosure blobsCl(&codeRootsCl); { G1RootProcessor root_processor(_g1h, 1); diff --git a/src/hotspot/share/gc/g1/g1CodeBlobClosure.cpp b/src/hotspot/share/gc/g1/g1NMethodClosure.cpp similarity index 79% rename from src/hotspot/share/gc/g1/g1CodeBlobClosure.cpp rename to src/hotspot/share/gc/g1/g1NMethodClosure.cpp index 5e99b91e76a..56f1f52e981 100644 --- a/src/hotspot/share/gc/g1/g1CodeBlobClosure.cpp +++ b/src/hotspot/share/gc/g1/g1NMethodClosure.cpp @@ -24,7 +24,7 @@ #include "precompiled.hpp" #include "code/nmethod.hpp" -#include "gc/g1/g1CodeBlobClosure.hpp" +#include "gc/g1/g1NMethodClosure.hpp" #include "gc/g1/g1CollectedHeap.inline.hpp" #include "gc/g1/g1ConcurrentMark.inline.hpp" #include "gc/g1/g1HeapRegion.hpp" @@ -35,7 +35,7 @@ #include "oops/oop.inline.hpp" template -void G1CodeBlobClosure::HeapRegionGatheringOopClosure::do_oop_work(T* p) { +void G1NMethodClosure::HeapRegionGatheringOopClosure::do_oop_work(T* p) { _work->do_oop(p); T oop_or_narrowoop = RawAccess<>::oop_load(p); if (!CompressedOops::is_null(oop_or_narrowoop)) { @@ -46,16 +46,16 @@ void G1CodeBlobClosure::HeapRegionGatheringOopClosure::do_oop_work(T* p) { } } -void G1CodeBlobClosure::HeapRegionGatheringOopClosure::do_oop(oop* o) { +void G1NMethodClosure::HeapRegionGatheringOopClosure::do_oop(oop* o) { do_oop_work(o); } -void G1CodeBlobClosure::HeapRegionGatheringOopClosure::do_oop(narrowOop* o) { +void G1NMethodClosure::HeapRegionGatheringOopClosure::do_oop(narrowOop* o) { do_oop_work(o); } template -void G1CodeBlobClosure::MarkingOopClosure::do_oop_work(T* p) { +void G1NMethodClosure::MarkingOopClosure::do_oop_work(T* p) { T oop_or_narrowoop = RawAccess<>::oop_load(p); if (!CompressedOops::is_null(oop_or_narrowoop)) { oop o = CompressedOops::decode_not_null(oop_or_narrowoop); @@ -63,18 +63,18 @@ void G1CodeBlobClosure::MarkingOopClosure::do_oop_work(T* p) { } } -G1CodeBlobClosure::MarkingOopClosure::MarkingOopClosure(uint worker_id) : +G1NMethodClosure::MarkingOopClosure::MarkingOopClosure(uint worker_id) : _cm(G1CollectedHeap::heap()->concurrent_mark()), _worker_id(worker_id) { } -void G1CodeBlobClosure::MarkingOopClosure::do_oop(oop* o) { +void G1NMethodClosure::MarkingOopClosure::do_oop(oop* o) { do_oop_work(o); } -void G1CodeBlobClosure::MarkingOopClosure::do_oop(narrowOop* o) { +void G1NMethodClosure::MarkingOopClosure::do_oop(narrowOop* o) { do_oop_work(o); } -void G1CodeBlobClosure::do_evacuation_and_fixup(nmethod* nm) { +void G1NMethodClosure::do_evacuation_and_fixup(nmethod* nm) { _oc.set_nm(nm); // Evacuate objects pointed to by the nmethod @@ -93,7 +93,7 @@ void G1CodeBlobClosure::do_evacuation_and_fixup(nmethod* nm) { nm->fix_oop_relocations(); } -void G1CodeBlobClosure::do_marking(nmethod* nm) { +void G1NMethodClosure::do_marking(nmethod* nm) { // Mark through oops in the nmethod nm->oops_do(&_marking_oc); @@ -109,10 +109,10 @@ void G1CodeBlobClosure::do_marking(nmethod* nm) { } class G1NmethodProcessor : public nmethod::OopsDoProcessor { - G1CodeBlobClosure* _cl; + G1NMethodClosure* _cl; public: - G1NmethodProcessor(G1CodeBlobClosure* cl) : _cl(cl) { } + G1NmethodProcessor(G1NMethodClosure* cl) : _cl(cl) { } void do_regular_processing(nmethod* nm) { _cl->do_evacuation_and_fixup(nm); @@ -123,11 +123,8 @@ class G1NmethodProcessor : public nmethod::OopsDoProcessor { } }; -void G1CodeBlobClosure::do_code_blob(CodeBlob* cb) { - nmethod* nm = cb->as_nmethod_or_null(); - if (nm == nullptr) { - return; - } +void G1NMethodClosure::do_nmethod(nmethod* nm) { + assert(nm != nullptr, "Sanity"); G1NmethodProcessor cl(this); diff --git a/src/hotspot/share/gc/g1/g1CodeBlobClosure.hpp b/src/hotspot/share/gc/g1/g1NMethodClosure.hpp similarity index 88% rename from src/hotspot/share/gc/g1/g1CodeBlobClosure.hpp rename to src/hotspot/share/gc/g1/g1NMethodClosure.hpp index e20073bc287..f8872b533ab 100644 --- a/src/hotspot/share/gc/g1/g1CodeBlobClosure.hpp +++ b/src/hotspot/share/gc/g1/g1NMethodClosure.hpp @@ -22,8 +22,8 @@ * */ -#ifndef SHARE_GC_G1_G1CODEBLOBCLOSURE_HPP -#define SHARE_GC_G1_G1CODEBLOBCLOSURE_HPP +#ifndef SHARE_GC_G1_G1NMETHODCLOSURE_HPP +#define SHARE_GC_G1_G1NMETHODCLOSURE_HPP #include "gc/g1/g1CollectedHeap.hpp" #include "memory/iterator.hpp" @@ -31,7 +31,7 @@ class G1ConcurrentMark; class nmethod; -class G1CodeBlobClosure : public CodeBlobClosure { +class G1NMethodClosure : public NMethodClosure { // Gather nmethod remembered set entries. class HeapRegionGatheringOopClosure : public OopClosure { G1CollectedHeap* _g1h; @@ -72,13 +72,13 @@ class G1CodeBlobClosure : public CodeBlobClosure { bool _strong; public: - G1CodeBlobClosure(uint worker_id, OopClosure* oc, bool strong) : + G1NMethodClosure(uint worker_id, OopClosure* oc, bool strong) : _oc(oc), _marking_oc(worker_id), _strong(strong) { } void do_evacuation_and_fixup(nmethod* nm); void do_marking(nmethod* nm); - void do_code_blob(CodeBlob* cb); + void do_nmethod(nmethod* nm); }; -#endif // SHARE_GC_G1_G1CODEBLOBCLOSURE_HPP +#endif // SHARE_GC_G1_G1NMETHODCLOSURE_HPP diff --git a/src/hotspot/share/gc/g1/g1RemSet.cpp b/src/hotspot/share/gc/g1/g1RemSet.cpp index 2b338d89e04..65aa0ff18ab 100644 --- a/src/hotspot/share/gc/g1/g1RemSet.cpp +++ b/src/hotspot/share/gc/g1/g1RemSet.cpp @@ -734,17 +734,17 @@ void G1RemSet::scan_heap_roots(G1ParScanThreadState* pss, p->record_or_add_thread_work_item(scan_phase, worker_id, cl.heap_roots_found(), G1GCPhaseTimes::ScanHRFoundRoots); } -// Wrapper around a CodeBlobClosure to count the number of code blobs scanned. -class G1ScanAndCountCodeBlobClosure : public CodeBlobClosure { - CodeBlobClosure* _cl; +// Wrapper around a NMethodClosure to count the number of nmethods scanned. +class G1ScanAndCountNMethodClosure : public NMethodClosure { + NMethodClosure* _cl; size_t _count; public: - G1ScanAndCountCodeBlobClosure(CodeBlobClosure* cl) : _cl(cl), _count(0) { + G1ScanAndCountNMethodClosure(NMethodClosure* cl) : _cl(cl), _count(0) { } - void do_code_blob(CodeBlob* cb) override { - _cl->do_code_blob(cb); + void do_nmethod(nmethod* nm) override { + _cl->do_nmethod(nm); _count++; } @@ -820,7 +820,7 @@ class G1ScanCollectionSetRegionClosure : public HeapRegionClosure { { EventGCPhaseParallel event; G1EvacPhaseWithTrimTimeTracker timer(_pss, _code_root_scan_time, _code_trim_partially_time); - G1ScanAndCountCodeBlobClosure cl(_pss->closures()->weak_codeblobs()); + G1ScanAndCountNMethodClosure cl(_pss->closures()->weak_nmethods()); // Scan the code root list attached to the current region r->code_roots_do(&cl); diff --git a/src/hotspot/share/gc/g1/g1RemSet.hpp b/src/hotspot/share/gc/g1/g1RemSet.hpp index f38e5e7f0f4..260fc728923 100644 --- a/src/hotspot/share/gc/g1/g1RemSet.hpp +++ b/src/hotspot/share/gc/g1/g1RemSet.hpp @@ -39,7 +39,6 @@ class BitMap; class CardTableBarrierSet; -class CodeBlobClosure; class G1AbstractSubTask; class G1CollectedHeap; class G1CMBitMap; diff --git a/src/hotspot/share/gc/g1/g1RootClosures.cpp b/src/hotspot/share/gc/g1/g1RootClosures.cpp index 0d3fac2c11e..9d64bc76fd6 100644 --- a/src/hotspot/share/gc/g1/g1RootClosures.cpp +++ b/src/hotspot/share/gc/g1/g1RootClosures.cpp @@ -42,8 +42,8 @@ class G1EvacuationClosures : public G1EvacuationRootClosures { CLDClosure* weak_clds() { return &_closures._clds; } CLDClosure* strong_clds() { return &_closures._clds; } - CodeBlobClosure* strong_codeblobs() { return &_closures._codeblobs; } - CodeBlobClosure* weak_codeblobs() { return &_closures._codeblobs; } + NMethodClosure* strong_nmethods() { return &_closures._nmethods; } + NMethodClosure* weak_nmethods() { return &_closures._nmethods; } }; // Closures used during concurrent start. @@ -65,8 +65,8 @@ class G1ConcurrentStartMarkClosures : public G1EvacuationRootClosures { CLDClosure* weak_clds() { return &_weak._clds; } CLDClosure* strong_clds() { return &_strong._clds; } - CodeBlobClosure* strong_codeblobs() { return &_strong._codeblobs; } - CodeBlobClosure* weak_codeblobs() { return &_weak._codeblobs; } + NMethodClosure* strong_nmethods() { return &_strong._nmethods; } + NMethodClosure* weak_nmethods() { return &_weak._nmethods; } }; G1EvacuationRootClosures* G1EvacuationRootClosures::create_root_closures(G1CollectedHeap* g1h, diff --git a/src/hotspot/share/gc/g1/g1RootClosures.hpp b/src/hotspot/share/gc/g1/g1RootClosures.hpp index cd3e30ad622..7ada501074d 100644 --- a/src/hotspot/share/gc/g1/g1RootClosures.hpp +++ b/src/hotspot/share/gc/g1/g1RootClosures.hpp @@ -40,14 +40,14 @@ class G1RootClosures : public CHeapObj { virtual CLDClosure* weak_clds() = 0; virtual CLDClosure* strong_clds() = 0; - // Applied to code blobs reachable as strong roots. - virtual CodeBlobClosure* strong_codeblobs() = 0; + // Applied to nmethods reachable as strong roots. + virtual NMethodClosure* strong_nmethods() = 0; }; class G1EvacuationRootClosures : public G1RootClosures { public: - // Applied to code blobs treated as weak roots. - virtual CodeBlobClosure* weak_codeblobs() = 0; + // Applied to nmethods treated as weak roots. + virtual NMethodClosure* weak_nmethods() = 0; static G1EvacuationRootClosures* create_root_closures(G1CollectedHeap* g1h, G1ParScanThreadState* pss, diff --git a/src/hotspot/share/gc/g1/g1RootProcessor.cpp b/src/hotspot/share/gc/g1/g1RootProcessor.cpp index 51a77eccfdf..140e8408e52 100644 --- a/src/hotspot/share/gc/g1/g1RootProcessor.cpp +++ b/src/hotspot/share/gc/g1/g1RootProcessor.cpp @@ -27,12 +27,12 @@ #include "classfile/stringTable.hpp" #include "code/codeCache.hpp" #include "gc/g1/g1BarrierSet.hpp" -#include "gc/g1/g1CodeBlobClosure.hpp" #include "gc/g1/g1CollectedHeap.inline.hpp" #include "gc/g1/g1CollectorState.hpp" #include "gc/g1/g1GCParPhaseTimesTracker.hpp" #include "gc/g1/g1GCPhaseTimes.hpp" #include "gc/g1/g1HeapRegion.inline.hpp" +#include "gc/g1/g1NMethodClosure.hpp" #include "gc/g1/g1ParScanThreadState.inline.hpp" #include "gc/g1/g1Policy.hpp" #include "gc/g1/g1RootClosures.hpp" @@ -80,23 +80,23 @@ void G1RootProcessor::evacuate_roots(G1ParScanThreadState* pss, uint worker_id) class StrongRootsClosures : public G1RootClosures { OopClosure* _roots; CLDClosure* _clds; - CodeBlobClosure* _blobs; + NMethodClosure* _nmethods; public: - StrongRootsClosures(OopClosure* roots, CLDClosure* clds, CodeBlobClosure* blobs) : - _roots(roots), _clds(clds), _blobs(blobs) {} + StrongRootsClosures(OopClosure* roots, CLDClosure* clds, NMethodClosure* nmethods) : + _roots(roots), _clds(clds), _nmethods(nmethods) {} OopClosure* strong_oops() { return _roots; } CLDClosure* weak_clds() { return nullptr; } CLDClosure* strong_clds() { return _clds; } - CodeBlobClosure* strong_codeblobs() { return _blobs; } + NMethodClosure* strong_nmethods() { return _nmethods; } }; void G1RootProcessor::process_strong_roots(OopClosure* oops, CLDClosure* clds, - CodeBlobClosure* blobs) { - StrongRootsClosures closures(oops, clds, blobs); + NMethodClosure* nmethods) { + StrongRootsClosures closures(oops, clds, nmethods); process_java_roots(&closures, nullptr, 0); process_vm_roots(&closures, nullptr, 0); @@ -123,20 +123,20 @@ class AllRootsClosures : public G1RootClosures { CLDClosure* weak_clds() { return _clds; } CLDClosure* strong_clds() { return _clds; } - // We don't want to visit code blobs more than once, so we return null for the + // We don't want to visit nmethods more than once, so we return null for the // strong case and walk the entire code cache as a separate step. - CodeBlobClosure* strong_codeblobs() { return nullptr; } + NMethodClosure* strong_nmethods() { return nullptr; } }; void G1RootProcessor::process_all_roots(OopClosure* oops, CLDClosure* clds, - CodeBlobClosure* blobs) { + NMethodClosure* nmethods) { AllRootsClosures closures(oops, clds); process_java_roots(&closures, nullptr, 0); process_vm_roots(&closures, nullptr, 0); - process_code_cache_roots(blobs, nullptr, 0); + process_code_cache_roots(nmethods, nullptr, 0); // refProcessor is not needed since we are inside a safe point _process_strong_tasks.all_tasks_claimed(G1RP_PS_refProcessor_oops_do); @@ -149,7 +149,7 @@ void G1RootProcessor::process_java_roots(G1RootClosures* closures, // processes nmethods in two ways, as "strong" and "weak" nmethods. // // 1) Strong nmethods are reachable from the thread stack frames. G1 applies - // the G1RootClosures::strong_codeblobs() closure on them. The closure + // the G1RootClosures::strong_nmethods() closure on them. The closure // iterates over all oops embedded inside each nmethod, and performs 3 // operations: // a) evacuates; relocate objects outside of collection set @@ -159,7 +159,7 @@ void G1RootProcessor::process_java_roots(G1RootClosures* closures, // classes will not be unloaded. // // 2) Weak nmethods are reachable only from the code root remembered set (see - // G1CodeRootSet). G1 applies the G1RootClosures::weak_codeblobs() closure on + // G1CodeRootSet). G1 applies the G1RootClosures::weak_nmethods() closure on // them. The closure iterates over all oops embedded inside each nmethod, and // performs 2 operations: a) and b). // Since these oops are *not* marked, their classes can potentially be @@ -179,7 +179,7 @@ void G1RootProcessor::process_java_roots(G1RootClosures* closures, bool is_par = n_workers() > 1; Threads::possibly_parallel_oops_do(is_par, closures->strong_oops(), - closures->strong_codeblobs()); + closures->strong_nmethods()); } if (_process_strong_tasks.try_claim_task(G1RP_PS_ClassLoaderDataGraph_oops_do)) { @@ -200,14 +200,14 @@ void G1RootProcessor::process_vm_roots(G1RootClosures* closures, } } -void G1RootProcessor::process_code_cache_roots(CodeBlobClosure* code_closure, +void G1RootProcessor::process_code_cache_roots(NMethodClosure* nmethod_closure, G1GCPhaseTimes* phase_times, uint worker_id) { // We do not track timing of this phase. It is only required with class unloading // disabled, which is an extremely uncommon use case and would otherwise only ever // show up as "skipped" in the logs. if (_process_strong_tasks.try_claim_task(G1RP_PS_CodeCache_oops_do)) { - CodeCache::blobs_do(code_closure); + CodeCache::nmethods_do(nmethod_closure); } } diff --git a/src/hotspot/share/gc/g1/g1RootProcessor.hpp b/src/hotspot/share/gc/g1/g1RootProcessor.hpp index cdb843e57fc..cf4fdc3c263 100644 --- a/src/hotspot/share/gc/g1/g1RootProcessor.hpp +++ b/src/hotspot/share/gc/g1/g1RootProcessor.hpp @@ -31,7 +31,6 @@ #include "runtime/mutex.hpp" class CLDClosure; -class CodeBlobClosure; class G1CollectedHeap; class G1EvacuationRootClosures; class G1GCPhaseTimes; @@ -68,7 +67,7 @@ class G1RootProcessor : public StackObj { G1GCPhaseTimes* phase_times, uint worker_id); - void process_code_cache_roots(CodeBlobClosure* code_closure, + void process_code_cache_roots(NMethodClosure* nmethods_closure, G1GCPhaseTimes* phase_times, uint worker_id); @@ -83,12 +82,12 @@ class G1RootProcessor : public StackObj { // Apply oops, clds and blobs to all strongly reachable roots in the system void process_strong_roots(OopClosure* oops, CLDClosure* clds, - CodeBlobClosure* blobs); + NMethodClosure* nmethods); // Apply oops, clds and blobs to strongly and weakly reachable roots in the system void process_all_roots(OopClosure* oops, CLDClosure* clds, - CodeBlobClosure* blobs); + NMethodClosure* nmethods); // Number of worker threads used by the root processor. uint n_workers() const; diff --git a/src/hotspot/share/gc/g1/g1SharedClosures.hpp b/src/hotspot/share/gc/g1/g1SharedClosures.hpp index 4808f0ae84f..80f1389e7d8 100644 --- a/src/hotspot/share/gc/g1/g1SharedClosures.hpp +++ b/src/hotspot/share/gc/g1/g1SharedClosures.hpp @@ -22,7 +22,7 @@ * */ -#include "gc/g1/g1CodeBlobClosure.hpp" +#include "gc/g1/g1NMethodClosure.hpp" #include "gc/g1/g1OopClosures.hpp" #include "memory/iterator.hpp" @@ -45,12 +45,12 @@ class G1SharedClosures { G1ParCopyClosure _oops_in_nmethod; G1CLDScanClosure _clds; - G1CodeBlobClosure _codeblobs; + G1NMethodClosure _nmethods; G1SharedClosures(G1CollectedHeap* g1h, G1ParScanThreadState* pss, bool process_only_dirty) : _oops(g1h, pss), _oops_in_cld(g1h, pss), _oops_in_nmethod(g1h, pss), _clds(&_oops_in_cld, process_only_dirty), - _codeblobs(pss->worker_id(), &_oops_in_nmethod, should_mark) {} + _nmethods(pss->worker_id(), &_oops_in_nmethod, should_mark) {} }; diff --git a/src/hotspot/share/gc/parallel/psOldGen.cpp b/src/hotspot/share/gc/parallel/psOldGen.cpp index d4eeade40e1..9899b89ad29 100644 --- a/src/hotspot/share/gc/parallel/psOldGen.cpp +++ b/src/hotspot/share/gc/parallel/psOldGen.cpp @@ -377,24 +377,6 @@ void PSOldGen::verify() { object_space()->verify(); } -class VerifyObjectStartArrayClosure : public ObjectClosure { - ObjectStartArray* _start_array; - -public: - VerifyObjectStartArrayClosure(ObjectStartArray* start_array) : - _start_array(start_array) { } - - virtual void do_object(oop obj) { - HeapWord* test_addr = cast_from_oop(obj) + 1; - guarantee(_start_array->object_start(test_addr) == cast_from_oop(obj), "ObjectStartArray cannot find start of object"); - } -}; - -void PSOldGen::verify_object_start_array() { - VerifyObjectStartArrayClosure check(&_start_array); - object_iterate(&check); -} - #ifndef PRODUCT void PSOldGen::record_spaces_top() { assert(ZapUnusedHeapArea, "Not mangling unused space"); diff --git a/src/hotspot/share/gc/parallel/psOldGen.hpp b/src/hotspot/share/gc/parallel/psOldGen.hpp index 82aa920f401..6eb5e01bc8a 100644 --- a/src/hotspot/share/gc/parallel/psOldGen.hpp +++ b/src/hotspot/share/gc/parallel/psOldGen.hpp @@ -149,7 +149,6 @@ class PSOldGen : public CHeapObj { virtual void print_on(outputStream* st) const; void verify(); - void verify_object_start_array(); // Performance Counter support void update_counters(); diff --git a/src/hotspot/share/gc/parallel/psParallelCompact.cpp b/src/hotspot/share/gc/parallel/psParallelCompact.cpp index 3abae8cb22a..8480e8520c4 100644 --- a/src/hotspot/share/gc/parallel/psParallelCompact.cpp +++ b/src/hotspot/share/gc/parallel/psParallelCompact.cpp @@ -913,12 +913,6 @@ void PSParallelCompact::pre_compact() Universe::verify("Before GC"); } - // Verify object start arrays - if (VerifyObjectStartArray && - VerifyBeforeGC) { - heap->old_gen()->verify_object_start_array(); - } - DEBUG_ONLY(mark_bitmap()->verify_clear();) DEBUG_ONLY(summary_data().verify_clear();) @@ -1414,7 +1408,7 @@ bool PSParallelCompact::invoke_no_policy(bool maximum_heap_compaction) { ClassUnloadingContext ctx(1 /* num_nmethod_unlink_workers */, false /* unregister_nmethods_during_purge */, - false /* lock_codeblob_free_separately */); + false /* lock_nmethod_free_separately */); marking_phase(&_gc_tracer); @@ -1427,7 +1421,7 @@ bool PSParallelCompact::invoke_no_policy(bool maximum_heap_compaction) { DerivedPointerTable::set_active(false); #endif - // adjust_roots() updates Universe::_intArrayKlassObj which is + // adjust_roots() updates Universe::_intArrayKlass which is // needed by the compaction for filling holes in the dense prefix. adjust_roots(); @@ -1535,12 +1529,6 @@ bool PSParallelCompact::invoke_no_policy(bool maximum_heap_compaction) { Universe::verify("After GC"); } - // Re-verify object start arrays - if (VerifyObjectStartArray && - VerifyAfterGC) { - old_gen->verify_object_start_array(); - } - if (ZapUnusedHeapArea) { old_gen->object_space()->check_mangled_unused_area_complete(); } @@ -1572,7 +1560,7 @@ class PCAddThreadRootsMarkingTaskClosure : public ThreadClosure { ParCompactionManager* cm = ParCompactionManager::gc_thread_compaction_manager(_worker_id); PCMarkAndPushClosure mark_and_push_closure(cm); - MarkingCodeBlobClosure mark_and_push_in_blobs(&mark_and_push_closure, !CodeBlobToOopClosure::FixRelocations, true /* keepalive nmethods */); + MarkingNMethodClosure mark_and_push_in_blobs(&mark_and_push_closure, !NMethodToOopClosure::FixRelocations, true /* keepalive nmethods */); thread->oops_do(&mark_and_push_closure, &mark_and_push_in_blobs); @@ -1743,7 +1731,7 @@ void PSParallelCompact::marking_phase(ParallelOldTracer *gc_tracer) { } { GCTraceTime(Debug, gc, phases) t("Free Code Blobs", gc_timer()); - ctx->free_code_blobs(); + ctx->free_nmethods(); } // Prune dead klasses from subklass/sibling/implementor lists. @@ -1809,8 +1797,8 @@ class PSAdjustTask final : public WorkerTask { _weak_proc_task.work(worker_id, &always_alive, &adjust); } if (_sub_tasks.try_claim_task(PSAdjustSubTask_code_cache)) { - CodeBlobToOopClosure adjust_code(&adjust, CodeBlobToOopClosure::FixRelocations); - CodeCache::blobs_do(&adjust_code); + NMethodToOopClosure adjust_code(&adjust, NMethodToOopClosure::FixRelocations); + CodeCache::nmethods_do(&adjust_code); } _sub_tasks.all_tasks_claimed(); } diff --git a/src/hotspot/share/gc/parallel/psScavenge.cpp b/src/hotspot/share/gc/parallel/psScavenge.cpp index 78fba1dfe72..92befe23438 100644 --- a/src/hotspot/share/gc/parallel/psScavenge.cpp +++ b/src/hotspot/share/gc/parallel/psScavenge.cpp @@ -99,7 +99,7 @@ static void scavenge_roots_work(ParallelRootType::Value root_type, uint worker_i case ParallelRootType::code_cache: { - MarkingCodeBlobClosure code_closure(&roots_to_old_closure, CodeBlobToOopClosure::FixRelocations, false /* keepalive nmethods */); + MarkingNMethodClosure code_closure(&roots_to_old_closure, NMethodToOopClosure::FixRelocations, false /* keepalive nmethods */); ScavengableNMethods::nmethods_do(&code_closure); } break; @@ -268,9 +268,9 @@ class PSThreadRootsTaskClosure : public ThreadClosure { PSPromotionManager* pm = PSPromotionManager::gc_thread_promotion_manager(_worker_id); PSScavengeRootsClosure roots_closure(pm); - MarkingCodeBlobClosure roots_in_blobs(&roots_closure, CodeBlobToOopClosure::FixRelocations, false /* keepalive nmethods */); + MarkingNMethodClosure roots_in_nmethods(&roots_closure, NMethodToOopClosure::FixRelocations, false /* keepalive nmethods */); - thread->oops_do(&roots_closure, &roots_in_blobs); + thread->oops_do(&roots_closure, &roots_in_nmethods); // Do the real work pm->drain_stacks(false); @@ -419,12 +419,6 @@ bool PSScavenge::invoke_no_policy() { // Let the size policy know we're starting size_policy->minor_collection_begin(); - // Verify the object start arrays. - if (VerifyObjectStartArray && - VerifyBeforeGC) { - old_gen->verify_object_start_array(); - } - // Verify no unmarked old->young roots if (VerifyRememberedSets) { heap->card_table()->verify_all_young_refs_imprecise(); @@ -634,12 +628,6 @@ bool PSScavenge::invoke_no_policy() { DerivedPointerTable::update_pointers(); #endif - // Re-verify object start arrays - if (VerifyObjectStartArray && - VerifyAfterGC) { - old_gen->verify_object_start_array(); - } - if (VerifyRememberedSets) { heap->card_table()->verify_all_young_refs_imprecise(); } diff --git a/src/hotspot/share/gc/serial/cardTableRS.cpp b/src/hotspot/share/gc/serial/cardTableRS.cpp index 87c0eba8192..789b5f21cff 100644 --- a/src/hotspot/share/gc/serial/cardTableRS.cpp +++ b/src/hotspot/share/gc/serial/cardTableRS.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 @@ -31,9 +31,9 @@ #include "memory/iterator.inline.hpp" #include "utilities/align.hpp" -void CardTableRS::scan_old_to_young_refs(TenuredSpace* sp) { +void CardTableRS::scan_old_to_young_refs(TenuredSpace* sp, HeapWord* saved_mark_word) { const MemRegion ur = sp->used_region(); - const MemRegion urasm = sp->used_region_at_save_marks(); + const MemRegion urasm = MemRegion(sp->bottom(), saved_mark_word); assert(ur.contains(urasm), "Did you forget to call save_marks()? " diff --git a/src/hotspot/share/gc/serial/cardTableRS.hpp b/src/hotspot/share/gc/serial/cardTableRS.hpp index 7ad6f8aef0b..9be2c720dcb 100644 --- a/src/hotspot/share/gc/serial/cardTableRS.hpp +++ b/src/hotspot/share/gc/serial/cardTableRS.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2021, 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 @@ -60,7 +60,7 @@ class CardTableRS : public CardTable { public: CardTableRS(MemRegion whole_heap); - void scan_old_to_young_refs(TenuredSpace* sp); + void scan_old_to_young_refs(TenuredSpace* sp, HeapWord* saved_mark_word); void inline_write_ref_field_gc(void* field) { CardValue* byte = byte_for(field); diff --git a/src/hotspot/share/gc/serial/defNewGeneration.cpp b/src/hotspot/share/gc/serial/defNewGeneration.cpp index 9aafe1b61f1..ee7ef765fa3 100644 --- a/src/hotspot/share/gc/serial/defNewGeneration.cpp +++ b/src/hotspot/share/gc/serial/defNewGeneration.cpp @@ -702,9 +702,9 @@ void DefNewGeneration::collect(bool full, RootScanClosure root_cl{this}; CLDScanClosure cld_cl{this}; - MarkingCodeBlobClosure code_cl(&root_cl, - CodeBlobToOopClosure::FixRelocations, - false /* keepalive_nmethods */); + MarkingNMethodClosure code_cl(&root_cl, + NMethodToOopClosure::FixRelocations, + false /* keepalive_nmethods */); heap->process_roots(SerialHeap::SO_ScavengeCodeCache, &root_cl, @@ -901,16 +901,12 @@ void DefNewGeneration::drain_promo_failure_scan_stack() { } void DefNewGeneration::save_marks() { - eden()->set_saved_mark(); - to()->set_saved_mark(); - from()->set_saved_mark(); + set_saved_mark_word(); } bool DefNewGeneration::no_allocs_since_save_marks() { - assert(eden()->saved_mark_at_top(), "Violated spec - alloc in eden"); - assert(from()->saved_mark_at_top(), "Violated spec - alloc in from"); - return to()->saved_mark_at_top(); + return saved_mark_at_top(); } void DefNewGeneration::contribute_scratch(void*& scratch, size_t& num_words) { diff --git a/src/hotspot/share/gc/serial/defNewGeneration.hpp b/src/hotspot/share/gc/serial/defNewGeneration.hpp index 5fcfa5813ad..bdcb34b6389 100644 --- a/src/hotspot/share/gc/serial/defNewGeneration.hpp +++ b/src/hotspot/share/gc/serial/defNewGeneration.hpp @@ -139,6 +139,9 @@ class DefNewGeneration: public Generation { ContiguousSpace* _from_space; ContiguousSpace* _to_space; + // Saved mark word, for to-space + HeapWord* _saved_mark_word; + STWGCTimer* _gc_timer; DefNewTracer* _gc_tracer; @@ -168,6 +171,10 @@ class DefNewGeneration: public Generation { ContiguousSpace* from() const { return _from_space; } ContiguousSpace* to() const { return _to_space; } + HeapWord* saved_mark_word() const { return _saved_mark_word; } + void set_saved_mark_word() { _saved_mark_word = to()->top(); } + bool saved_mark_at_top() { return _saved_mark_word == _to_space->top(); } + // Space enquiries size_t capacity() const; size_t used() const; diff --git a/src/hotspot/share/gc/serial/defNewGeneration.inline.hpp b/src/hotspot/share/gc/serial/defNewGeneration.inline.hpp index 808e04a3002..3b129ade499 100644 --- a/src/hotspot/share/gc/serial/defNewGeneration.inline.hpp +++ b/src/hotspot/share/gc/serial/defNewGeneration.inline.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2022, 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 @@ -36,11 +36,8 @@ template void DefNewGeneration::oop_since_save_marks_iterate(OopClosureType* cl) { - // No allocation in eden and from spaces, so no iteration required. - assert(eden()->saved_mark_at_top(), "inv"); - assert(from()->saved_mark_at_top(), "inv"); - - to()->oop_since_save_marks_iterate(cl); + Generation::oop_since_save_marks_iterate_impl(cl, to(), _saved_mark_word); + set_saved_mark_word(); } #endif // SHARE_GC_SERIAL_DEFNEWGENERATION_INLINE_HPP diff --git a/src/hotspot/share/gc/serial/generation.hpp b/src/hotspot/share/gc/serial/generation.hpp index 33ae773f7bf..800abc2e3c4 100644 --- a/src/hotspot/share/gc/serial/generation.hpp +++ b/src/hotspot/share/gc/serial/generation.hpp @@ -27,12 +27,14 @@ #include "gc/shared/collectorCounters.hpp" #include "gc/shared/referenceProcessor.hpp" +#include "gc/shared/space.inline.hpp" #include "logging/log.hpp" #include "memory/allocation.hpp" #include "memory/memRegion.hpp" #include "memory/virtualspace.hpp" #include "runtime/mutex.hpp" #include "runtime/perfData.hpp" +#include "runtime/prefetch.inline.hpp" // A Generation models a heap area for similarly-aged objects. // It will contain one ore more spaces holding the actual objects. @@ -41,7 +43,7 @@ // // Generation - abstract base class // - DefNewGeneration - allocation area (copy collected) -// - TenuredGeneration - tenured (old object) space (markSweepCompact) +// - TenuredGeneration - tenured (old object) space (mark-compact) // // The system configuration currently allowed is: // @@ -199,6 +201,31 @@ class Generation: public CHeapObj { _gc_manager = gc_manager; } + // Apply "blk->do_oop" to the addresses of all reference fields in objects + // starting with the _saved_mark_word, which was noted during a generation's + // save_marks and is required to denote the head of an object. + // Fields in objects allocated by applications of the closure + // *are* included in the iteration. + // Updates saved_mark_word to point to just after the last object iterated over. + template + void oop_since_save_marks_iterate_impl(OopClosureType* blk, ContiguousSpace* space, HeapWord* saved_mark_word); }; +template +void Generation::oop_since_save_marks_iterate_impl(OopClosureType* blk, ContiguousSpace* space, HeapWord* saved_mark_word) { + HeapWord* t; + HeapWord* p = saved_mark_word; + assert(p != nullptr, "expected saved mark"); + + const intx interval = PrefetchScanIntervalInBytes; + do { + t = space->top(); + while (p < t) { + Prefetch::write(p, interval); + oop m = cast_to_oop(p); + p += m->oop_iterate_size(blk); + } + } while (t < space->top()); +} + #endif // SHARE_GC_SERIAL_GENERATION_HPP diff --git a/src/hotspot/share/gc/serial/serialBlockOffsetTable.cpp b/src/hotspot/share/gc/serial/serialBlockOffsetTable.cpp index 6a04b65e9aa..59b7f130df3 100644 --- a/src/hotspot/share/gc/serial/serialBlockOffsetTable.cpp +++ b/src/hotspot/share/gc/serial/serialBlockOffsetTable.cpp @@ -77,6 +77,11 @@ void SerialBlockOffsetTable::resize(size_t new_word_size) { } } +static void fill_range(uint8_t* start, uint8_t* end, uint8_t value) { + // + 1 for inclusive. + memset(start, value, pointer_delta(end, start, sizeof(uint8_t)) + 1); +} + // Write the backskip value for each logarithmic region (array slots containing the same entry value). // // offset @@ -115,7 +120,7 @@ void SerialBlockOffsetTable::update_for_block_work(HeapWord* blk_start, uint8_t* const offset_card = entry_for_addr(cur_card_boundary); // The first card holds the actual offset. - set_offset_array(offset_card, cur_card_boundary, blk_start); + *offset_card = checked_cast(pointer_delta(cur_card_boundary, blk_start)); // Check if this block spans over other cards. uint8_t* end_card = entry_for_addr(blk_end - 1); @@ -130,7 +135,7 @@ void SerialBlockOffsetTable::update_for_block_work(HeapWord* blk_start, uint8_t* reach = offset_card + BOTConstants::power_to_cards_back(i + 1) - 1; uint8_t value = checked_cast(CardTable::card_size_in_words() + i); - set_offset_array(start_card_for_region, MIN2(reach, end_card), value); + fill_range(start_card_for_region, MIN2(reach, end_card), value); start_card_for_region = reach + 1; if (reach >= end_card) { diff --git a/src/hotspot/share/gc/serial/serialBlockOffsetTable.hpp b/src/hotspot/share/gc/serial/serialBlockOffsetTable.hpp index 1c720cfaf87..26364610559 100644 --- a/src/hotspot/share/gc/serial/serialBlockOffsetTable.hpp +++ b/src/hotspot/share/gc/serial/serialBlockOffsetTable.hpp @@ -53,10 +53,6 @@ class SerialBlockOffsetTable: public CHeapObj { // Biased array-start of BOT array for fast BOT entry translation uint8_t* _offset_base; - void fill_range(uint8_t* const start, size_t num_cards, uint8_t offset) { - memset(start, offset, num_cards); - } - // Return the number of slots needed for an offset array // that covers mem_region_words words. static size_t compute_size(size_t mem_region_words) { @@ -66,6 +62,12 @@ class SerialBlockOffsetTable: public CHeapObj { return ReservedSpace::allocation_align_size_up(number_of_slots); } + // Mapping from address to object start array entry. + uint8_t* entry_for_addr(const void* const p) const; + + // Mapping from object start array entry to address of first word. + HeapWord* addr_for_entry(const uint8_t* const p) const; + void update_for_block_work(HeapWord* blk_start, HeapWord* blk_end); static HeapWord* align_up_by_card_size(HeapWord* const addr) { @@ -105,27 +107,6 @@ class SerialBlockOffsetTable: public CHeapObj { // table. The "new_word_size" may not be larger than the size of the // reserved region this table covers. void resize(size_t new_word_size); - - // Mapping from address to object start array entry - uint8_t* entry_for_addr(const void* const p) const; - - // Mapping from object start array entry to address of first word - HeapWord* addr_for_entry(const uint8_t* const p) const; - - void set_offset_array(uint8_t* const addr, HeapWord* high, HeapWord* low) { - assert(_vs.contains(addr), "Block offset address out of range"); - assert(high >= low, "addresses out of order"); - assert(pointer_delta(high, low) < CardTable::card_size_in_words(), "offset too large"); - *addr = checked_cast(pointer_delta(high, low)); - } - - void set_offset_array(uint8_t* const left, uint8_t* const right, uint8_t offset) { - assert(_vs.contains(right), "right address out of range"); - assert(left <= right, "precondition"); - size_t num_cards = right - left + 1; - - fill_range(left, num_cards, offset); - } }; #endif // SHARE_GC_SERIAL_SERIALBLOCKOFFSETTABLE_HPP diff --git a/src/hotspot/share/gc/serial/markSweep.cpp b/src/hotspot/share/gc/serial/serialFullGC.cpp similarity index 83% rename from src/hotspot/share/gc/serial/markSweep.cpp rename to src/hotspot/share/gc/serial/serialFullGC.cpp index 6cca31d76a7..4bcdf702fe2 100644 --- a/src/hotspot/share/gc/serial/markSweep.cpp +++ b/src/hotspot/share/gc/serial/serialFullGC.cpp @@ -34,7 +34,7 @@ #include "compiler/oopMap.hpp" #include "gc/serial/cardTableRS.hpp" #include "gc/serial/defNewGeneration.hpp" -#include "gc/serial/markSweep.inline.hpp" +#include "gc/serial/serialFullGC.inline.hpp" #include "gc/serial/serialGcRefProcProxyTask.hpp" #include "gc/serial/serialHeap.hpp" #include "gc/shared/classUnloadingContext.hpp" @@ -45,6 +45,7 @@ #include "gc/shared/gcTraceTime.inline.hpp" #include "gc/shared/gc_globals.hpp" #include "gc/shared/modRefBarrierSet.hpp" +#include "gc/shared/preservedMarks.inline.hpp" #include "gc/shared/referencePolicy.hpp" #include "gc/shared/referenceProcessorPhaseTimes.hpp" #include "gc/shared/space.inline.hpp" @@ -67,28 +68,28 @@ #include "jvmci/jvmci.hpp" #endif -uint MarkSweep::_total_invocations = 0; +uint SerialFullGC::_total_invocations = 0; -Stack MarkSweep::_marking_stack; -Stack MarkSweep::_objarray_stack; +Stack SerialFullGC::_marking_stack; +Stack SerialFullGC::_objarray_stack; -PreservedMarksSet MarkSweep::_preserved_overflow_stack_set(false /* in_c_heap */); -size_t MarkSweep::_preserved_count = 0; -size_t MarkSweep::_preserved_count_max = 0; -PreservedMark* MarkSweep::_preserved_marks = nullptr; -STWGCTimer* MarkSweep::_gc_timer = nullptr; -SerialOldTracer* MarkSweep::_gc_tracer = nullptr; +PreservedMarksSet SerialFullGC::_preserved_overflow_stack_set(false /* in_c_heap */); +size_t SerialFullGC::_preserved_count = 0; +size_t SerialFullGC::_preserved_count_max = 0; +PreservedMark* SerialFullGC::_preserved_marks = nullptr; +STWGCTimer* SerialFullGC::_gc_timer = nullptr; +SerialOldTracer* SerialFullGC::_gc_tracer = nullptr; -AlwaysTrueClosure MarkSweep::_always_true_closure; -ReferenceProcessor* MarkSweep::_ref_processor; +AlwaysTrueClosure SerialFullGC::_always_true_closure; +ReferenceProcessor* SerialFullGC::_ref_processor; -StringDedup::Requests* MarkSweep::_string_dedup_requests = nullptr; +StringDedup::Requests* SerialFullGC::_string_dedup_requests = nullptr; -MarkSweep::FollowRootClosure MarkSweep::follow_root_closure; +SerialFullGC::FollowRootClosure SerialFullGC::follow_root_closure; -MarkAndPushClosure MarkSweep::mark_and_push_closure(ClassLoaderData::_claim_stw_fullgc_mark); -CLDToOopClosure MarkSweep::follow_cld_closure(&mark_and_push_closure, ClassLoaderData::_claim_stw_fullgc_mark); -CLDToOopClosure MarkSweep::adjust_cld_closure(&adjust_pointer_closure, ClassLoaderData::_claim_stw_fullgc_adjust); +MarkAndPushClosure SerialFullGC::mark_and_push_closure(ClassLoaderData::_claim_stw_fullgc_mark); +CLDToOopClosure SerialFullGC::follow_cld_closure(&mark_and_push_closure, ClassLoaderData::_claim_stw_fullgc_mark); +CLDToOopClosure SerialFullGC::adjust_cld_closure(&adjust_pointer_closure, ClassLoaderData::_claim_stw_fullgc_adjust); class DeadSpacer : StackObj { size_t _allowed_deadspace_words; @@ -97,7 +98,8 @@ class DeadSpacer : StackObj { public: DeadSpacer(ContiguousSpace* space) : _allowed_deadspace_words(0), _space(space) { - size_t ratio = _space->allowed_dead_ratio(); + size_t ratio = (_space == SerialHeap::heap()->old_gen()->space()) + ? MarkSweepDeadRatio : 0; _active = ratio > 0; if (_active) { @@ -105,7 +107,7 @@ class DeadSpacer : StackObj { // we don't start compacting before there is a significant gain to be made. // Occasionally, we want to ensure a full compaction, which is determined // by the MarkSweepAlwaysCompactCount parameter. - if ((MarkSweep::total_invocations() % MarkSweepAlwaysCompactCount) != 0) { + if ((SerialFullGC::total_invocations() % MarkSweepAlwaysCompactCount) != 0) { _allowed_deadspace_words = (space->capacity() * ratio / 100) / HeapWordSize; } else { _active = false; @@ -325,7 +327,7 @@ class Compacter { while (cur_addr < top) { prefetch_write_scan(cur_addr); if (cur_addr < first_dead || cast_to_oop(cur_addr)->is_gc_marked()) { - size_t size = MarkSweep::adjust_pointers(cast_to_oop(cur_addr)); + size_t size = SerialFullGC::adjust_pointers(cast_to_oop(cur_addr)); cur_addr += size; } else { assert(*(HeapWord**)cur_addr > cur_addr, "forward progress"); @@ -364,36 +366,36 @@ class Compacter { } }; -template void MarkSweep::KeepAliveClosure::do_oop_work(T* p) { +template void SerialFullGC::KeepAliveClosure::do_oop_work(T* p) { mark_and_push(p); } -void MarkSweep::push_objarray(oop obj, size_t index) { +void SerialFullGC::push_objarray(oop obj, size_t index) { ObjArrayTask task(obj, index); assert(task.is_valid(), "bad ObjArrayTask"); _objarray_stack.push(task); } -void MarkSweep::follow_array(objArrayOop array) { +void SerialFullGC::follow_array(objArrayOop array) { mark_and_push_closure.do_klass(array->klass()); // Don't push empty arrays to avoid unnecessary work. if (array->length() > 0) { - MarkSweep::push_objarray(array, 0); + SerialFullGC::push_objarray(array, 0); } } -void MarkSweep::follow_object(oop obj) { +void SerialFullGC::follow_object(oop obj) { assert(obj->is_gc_marked(), "should be marked"); if (obj->is_objArray()) { // Handle object arrays explicitly to allow them to // be split into chunks if needed. - MarkSweep::follow_array((objArrayOop)obj); + SerialFullGC::follow_array((objArrayOop)obj); } else { obj->oop_iterate(&mark_and_push_closure); } } -void MarkSweep::follow_array_chunk(objArrayOop array, int index) { +void SerialFullGC::follow_array_chunk(objArrayOop array, int index) { const int len = array->length(); const int beg_index = index; assert(beg_index < len || len == 0, "index too large"); @@ -404,11 +406,11 @@ void MarkSweep::follow_array_chunk(objArrayOop array, int index) { array->oop_iterate_range(&mark_and_push_closure, beg_index, end_index); if (end_index < len) { - MarkSweep::push_objarray(array, end_index); // Push the continuation. + SerialFullGC::push_objarray(array, end_index); // Push the continuation. } } -void MarkSweep::follow_stack() { +void SerialFullGC::follow_stack() { do { while (!_marking_stack.is_empty()) { oop obj = _marking_stack.pop(); @@ -423,11 +425,11 @@ void MarkSweep::follow_stack() { } while (!_marking_stack.is_empty() || !_objarray_stack.is_empty()); } -MarkSweep::FollowStackClosure MarkSweep::follow_stack_closure; +SerialFullGC::FollowStackClosure SerialFullGC::follow_stack_closure; -void MarkSweep::FollowStackClosure::do_void() { follow_stack(); } +void SerialFullGC::FollowStackClosure::do_void() { follow_stack(); } -template void MarkSweep::follow_root(T* p) { +template void SerialFullGC::follow_root(T* p) { assert(!Universe::heap()->is_in(p), "roots shouldn't be things within the heap"); T heap_oop = RawAccess<>::oop_load(p); @@ -441,13 +443,13 @@ template void MarkSweep::follow_root(T* p) { follow_stack(); } -void MarkSweep::FollowRootClosure::do_oop(oop* p) { follow_root(p); } -void MarkSweep::FollowRootClosure::do_oop(narrowOop* p) { follow_root(p); } +void SerialFullGC::FollowRootClosure::do_oop(oop* p) { follow_root(p); } +void SerialFullGC::FollowRootClosure::do_oop(narrowOop* p) { follow_root(p); } // We preserve the mark which should be replaced at the end and the location // that it will go. Note that the object that this markWord belongs to isn't // currently at that address but it will be after phase4 -void MarkSweep::preserve_mark(oop obj, markWord mark) { +void SerialFullGC::preserve_mark(oop obj, markWord mark) { // We try to store preserved marks in the to space of the new generation since // this is storage which should be available. Most of the time this should be // sufficient space for the marks we need to preserve but if it isn't we fall @@ -459,7 +461,7 @@ void MarkSweep::preserve_mark(oop obj, markWord mark) { } } -void MarkSweep::phase1_mark(bool clear_all_softrefs) { +void SerialFullGC::phase1_mark(bool clear_all_softrefs) { // Recursively traverse all live objects and mark them GCTraceTime(Info, gc, phases) tm("Phase 1: Mark live objects", _gc_timer); @@ -473,7 +475,7 @@ void MarkSweep::phase1_mark(bool clear_all_softrefs) { StrongRootsScope srs(0); CLDClosure* weak_cld_closure = ClassUnloading ? nullptr : &follow_cld_closure; - MarkingCodeBlobClosure mark_code_closure(&follow_root_closure, !CodeBlobToOopClosure::FixRelocations, true); + MarkingNMethodClosure mark_code_closure(&follow_root_closure, !NMethodToOopClosure::FixRelocations, true); gch->process_roots(SerialHeap::SO_None, &follow_root_closure, &follow_cld_closure, @@ -527,7 +529,7 @@ void MarkSweep::phase1_mark(bool clear_all_softrefs) { } { GCTraceTime(Debug, gc, phases) t("Free Code Blobs", gc_timer()); - ctx->free_code_blobs(); + ctx->free_nmethods(); } // Prune dead klasses from subklass/sibling/implementor lists. @@ -543,7 +545,7 @@ void MarkSweep::phase1_mark(bool clear_all_softrefs) { } } -void MarkSweep::allocate_stacks() { +void SerialFullGC::allocate_stacks() { void* scratch = nullptr; size_t num_words; DefNewGeneration* young_gen = (DefNewGeneration*)SerialHeap::heap()->young_gen(); @@ -561,7 +563,7 @@ void MarkSweep::allocate_stacks() { _preserved_overflow_stack_set.init(1); } -void MarkSweep::deallocate_stacks() { +void SerialFullGC::deallocate_stacks() { if (_preserved_count_max != 0) { DefNewGeneration* young_gen = (DefNewGeneration*)SerialHeap::heap()->young_gen(); young_gen->reset_scratch(); @@ -572,7 +574,7 @@ void MarkSweep::deallocate_stacks() { _objarray_stack.clear(true); } -void MarkSweep::mark_object(oop obj) { +void SerialFullGC::mark_object(oop obj) { if (StringDedup::is_enabled() && java_lang_String::is_instance(obj) && SerialStringDedup::is_candidate_from_mark(obj)) { @@ -580,7 +582,7 @@ void MarkSweep::mark_object(oop obj) { } // some marks may contain information we need to preserve so we store them away - // and overwrite the mark. We'll restore it at the end of markSweep. + // and overwrite the mark. We'll restore it at the end of serial full GC. markWord mark = obj->mark(); obj->set_mark(markWord::prototype().set_marked()); @@ -591,7 +593,7 @@ void MarkSweep::mark_object(oop obj) { } } -template void MarkSweep::mark_and_push(T* p) { +template void SerialFullGC::mark_and_push(T* p) { T heap_oop = RawAccess<>::oop_load(p); if (!CompressedOops::is_null(heap_oop)) { oop obj = CompressedOops::decode_not_null(heap_oop); @@ -603,13 +605,13 @@ template void MarkSweep::mark_and_push(T* p) { } template -void MarkAndPushClosure::do_oop_work(T* p) { MarkSweep::mark_and_push(p); } +void MarkAndPushClosure::do_oop_work(T* p) { SerialFullGC::mark_and_push(p); } void MarkAndPushClosure::do_oop( oop* p) { do_oop_work(p); } void MarkAndPushClosure::do_oop(narrowOop* p) { do_oop_work(p); } -AdjustPointerClosure MarkSweep::adjust_pointer_closure; +AdjustPointerClosure SerialFullGC::adjust_pointer_closure; -void MarkSweep::adjust_marks() { +void SerialFullGC::adjust_marks() { // adjust the oops we saved earlier for (size_t i = 0; i < _preserved_count; i++) { PreservedMarks::adjust_preserved_mark(_preserved_marks + i); @@ -619,7 +621,7 @@ void MarkSweep::adjust_marks() { _preserved_overflow_stack_set.get()->adjust_during_full_gc(); } -void MarkSweep::restore_marks() { +void SerialFullGC::restore_marks() { log_trace(gc)("Restoring " SIZE_FORMAT " marks", _preserved_count + _preserved_overflow_stack_set.get()->size()); // restore the marks we saved earlier @@ -631,27 +633,27 @@ void MarkSweep::restore_marks() { _preserved_overflow_stack_set.restore(nullptr); } -MarkSweep::IsAliveClosure MarkSweep::is_alive; +SerialFullGC::IsAliveClosure SerialFullGC::is_alive; -bool MarkSweep::IsAliveClosure::do_object_b(oop p) { return p->is_gc_marked(); } +bool SerialFullGC::IsAliveClosure::do_object_b(oop p) { return p->is_gc_marked(); } -MarkSweep::KeepAliveClosure MarkSweep::keep_alive; +SerialFullGC::KeepAliveClosure SerialFullGC::keep_alive; -void MarkSweep::KeepAliveClosure::do_oop(oop* p) { MarkSweep::KeepAliveClosure::do_oop_work(p); } -void MarkSweep::KeepAliveClosure::do_oop(narrowOop* p) { MarkSweep::KeepAliveClosure::do_oop_work(p); } +void SerialFullGC::KeepAliveClosure::do_oop(oop* p) { SerialFullGC::KeepAliveClosure::do_oop_work(p); } +void SerialFullGC::KeepAliveClosure::do_oop(narrowOop* p) { SerialFullGC::KeepAliveClosure::do_oop_work(p); } -void MarkSweep::initialize() { - MarkSweep::_gc_timer = new STWGCTimer(); - MarkSweep::_gc_tracer = new SerialOldTracer(); - MarkSweep::_string_dedup_requests = new StringDedup::Requests(); +void SerialFullGC::initialize() { + SerialFullGC::_gc_timer = new STWGCTimer(); + SerialFullGC::_gc_tracer = new SerialOldTracer(); + SerialFullGC::_string_dedup_requests = new StringDedup::Requests(); // The Full GC operates on the entire heap so all objects should be subject // to discovery, hence the _always_true_closure. - MarkSweep::_ref_processor = new ReferenceProcessor(&_always_true_closure); + SerialFullGC::_ref_processor = new ReferenceProcessor(&_always_true_closure); mark_and_push_closure.set_ref_discoverer(_ref_processor); } -void MarkSweep::invoke_at_safepoint(bool clear_all_softrefs) { +void SerialFullGC::invoke_at_safepoint(bool clear_all_softrefs) { assert(SafepointSynchronize::is_at_safepoint(), "must be at a safepoint"); SerialHeap* gch = SerialHeap::heap(); @@ -695,7 +697,7 @@ void MarkSweep::invoke_at_safepoint(bool clear_all_softrefs) { ClassLoaderDataGraph::verify_claimed_marks_cleared(ClassLoaderData::_claim_stw_fullgc_adjust); - CodeBlobToOopClosure code_closure(&adjust_pointer_closure, CodeBlobToOopClosure::FixRelocations); + NMethodToOopClosure code_closure(&adjust_pointer_closure, NMethodToOopClosure::FixRelocations); gch->process_roots(SerialHeap::SO_AllCodeCache, &adjust_pointer_closure, &adjust_cld_closure, @@ -723,7 +725,7 @@ void MarkSweep::invoke_at_safepoint(bool clear_all_softrefs) { deallocate_stacks(); - MarkSweep::_string_dedup_requests->flush(); + SerialFullGC::_string_dedup_requests->flush(); bool is_young_gen_empty = (gch->young_gen()->used() == 0); gch->rem_set()->maintain_old_to_young_invariant(gch->old_gen(), is_young_gen_empty); diff --git a/src/hotspot/share/gc/serial/markSweep.hpp b/src/hotspot/share/gc/serial/serialFullGC.hpp similarity index 92% rename from src/hotspot/share/gc/serial/markSweep.hpp rename to src/hotspot/share/gc/serial/serialFullGC.hpp index 72dddc69df7..fba41560e67 100644 --- a/src/hotspot/share/gc/serial/markSweep.hpp +++ b/src/hotspot/share/gc/serial/serialFullGC.hpp @@ -22,11 +22,11 @@ * */ -#ifndef SHARE_GC_SERIAL_MARKSWEEP_HPP -#define SHARE_GC_SERIAL_MARKSWEEP_HPP +#ifndef SHARE_GC_SERIAL_SERIALFULLGC_HPP +#define SHARE_GC_SERIAL_SERIALFULLGC_HPP #include "gc/shared/collectedHeap.hpp" -#include "gc/shared/preservedMarks.inline.hpp" +#include "gc/shared/preservedMarks.hpp" #include "gc/shared/referenceProcessor.hpp" #include "gc/shared/stringdedup/stringDedup.hpp" #include "gc/shared/taskqueue.hpp" @@ -37,11 +37,10 @@ #include "utilities/growableArray.hpp" #include "utilities/stack.hpp" -class DataLayout; class SerialOldTracer; class STWGCTimer; -// MarkSweep takes care of global mark-compact garbage collection for a +// Serial full GC takes care of global mark-compact garbage collection for a // SerialHeap using a four-phase pointer forwarding algorithm. All // generations are assumed to support marking; those that can also support // compaction. @@ -49,11 +48,10 @@ class STWGCTimer; // Class unloading will only occur when a full gc is invoked. // declared at end -class PreservedMark; class MarkAndPushClosure; class AdjustPointerClosure; -class MarkSweep : AllStatic { +class SerialFullGC : AllStatic { // // Inline closure decls // @@ -82,17 +80,8 @@ class MarkSweep : AllStatic { virtual void do_oop(narrowOop* p); }; - // - // Friend decls - // - friend class AdjustPointerClosure; - friend class KeepAliveClosure; - - // - // Vars - // protected: - // Total invocations of a MarkSweep collection + // Total invocations of serial full GC static uint _total_invocations; // Traversal stacks used during phase1 @@ -196,4 +185,4 @@ class AdjustPointerClosure: public BasicOopIterateClosure { virtual ReferenceIterationMode reference_iteration_mode() { return DO_FIELDS; } }; -#endif // SHARE_GC_SERIAL_MARKSWEEP_HPP +#endif // SHARE_GC_SERIAL_SERIALFULLGC_HPP diff --git a/src/hotspot/share/gc/serial/markSweep.inline.hpp b/src/hotspot/share/gc/serial/serialFullGC.inline.hpp similarity index 78% rename from src/hotspot/share/gc/serial/markSweep.inline.hpp rename to src/hotspot/share/gc/serial/serialFullGC.inline.hpp index 97283e98746..2984c49b3d5 100644 --- a/src/hotspot/share/gc/serial/markSweep.inline.hpp +++ b/src/hotspot/share/gc/serial/serialFullGC.inline.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 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,10 +22,10 @@ * */ -#ifndef SHARE_GC_SERIAL_MARKSWEEP_INLINE_HPP -#define SHARE_GC_SERIAL_MARKSWEEP_INLINE_HPP +#ifndef SHARE_GC_SERIAL_SERIALFULLGC_INLINE_HPP +#define SHARE_GC_SERIAL_SERIALFULLGC_INLINE_HPP -#include "gc/serial/markSweep.hpp" +#include "gc/serial/serialFullGC.hpp" #include "classfile/classLoaderData.inline.hpp" #include "classfile/javaClasses.inline.hpp" @@ -39,7 +39,7 @@ #include "utilities/align.hpp" #include "utilities/stack.inline.hpp" -template inline void MarkSweep::adjust_pointer(T* p) { +template inline void SerialFullGC::adjust_pointer(T* p) { T heap_oop = RawAccess<>::oop_load(p); if (!CompressedOops::is_null(heap_oop)) { oop obj = CompressedOops::decode_not_null(heap_oop); @@ -54,12 +54,12 @@ template inline void MarkSweep::adjust_pointer(T* p) { } template -void AdjustPointerClosure::do_oop_work(T* p) { MarkSweep::adjust_pointer(p); } +void AdjustPointerClosure::do_oop_work(T* p) { SerialFullGC::adjust_pointer(p); } inline void AdjustPointerClosure::do_oop(oop* p) { do_oop_work(p); } inline void AdjustPointerClosure::do_oop(narrowOop* p) { do_oop_work(p); } -inline size_t MarkSweep::adjust_pointers(oop obj) { - return obj->oop_iterate_size(&MarkSweep::adjust_pointer_closure); +inline size_t SerialFullGC::adjust_pointers(oop obj) { + return obj->oop_iterate_size(&SerialFullGC::adjust_pointer_closure); } -#endif // SHARE_GC_SERIAL_MARKSWEEP_INLINE_HPP +#endif // SHARE_GC_SERIAL_SERIALFULLGC_INLINE_HPP diff --git a/src/hotspot/share/gc/serial/serialHeap.cpp b/src/hotspot/share/gc/serial/serialHeap.cpp index 3497857255e..8c43239b201 100644 --- a/src/hotspot/share/gc/serial/serialHeap.cpp +++ b/src/hotspot/share/gc/serial/serialHeap.cpp @@ -31,7 +31,7 @@ #include "compiler/oopMap.hpp" #include "gc/serial/cardTableRS.hpp" #include "gc/serial/defNewGeneration.inline.hpp" -#include "gc/serial/markSweep.hpp" +#include "gc/serial/serialFullGC.hpp" #include "gc/serial/serialHeap.hpp" #include "gc/serial/serialMemoryPools.hpp" #include "gc/serial/serialVMOperations.hpp" @@ -249,7 +249,7 @@ void SerialHeap::post_initialize() { def_new_gen->ref_processor_init(); - MarkSweep::initialize(); + SerialFullGC::initialize(); ScavengableNMethods::initialize(&_is_scavengable); } @@ -560,7 +560,7 @@ void SerialHeap::do_collection(bool full, if (do_full_collection) { GCIdMark gc_id_mark; - GCTraceCPUTime tcpu(MarkSweep::gc_tracer()); + GCTraceCPUTime tcpu(SerialFullGC::gc_tracer()); GCTraceTime(Info, gc) t("Pause Full", nullptr, gc_cause(), true); print_heap_before_gc(); @@ -585,7 +585,7 @@ void SerialHeap::do_collection(bool full, ClassUnloadingContext ctx(1 /* num_nmethod_unlink_workers */, false /* unregister_nmethods_during_purge */, - false /* lock_codeblob_free_separately */); + false /* lock_nmethod_free_separately */); collect_generation(_old_gen, full, @@ -725,29 +725,18 @@ HeapWord* SerialHeap::satisfy_failed_allocation(size_t size, bool is_tlab) { return nullptr; } -#ifdef ASSERT -class AssertNonScavengableClosure: public OopClosure { -public: - virtual void do_oop(oop* p) { - assert(!SerialHeap::heap()->is_in_partial_collection(*p), - "Referent should not be scavengable."); } - virtual void do_oop(narrowOop* p) { ShouldNotReachHere(); } -}; -static AssertNonScavengableClosure assert_is_non_scavengable_closure; -#endif - void SerialHeap::process_roots(ScanningOption so, OopClosure* strong_roots, CLDClosure* strong_cld_closure, CLDClosure* weak_cld_closure, - CodeBlobToOopClosure* code_roots) { + NMethodToOopClosure* code_roots) { // General roots. assert(code_roots != nullptr, "code root closure should always be set"); ClassLoaderDataGraph::roots_cld_do(strong_cld_closure, weak_cld_closure); // Only process code roots from thread stacks if we aren't visiting the entire CodeCache anyway - CodeBlobToOopClosure* roots_from_code_p = (so & SO_AllCodeCache) ? nullptr : code_roots; + NMethodToOopClosure* roots_from_code_p = (so & SO_AllCodeCache) ? nullptr : code_roots; Threads::oops_do(strong_roots, roots_from_code_p); @@ -764,12 +753,8 @@ void SerialHeap::process_roots(ScanningOption so, // CMSCollector uses this to do intermediate-strength collections. // We scan the entire code cache, since CodeCache::do_unloading is not called. - CodeCache::blobs_do(code_roots); + CodeCache::nmethods_do(code_roots); } - // Verify that the code cache contents are not subject to - // movement by a scavenging collection. - DEBUG_ONLY(CodeBlobToOopClosure assert_code_is_non_scavengable(&assert_is_non_scavengable_closure, !CodeBlobToOopClosure::FixRelocations)); - DEBUG_ONLY(ScavengableNMethods::asserted_non_scavengable_nmethods_do(&assert_code_is_non_scavengable)); } bool SerialHeap::no_allocs_since_save_marks() { @@ -869,16 +854,6 @@ bool SerialHeap::is_in(const void* p) const { return _young_gen->is_in(p) || _old_gen->is_in(p); } -#ifdef ASSERT -// Don't implement this by using is_in_young(). This method is used -// in some cases to check that is_in_young() is correct. -bool SerialHeap::is_in_partial_collection(const void* p) { - assert(is_in_reserved(p) || p == nullptr, - "Does not work if address is non-null and outside of the heap"); - return p < _young_gen->reserved().end() && p != nullptr; -} -#endif - void SerialHeap::object_iterate(ObjectClosure* cl) { _young_gen->object_iterate(cl); _old_gen->object_iterate(cl); diff --git a/src/hotspot/share/gc/serial/serialHeap.hpp b/src/hotspot/share/gc/serial/serialHeap.hpp index f780b55ac68..54a776406fa 100644 --- a/src/hotspot/share/gc/serial/serialHeap.hpp +++ b/src/hotspot/share/gc/serial/serialHeap.hpp @@ -66,7 +66,7 @@ class SerialHeap : public CollectedHeap { friend class Generation; friend class DefNewGeneration; friend class TenuredGeneration; - friend class MarkSweep; + friend class SerialFullGC; friend class VM_GenCollectForAllocation; friend class VM_GenCollectFull; friend class VM_GC_HeapInspection; @@ -178,10 +178,6 @@ class SerialHeap : public CollectedHeap { bool requires_barriers(stackChunkOop obj) const override; -#ifdef ASSERT - bool is_in_partial_collection(const void* p); -#endif - // Optimized nmethod scanning support routines void register_nmethod(nmethod* nm) override; void unregister_nmethod(nmethod* nm) override; @@ -276,7 +272,7 @@ class SerialHeap : public CollectedHeap { OopClosure* strong_roots, CLDClosure* strong_cld_closure, CLDClosure* weak_cld_closure, - CodeBlobToOopClosure* code_roots); + NMethodToOopClosure* code_roots); // Set the saved marks of generations, if that makes sense. // In particular, if any generation might iterate over the oops diff --git a/src/hotspot/share/gc/serial/tenuredGeneration.cpp b/src/hotspot/share/gc/serial/tenuredGeneration.cpp index e9382ec88cb..d6a1a4a6910 100644 --- a/src/hotspot/share/gc/serial/tenuredGeneration.cpp +++ b/src/hotspot/share/gc/serial/tenuredGeneration.cpp @@ -24,8 +24,8 @@ #include "precompiled.hpp" #include "gc/serial/cardTableRS.hpp" -#include "gc/serial/markSweep.hpp" #include "gc/serial/serialBlockOffsetTable.inline.hpp" +#include "gc/serial/serialFullGC.hpp" #include "gc/serial/serialHeap.hpp" #include "gc/serial/tenuredGeneration.inline.hpp" #include "gc/shared/collectorCounters.hpp" @@ -37,6 +37,7 @@ #include "memory/allocation.inline.hpp" #include "oops/oop.inline.hpp" #include "runtime/java.hpp" +#include "utilities/copy.hpp" #include "utilities/macros.hpp" bool TenuredGeneration::grow_by(size_t bytes) { @@ -268,7 +269,7 @@ HeapWord* TenuredGeneration::block_start(const void* p) const { } void TenuredGeneration::scan_old_to_young_refs() { - _rs->scan_old_to_young_refs(space()); + _rs->scan_old_to_young_refs(space(), saved_mark_word()); } TenuredGeneration::TenuredGeneration(ReservedSpace rs, @@ -444,15 +445,15 @@ void TenuredGeneration::collect(bool full, bool is_tlab) { SerialHeap* gch = SerialHeap::heap(); - STWGCTimer* gc_timer = MarkSweep::gc_timer(); + STWGCTimer* gc_timer = SerialFullGC::gc_timer(); gc_timer->register_gc_start(); - SerialOldTracer* gc_tracer = MarkSweep::gc_tracer(); + SerialOldTracer* gc_tracer = SerialFullGC::gc_tracer(); gc_tracer->report_gc_start(gch->gc_cause(), gc_timer->gc_start()); gch->pre_full_gc_dump(gc_timer); - MarkSweep::invoke_at_safepoint(clear_all_soft_refs); + SerialFullGC::invoke_at_safepoint(clear_all_soft_refs); gch->post_full_gc_dump(gc_timer); @@ -492,11 +493,11 @@ void TenuredGeneration::complete_loaded_archive_space(MemRegion archive_space) { } void TenuredGeneration::save_marks() { - _the_space->set_saved_mark(); + set_saved_mark_word(); } bool TenuredGeneration::no_allocs_since_save_marks() { - return _the_space->saved_mark_at_top(); + return saved_mark_at_top(); } void TenuredGeneration::gc_epilogue() { diff --git a/src/hotspot/share/gc/serial/tenuredGeneration.hpp b/src/hotspot/share/gc/serial/tenuredGeneration.hpp index c0c3c7fcf60..9983790b82e 100644 --- a/src/hotspot/share/gc/serial/tenuredGeneration.hpp +++ b/src/hotspot/share/gc/serial/tenuredGeneration.hpp @@ -66,6 +66,7 @@ class TenuredGeneration: public Generation { void assert_correct_size_change_locking(); TenuredSpace* _the_space; // Actual space holding objects + HeapWord* _saved_mark_word; GenerationCounters* _gen_counters; CSpaceCounters* _space_counters; @@ -88,6 +89,9 @@ class TenuredGeneration: public Generation { void compute_new_size(); TenuredSpace* space() const { return _the_space; } + HeapWord* saved_mark_word() const { return _saved_mark_word; } + void set_saved_mark_word() { _saved_mark_word = _the_space->top(); } + bool saved_mark_at_top() { return _saved_mark_word == space()->top(); } // Grow generation with specified size (returns false if unable to grow) bool grow_by(size_t bytes); diff --git a/src/hotspot/share/gc/serial/tenuredGeneration.inline.hpp b/src/hotspot/share/gc/serial/tenuredGeneration.inline.hpp index 25d57a76282..d03c97fc508 100644 --- a/src/hotspot/share/gc/serial/tenuredGeneration.inline.hpp +++ b/src/hotspot/share/gc/serial/tenuredGeneration.inline.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 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,8 @@ HeapWord* TenuredGeneration::par_allocate(size_t word_size, template void TenuredGeneration::oop_since_save_marks_iterate(OopClosureType* blk) { - _the_space->oop_since_save_marks_iterate(blk); + Generation::oop_since_save_marks_iterate_impl(blk, _the_space, _saved_mark_word); + set_saved_mark_word(); } #endif // SHARE_GC_SERIAL_TENUREDGENERATION_INLINE_HPP diff --git a/src/hotspot/share/gc/shared/barrierSet.hpp b/src/hotspot/share/gc/shared/barrierSet.hpp index e171316fdcc..e713a4fca2f 100644 --- a/src/hotspot/share/gc/shared/barrierSet.hpp +++ b/src/hotspot/share/gc/shared/barrierSet.hpp @@ -142,7 +142,6 @@ class BarrierSet: public CHeapObj { virtual void make_parsable(JavaThread* thread) {} -public: // Print a description of the memory for the barrier set virtual void print_on(outputStream* st) const = 0; diff --git a/src/hotspot/share/gc/shared/cardTableBarrierSet.hpp b/src/hotspot/share/gc/shared/cardTableBarrierSet.hpp index 9d9d379cafe..c650e2a1fd9 100644 --- a/src/hotspot/share/gc/shared/cardTableBarrierSet.hpp +++ b/src/hotspot/share/gc/shared/cardTableBarrierSet.hpp @@ -45,10 +45,8 @@ class CardTableBarrierSet: public ModRefBarrierSet { // Some classes get to look at some private stuff. friend class VMStructs; -public: - - typedef CardTable::CardValue CardValue; protected: + typedef CardTable::CardValue CardValue; // Used in support of ReduceInitialCardMarks; only consulted if COMPILER2 // or INCLUDE_JVMCI is being used bool _defer_initial_card_mark; diff --git a/src/hotspot/share/gc/shared/classUnloadingContext.cpp b/src/hotspot/share/gc/shared/classUnloadingContext.cpp index 6d9674ef801..bd5fb2ff3d7 100644 --- a/src/hotspot/share/gc/shared/classUnloadingContext.cpp +++ b/src/hotspot/share/gc/shared/classUnloadingContext.cpp @@ -34,12 +34,12 @@ ClassUnloadingContext* ClassUnloadingContext::_context = nullptr; ClassUnloadingContext::ClassUnloadingContext(uint num_workers, bool unregister_nmethods_during_purge, - bool lock_codeblob_free_separately) : + bool lock_nmethod_free_separately) : _cld_head(nullptr), _num_nmethod_unlink_workers(num_workers), _unlinked_nmethods(nullptr), _unregister_nmethods_during_purge(unregister_nmethods_during_purge), - _lock_codeblob_free_separately(lock_codeblob_free_separately) { + _lock_nmethod_free_separately(lock_nmethod_free_separately) { assert(_context == nullptr, "context already set"); _context = this; @@ -123,7 +123,7 @@ void ClassUnloadingContext::purge_nmethods() { CodeCache::maybe_restart_compiler(freed_memory); } -void ClassUnloadingContext::free_code_blobs() { +void ClassUnloadingContext::free_nmethods() { assert(_context != nullptr, "no context set"); // Sort nmethods before freeing to benefit from optimizations. If Nmethods were @@ -159,7 +159,7 @@ void ClassUnloadingContext::free_code_blobs() { nmethod_set->sort(sort_nmethods); // And free. Duplicate loop for clarity depending on where we want the locking. - if (_lock_codeblob_free_separately) { + if (_lock_nmethod_free_separately) { for (nmethod* nm : *nmethod_set) { MutexLocker ml(CodeCache_lock, Mutex::_no_safepoint_check_flag); CodeCache::free(nm); diff --git a/src/hotspot/share/gc/shared/classUnloadingContext.hpp b/src/hotspot/share/gc/shared/classUnloadingContext.hpp index 30930967d38..fa1acb89da7 100644 --- a/src/hotspot/share/gc/shared/classUnloadingContext.hpp +++ b/src/hotspot/share/gc/shared/classUnloadingContext.hpp @@ -43,7 +43,7 @@ class ClassUnloadingContext : public CHeapObj { NMethodSet** _unlinked_nmethods; bool _unregister_nmethods_during_purge; - bool _lock_codeblob_free_separately; + bool _lock_nmethod_free_separately; public: static ClassUnloadingContext* context() { assert(_context != nullptr, "context not set"); return _context; } @@ -53,12 +53,12 @@ class ClassUnloadingContext : public CHeapObj { // unregister_nmethods_during_purge determines whether unloaded nmethods should // be unregistered from the garbage collector during purge. If not, ,the caller // is responsible to do that later. - // lock_codeblob_free_separately determines whether freeing the code blobs takes - // the CodeCache_lock during the whole operation (=false) or per code blob + // lock_nmethod_free_separately determines whether freeing the nmethods takes + // the CodeCache_lock during the whole operation (=false) or per nmethod // free operation (=true). ClassUnloadingContext(uint num_nmethod_unlink_workers, bool unregister_nmethods_during_purge, - bool lock_codeblob_free_separately); + bool lock_nmethod_free_separately); ~ClassUnloadingContext(); bool has_unloaded_classes() const; @@ -71,11 +71,11 @@ class ClassUnloadingContext : public CHeapObj { // Register unloading nmethods, potentially in parallel. void register_unlinked_nmethod(nmethod* nm); void purge_nmethods(); - void free_code_blobs(); + void free_nmethods(); void purge_and_free_nmethods() { purge_nmethods(); - free_code_blobs(); + free_nmethods(); } }; diff --git a/src/hotspot/share/gc/shared/collectedHeap.cpp b/src/hotspot/share/gc/shared/collectedHeap.cpp index d1291e35bfc..2e79d6c567c 100644 --- a/src/hotspot/share/gc/shared/collectedHeap.cpp +++ b/src/hotspot/share/gc/shared/collectedHeap.cpp @@ -229,7 +229,7 @@ bool CollectedHeap::is_oop(oop object) const { return false; } - if (!Metaspace::contains(object->klass_raw())) { + if (!Metaspace::contains(object->klass_without_asserts())) { return false; } @@ -462,7 +462,7 @@ CollectedHeap::fill_with_array(HeapWord* start, size_t words, bool zap) const size_t len = payload_size * HeapWordSize / sizeof(jint); assert((int)len >= 0, "size too large " SIZE_FORMAT " becomes %d", words, (int)len); - ObjArrayAllocator allocator(Universe::fillerArrayKlassObj(), words, (int)len, /* do_zero */ false); + ObjArrayAllocator allocator(Universe::fillerArrayKlass(), words, (int)len, /* do_zero */ false); allocator.initialize(start); if (CDSConfig::is_dumping_heap()) { // This array is written into the CDS archive. Make sure it diff --git a/src/hotspot/share/gc/shared/gcBehaviours.cpp b/src/hotspot/share/gc/shared/gcBehaviours.cpp index 76d28d1ab75..b52ef9e7d3d 100644 --- a/src/hotspot/share/gc/shared/gcBehaviours.cpp +++ b/src/hotspot/share/gc/shared/gcBehaviours.cpp @@ -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 @@ -23,19 +23,18 @@ */ #include "precompiled.hpp" -#include "code/compiledMethod.hpp" #include "code/nmethod.hpp" #include "gc/shared/gcBehaviours.hpp" IsUnloadingBehaviour* IsUnloadingBehaviour::_current = nullptr; -bool IsUnloadingBehaviour::is_unloading(CompiledMethod* cm) { - if (cm->method()->can_be_allocated_in_NonNMethod_space()) { +bool IsUnloadingBehaviour::is_unloading(nmethod* nm) { + if (nm->method()->can_be_allocated_in_NonNMethod_space()) { // When the nmethod is in NonNMethod space, we may reach here without IsUnloadingBehaviour. // However, we only allow this for special methods which never get unloaded. return false; } - return _current->has_dead_oop(cm) || cm->as_nmethod()->is_cold(); + return _current->has_dead_oop(nm) || nm->is_cold(); } class IsCompiledMethodUnloadingOopClosure: public OopClosure { @@ -70,12 +69,8 @@ class IsCompiledMethodUnloadingOopClosure: public OopClosure { } }; -bool ClosureIsUnloadingBehaviour::has_dead_oop(CompiledMethod* cm) const { - if (cm->is_nmethod()) { - IsCompiledMethodUnloadingOopClosure cl(_cl); - static_cast(cm)->oops_do(&cl, true /* allow_dead */); - return cl.is_unloading(); - } else { - return false; - } +bool ClosureIsUnloadingBehaviour::has_dead_oop(nmethod* nm) const { + IsCompiledMethodUnloadingOopClosure cl(_cl); + nm->oops_do(&cl, true /* allow_dead */); + return cl.is_unloading(); } diff --git a/src/hotspot/share/gc/shared/gcBehaviours.hpp b/src/hotspot/share/gc/shared/gcBehaviours.hpp index 6265123f0f6..59f2a3e7460 100644 --- a/src/hotspot/share/gc/shared/gcBehaviours.hpp +++ b/src/hotspot/share/gc/shared/gcBehaviours.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2019, 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 @@ -28,14 +28,14 @@ #include "memory/iterator.hpp" #include "oops/oopsHierarchy.hpp" -// This is the behaviour for checking if a CompiledMethod is unloading +// This is the behaviour for checking if an nmethod is unloading // or has unloaded due to having phantomly dead oops in it after a GC. class IsUnloadingBehaviour { static IsUnloadingBehaviour* _current; public: - static bool is_unloading(CompiledMethod* cm); - virtual bool has_dead_oop(CompiledMethod* cm) const = 0; + static bool is_unloading(nmethod* nm); + virtual bool has_dead_oop(nmethod* nm) const = 0; static IsUnloadingBehaviour* current() { return _current; } static void set_current(IsUnloadingBehaviour* current) { _current = current; } }; @@ -48,7 +48,7 @@ class ClosureIsUnloadingBehaviour: public IsUnloadingBehaviour { : _cl(is_alive) { } - virtual bool has_dead_oop(CompiledMethod* cm) const; + virtual bool has_dead_oop(nmethod* nm) const; }; #endif // SHARE_GC_SHARED_GCBEHAVIOURS_HPP diff --git a/src/hotspot/share/gc/shared/gc_globals.hpp b/src/hotspot/share/gc/shared/gc_globals.hpp index 35e1aadcd7c..a3a1b03dfb9 100644 --- a/src/hotspot/share/gc/shared/gc_globals.hpp +++ b/src/hotspot/share/gc/shared/gc_globals.hpp @@ -500,9 +500,6 @@ product(bool, VerifyRememberedSets, false, DIAGNOSTIC, \ "Verify GC remembered sets") \ \ - product(bool, VerifyObjectStartArray, true, DIAGNOSTIC, \ - "Verify GC object start array if verify before/after") \ - \ product(bool, DisableExplicitGC, false, \ "Ignore calls to System.gc()") \ \ diff --git a/src/hotspot/share/gc/shared/locationPrinter.cpp b/src/hotspot/share/gc/shared/locationPrinter.cpp index abe1862e9dc..69fad87a097 100644 --- a/src/hotspot/share/gc/shared/locationPrinter.cpp +++ b/src/hotspot/share/gc/shared/locationPrinter.cpp @@ -28,6 +28,7 @@ #include "memory/universe.hpp" #include "runtime/os.hpp" #include "oops/klass.hpp" +#include "oops/oop.inline.hpp" bool LocationPrinter::is_valid_obj(void* obj) { if (!is_object_aligned(obj)) { @@ -45,6 +46,6 @@ bool LocationPrinter::is_valid_obj(void* obj) { return false; } - Klass* k = (Klass*)oopDesc::load_klass_raw((oopDesc*)obj); + Klass* k = ((oopDesc*)obj)->klass_without_asserts(); return Klass::is_valid(k); } diff --git a/src/hotspot/share/gc/shared/parallelCleaning.cpp b/src/hotspot/share/gc/shared/parallelCleaning.cpp index ef82c8b676e..3671500995e 100644 --- a/src/hotspot/share/gc/shared/parallelCleaning.cpp +++ b/src/hotspot/share/gc/shared/parallelCleaning.cpp @@ -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 @@ -38,7 +38,7 @@ CodeCacheUnloadingTask::CodeCacheUnloadingTask(uint num_workers, bool unloading_ _first_nmethod(nullptr), _claimed_nmethod(nullptr) { // Get first alive nmethod - CompiledMethodIterator iter(CompiledMethodIterator::all_blobs); + NMethodIterator iter(NMethodIterator::all); if(iter.next()) { _first_nmethod = iter.method(); } @@ -49,15 +49,15 @@ CodeCacheUnloadingTask::~CodeCacheUnloadingTask() { CodeCache::verify_clean_inline_caches(); } -void CodeCacheUnloadingTask::claim_nmethods(CompiledMethod** claimed_nmethods, int *num_claimed_nmethods) { - CompiledMethod* first; - CompiledMethodIterator last(CompiledMethodIterator::all_blobs); +void CodeCacheUnloadingTask::claim_nmethods(nmethod** claimed_nmethods, int *num_claimed_nmethods) { + nmethod* first; + NMethodIterator last(NMethodIterator::all); do { *num_claimed_nmethods = 0; first = _claimed_nmethod; - last = CompiledMethodIterator(CompiledMethodIterator::all_blobs, first); + last = NMethodIterator(NMethodIterator::all, first); if (first != nullptr) { @@ -81,7 +81,7 @@ void CodeCacheUnloadingTask::work(uint worker_id) { } int num_claimed_nmethods; - CompiledMethod* claimed_nmethods[MaxClaimNmethods]; + nmethod* claimed_nmethods[MaxClaimNmethods]; while (true) { claim_nmethods(claimed_nmethods, &num_claimed_nmethods); diff --git a/src/hotspot/share/gc/shared/parallelCleaning.hpp b/src/hotspot/share/gc/shared/parallelCleaning.hpp index f734a819259..a15326f1b85 100644 --- a/src/hotspot/share/gc/shared/parallelCleaning.hpp +++ b/src/hotspot/share/gc/shared/parallelCleaning.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2021, 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 @@ -36,8 +36,8 @@ class CodeCacheUnloadingTask { const uint _num_workers; // Variables used to claim nmethods. - CompiledMethod* _first_nmethod; - CompiledMethod* volatile _claimed_nmethod; + nmethod* _first_nmethod; + nmethod* volatile _claimed_nmethod; public: CodeCacheUnloadingTask(uint num_workers, bool unloading_occurred); @@ -45,7 +45,7 @@ class CodeCacheUnloadingTask { private: static const int MaxClaimNmethods = 16; - void claim_nmethods(CompiledMethod** claimed_nmethods, int *num_claimed_nmethods); + void claim_nmethods(nmethod** claimed_nmethods, int *num_claimed_nmethods); public: // Cleaning and unloading of nmethods. diff --git a/src/hotspot/share/gc/shared/scavengableNMethods.cpp b/src/hotspot/share/gc/shared/scavengableNMethods.cpp index 6c8e6259b11..c619ddb764a 100644 --- a/src/hotspot/share/gc/shared/scavengableNMethods.cpp +++ b/src/hotspot/share/gc/shared/scavengableNMethods.cpp @@ -129,7 +129,7 @@ bool ScavengableNMethods::has_scavengable_oops(nmethod* nm) { } // Walk the list of methods which might contain oops to the java heap. -void ScavengableNMethods::nmethods_do_and_prune(CodeBlobToOopClosure* cl) { +void ScavengableNMethods::nmethods_do_and_prune(NMethodToOopClosure* cl) { assert_locked_or_safepoint(CodeCache_lock); debug_only(mark_on_list_nmethods()); @@ -142,7 +142,7 @@ void ScavengableNMethods::nmethods_do_and_prune(CodeBlobToOopClosure* cl) { assert(data.on_list(), "else shouldn't be on this list"); if (cl != nullptr) { - cl->do_code_blob(cur); + cl->do_nmethod(cur); } nmethod* const next = data.next(); @@ -157,7 +157,7 @@ void ScavengableNMethods::nmethods_do_and_prune(CodeBlobToOopClosure* cl) { } // Check for stray marks. - debug_only(verify_unlisted_nmethods(nullptr)); + debug_only(verify_nmethods()); } void ScavengableNMethods::prune_nmethods_not_into_young() { @@ -188,26 +188,14 @@ void ScavengableNMethods::prune_unlinked_nmethods() { } // Check for stray marks. - debug_only(verify_unlisted_nmethods(nullptr)); + debug_only(verify_nmethods()); } // Walk the list of methods which might contain oops to the java heap. -void ScavengableNMethods::nmethods_do(CodeBlobToOopClosure* cl) { +void ScavengableNMethods::nmethods_do(NMethodToOopClosure* cl) { nmethods_do_and_prune(cl); } -#ifndef PRODUCT -void ScavengableNMethods::asserted_non_scavengable_nmethods_do(CodeBlobClosure* cl) { - // While we are here, verify the integrity of the list. - mark_on_list_nmethods(); - for (nmethod* cur = _head; cur != nullptr; cur = gc_data(cur).next()) { - assert(gc_data(cur).on_list(), "else shouldn't be on this list"); - gc_data(cur).clear_marked(); - } - verify_unlisted_nmethods(cl); -} -#endif // PRODUCT - void ScavengableNMethods::unlist_nmethod(nmethod* nm, nmethod* prev) { assert_locked_or_safepoint(CodeCache_lock); @@ -228,7 +216,7 @@ void ScavengableNMethods::unlist_nmethod(nmethod* nm, nmethod* prev) { #ifndef PRODUCT // Temporarily mark nmethods that are claimed to be on the scavenge list. void ScavengableNMethods::mark_on_list_nmethods() { - NMethodIterator iter(NMethodIterator::all_blobs); + NMethodIterator iter(NMethodIterator::all); while(iter.next()) { nmethod* nm = iter.method(); ScavengableNMethodsData data = gc_data(nm); @@ -239,10 +227,9 @@ void ScavengableNMethods::mark_on_list_nmethods() { } } -// If the closure is given, run it on the unlisted nmethods. -// Also make sure that the effects of mark_on_list_nmethods is gone. -void ScavengableNMethods::verify_unlisted_nmethods(CodeBlobClosure* cl) { - NMethodIterator iter(NMethodIterator::all_blobs); +// Make sure that the effects of mark_on_list_nmethods is gone. +void ScavengableNMethods::verify_nmethods() { + NMethodIterator iter(NMethodIterator::all); while(iter.next()) { nmethod* nm = iter.method(); @@ -250,10 +237,6 @@ void ScavengableNMethods::verify_unlisted_nmethods(CodeBlobClosure* cl) { if (!nm->is_unlinked()) { verify_nmethod(nm); } - - if (cl != nullptr && !gc_data(nm).on_list()) { - cl->do_code_blob(nm); - } } } diff --git a/src/hotspot/share/gc/shared/scavengableNMethods.hpp b/src/hotspot/share/gc/shared/scavengableNMethods.hpp index 94d594cd529..344575f045e 100644 --- a/src/hotspot/share/gc/shared/scavengableNMethods.hpp +++ b/src/hotspot/share/gc/shared/scavengableNMethods.hpp @@ -29,9 +29,8 @@ #include "utilities/macros.hpp" class BoolObjectClosure; -class CodeBlobClosure; -class CodeBlobToOopClosure; class nmethod; +class NMethodToOopClosure; class ScavengableNMethods : public AllStatic { friend class VMStructs; @@ -53,18 +52,16 @@ class ScavengableNMethods : public AllStatic { // Apply closure to every scavengable nmethod. // Remove nmethods that no longer have scavengable oops. - static void nmethods_do(CodeBlobToOopClosure* cl); - - static void asserted_non_scavengable_nmethods_do(CodeBlobClosure* cl) PRODUCT_RETURN; + static void nmethods_do(NMethodToOopClosure* cl); private: - static void nmethods_do_and_prune(CodeBlobToOopClosure* cl); + static void nmethods_do_and_prune(NMethodToOopClosure* cl); static void unlist_nmethod(nmethod* nm, nmethod* prev); static bool has_scavengable_oops(nmethod* nm); static void mark_on_list_nmethods() PRODUCT_RETURN; - static void verify_unlisted_nmethods(CodeBlobClosure* cl) PRODUCT_RETURN; + static void verify_nmethods() PRODUCT_RETURN; }; #endif // SHARE_GC_SHARED_SCAVENGABLENMETHODS_HPP diff --git a/src/hotspot/share/gc/shared/space.cpp b/src/hotspot/share/gc/shared/space.cpp index 6ab5eec200e..f5622cd64de 100644 --- a/src/hotspot/share/gc/shared/space.cpp +++ b/src/hotspot/share/gc/shared/space.cpp @@ -69,7 +69,6 @@ void ContiguousSpace::initialize(MemRegion mr, void ContiguousSpace::clear(bool mangle_space) { set_top(bottom()); - set_saved_mark(); if (ZapUnusedHeapArea && mangle_space) { mangle_unused_area(); } @@ -214,8 +213,4 @@ TenuredSpace::TenuredSpace(SerialBlockOffsetTable* offsets, { initialize(mr, SpaceDecorator::Clear, SpaceDecorator::Mangle); } - -size_t TenuredSpace::allowed_dead_ratio() const { - return MarkSweepDeadRatio; -} #endif // INCLUDE_SERIALGC diff --git a/src/hotspot/share/gc/shared/space.hpp b/src/hotspot/share/gc/shared/space.hpp index d0a6348d50d..a4679b3adad 100644 --- a/src/hotspot/share/gc/shared/space.hpp +++ b/src/hotspot/share/gc/shared/space.hpp @@ -65,9 +65,6 @@ class ContiguousSpace: public CHeapObj { HeapWord* _bottom; HeapWord* _end; - // Used in support of save_marks() - HeapWord* _saved_mark_word; - ContiguousSpace* _next_compaction_space; HeapWord* _top; @@ -90,20 +87,6 @@ class ContiguousSpace: public CHeapObj { void set_bottom(HeapWord* value) { _bottom = value; } void set_end(HeapWord* value) { _end = value; } - HeapWord* saved_mark_word() const { return _saved_mark_word; } - - // Returns a region that is guaranteed to contain (at least) all objects - // allocated at the time of the last call to "save_marks". If the space - // initializes its DirtyCardToOopClosure's specifying the "contig" option - // (that is, if the space is contiguous), then this region must contain only - // such objects: the memregion will be from the bottom of the region to the - // saved mark. Otherwise, the "obj_allocated_since_save_marks" method of - // the space must distinguish between objects in the region allocated before - // and after the call to save marks. - MemRegion used_region_at_save_marks() const { - return MemRegion(bottom(), saved_mark_word()); - } - // Testers bool is_empty() const { return used() == 0; } @@ -152,18 +135,10 @@ class ContiguousSpace: public CHeapObj { _next_compaction_space = csp; } - // The maximum percentage of objects that can be dead in the compacted - // live part of a compacted space ("deadwood" support.) - virtual size_t allowed_dead_ratio() const { return 0; }; - // Accessors HeapWord* top() const { return _top; } void set_top(HeapWord* value) { _top = value; } - void set_saved_mark() { _saved_mark_word = top(); } - - bool saved_mark_at_top() const { return saved_mark_word() == top(); } - // Used to save the space's current top for later use during mangling. void set_top_for_allocations() PRODUCT_RETURN; @@ -194,16 +169,6 @@ class ContiguousSpace: public CHeapObj { // Iteration void object_iterate(ObjectClosure* blk); - // Apply "blk->do_oop" to the addresses of all reference fields in objects - // starting with the _saved_mark_word, which was noted during a generation's - // save_marks and is required to denote the head of an object. - // Fields in objects allocated by applications of the closure - // *are* included in the iteration. - // Updates _saved_mark_word to point to just after the last object - // iterated over. - template - void oop_since_save_marks_iterate(OopClosureType* blk); - // If "p" is in the space, returns the address of the start of the // "block" that contains "p". We say "block" instead of "object" since // some heaps may not pack objects densely; a chunk may either be an @@ -227,8 +192,6 @@ class TenuredSpace: public ContiguousSpace { protected: SerialBlockOffsetTable* _offsets; - // Mark sweep support - size_t allowed_dead_ratio() const override; public: // Constructor TenuredSpace(SerialBlockOffsetTable* offsets, diff --git a/src/hotspot/share/gc/shared/space.inline.hpp b/src/hotspot/share/gc/shared/space.inline.hpp index e73a7b478bf..741263e668a 100644 --- a/src/hotspot/share/gc/shared/space.inline.hpp +++ b/src/hotspot/share/gc/shared/space.inline.hpp @@ -56,23 +56,4 @@ inline void TenuredSpace::update_for_block(HeapWord* start, HeapWord* end) { } #endif // INCLUDE_SERIALGC -template -void ContiguousSpace::oop_since_save_marks_iterate(OopClosureType* blk) { - HeapWord* t; - HeapWord* p = saved_mark_word(); - assert(p != nullptr, "expected saved mark"); - - const intx interval = PrefetchScanIntervalInBytes; - do { - t = top(); - while (p < t) { - Prefetch::write(p, interval); - oop m = cast_to_oop(p); - p += m->oop_iterate_size(blk); - } - } while (t < top()); - - set_saved_mark(); -} - #endif // SHARE_GC_SHARED_SPACE_INLINE_HPP diff --git a/src/hotspot/share/gc/shared/vmStructs_gc.hpp b/src/hotspot/share/gc/shared/vmStructs_gc.hpp index d932b195695..4c1d7b6b2aa 100644 --- a/src/hotspot/share/gc/shared/vmStructs_gc.hpp +++ b/src/hotspot/share/gc/shared/vmStructs_gc.hpp @@ -100,7 +100,6 @@ nonstatic_field(ContiguousSpace, _bottom, HeapWord*) \ nonstatic_field(ContiguousSpace, _end, HeapWord*) \ nonstatic_field(ContiguousSpace, _top, HeapWord*) \ - nonstatic_field(ContiguousSpace, _saved_mark_word, HeapWord*) \ \ nonstatic_field(MemRegion, _start, HeapWord*) \ nonstatic_field(MemRegion, _word_size, size_t) diff --git a/src/hotspot/share/gc/shenandoah/shenandoahClosures.hpp b/src/hotspot/share/gc/shenandoah/shenandoahClosures.hpp index cba3be0311c..51903a60fb4 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahClosures.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahClosures.hpp @@ -119,13 +119,13 @@ class ShenandoahCleanUpdateWeakOopsClosure : public OopClosure { inline void do_oop(narrowOop* p); }; -class ShenandoahCodeBlobAndDisarmClosure: public CodeBlobToOopClosure { +class ShenandoahNMethodAndDisarmClosure: public NMethodToOopClosure { private: BarrierSetNMethod* const _bs; public: - inline ShenandoahCodeBlobAndDisarmClosure(OopClosure* cl); - inline void do_code_blob(CodeBlob* cb); + inline ShenandoahNMethodAndDisarmClosure(OopClosure* cl); + inline void do_nmethod(nmethod* nm); }; #ifdef ASSERT diff --git a/src/hotspot/share/gc/shenandoah/shenandoahClosures.inline.hpp b/src/hotspot/share/gc/shenandoah/shenandoahClosures.inline.hpp index 6674c40f768..befc0d7c1f1 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahClosures.inline.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahClosures.inline.hpp @@ -192,18 +192,16 @@ void ShenandoahCleanUpdateWeakOopsClosure::do_oo ShouldNotReachHere(); } -ShenandoahCodeBlobAndDisarmClosure::ShenandoahCodeBlobAndDisarmClosure(OopClosure* cl) : - CodeBlobToOopClosure(cl, true /* fix_relocations */), +ShenandoahNMethodAndDisarmClosure::ShenandoahNMethodAndDisarmClosure(OopClosure* cl) : + NMethodToOopClosure(cl, true /* fix_relocations */), _bs(BarrierSet::barrier_set()->barrier_set_nmethod()) { } -void ShenandoahCodeBlobAndDisarmClosure::do_code_blob(CodeBlob* cb) { - nmethod* const nm = cb->as_nmethod_or_null(); - if (nm != nullptr) { - assert(!ShenandoahNMethod::gc_data(nm)->is_unregistered(), "Should not be here"); - CodeBlobToOopClosure::do_code_blob(cb); - _bs->disarm(nm); - } +void ShenandoahNMethodAndDisarmClosure::do_nmethod(nmethod* nm) { + assert(nm != nullptr, "Sanity"); + assert(!ShenandoahNMethod::gc_data(nm)->is_unregistered(), "Should not be here"); + NMethodToOopClosure::do_nmethod(nm); + _bs->disarm(nm); } #ifdef ASSERT diff --git a/src/hotspot/share/gc/shenandoah/shenandoahCodeRoots.cpp b/src/hotspot/share/gc/shenandoah/shenandoahCodeRoots.cpp index c6352b2749c..0f073c8428e 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahCodeRoots.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahCodeRoots.cpp @@ -215,8 +215,8 @@ ShenandoahCodeRootsIterator::~ShenandoahCodeRootsIterator() { locker.notify_all(); } -void ShenandoahCodeRootsIterator::possibly_parallel_blobs_do(CodeBlobClosure *f) { +void ShenandoahCodeRootsIterator::possibly_parallel_nmethods_do(NMethodClosure *f) { assert(SafepointSynchronize::is_at_safepoint(), "Must be at safepoint"); assert(_table_snapshot != nullptr, "Sanity"); - _table_snapshot->parallel_blobs_do(f); + _table_snapshot->parallel_nmethods_do(f); } diff --git a/src/hotspot/share/gc/shenandoah/shenandoahCodeRoots.hpp b/src/hotspot/share/gc/shenandoah/shenandoahCodeRoots.hpp index b8870e71ed0..34db132ab83 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahCodeRoots.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahCodeRoots.hpp @@ -48,7 +48,7 @@ class ShenandoahCodeRootsIterator { ShenandoahCodeRootsIterator(); ~ShenandoahCodeRootsIterator(); - void possibly_parallel_blobs_do(CodeBlobClosure *f); + void possibly_parallel_nmethods_do(NMethodClosure *f); }; class ShenandoahCodeRoots : public AllStatic { diff --git a/src/hotspot/share/gc/shenandoah/shenandoahHeap.cpp b/src/hotspot/share/gc/shenandoah/shenandoahHeap.cpp index 8e6081fd0bf..c9d3d1d9364 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahHeap.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahHeap.cpp @@ -1890,7 +1890,7 @@ void ShenandoahHeap::stw_unload_classes(bool full_gc) { if (!unload_classes()) return; ClassUnloadingContext ctx(_workers->active_workers(), true /* unregister_nmethods_during_purge */, - false /* lock_codeblob_free_separately */); + false /* lock_nmethod_free_separately */); // Unload classes and purge SystemDictionary. { diff --git a/src/hotspot/share/gc/shenandoah/shenandoahNMethod.cpp b/src/hotspot/share/gc/shenandoah/shenandoahNMethod.cpp index 980050b8b00..fd42580b7ad 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahNMethod.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahNMethod.cpp @@ -427,7 +427,7 @@ ShenandoahNMethodTableSnapshot::~ShenandoahNMethodTableSnapshot() { _list->release(); } -void ShenandoahNMethodTableSnapshot::parallel_blobs_do(CodeBlobClosure *f) { +void ShenandoahNMethodTableSnapshot::parallel_nmethods_do(NMethodClosure *f) { size_t stride = 256; // educated guess ShenandoahNMethod** const list = _list->list(); @@ -447,7 +447,7 @@ void ShenandoahNMethodTableSnapshot::parallel_blobs_do(CodeBlobClosure *f) { } nmr->assert_correct(); - f->do_code_blob(nmr->nm()); + f->do_nmethod(nmr->nm()); } } } diff --git a/src/hotspot/share/gc/shenandoah/shenandoahNMethod.hpp b/src/hotspot/share/gc/shenandoah/shenandoahNMethod.hpp index 6a856e68403..89e093db0f0 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahNMethod.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahNMethod.hpp @@ -119,7 +119,7 @@ class ShenandoahNMethodTableSnapshot : public CHeapObj { ShenandoahNMethodTableSnapshot(ShenandoahNMethodTable* table); ~ShenandoahNMethodTableSnapshot(); - void parallel_blobs_do(CodeBlobClosure *f); + void parallel_nmethods_do(NMethodClosure *f); void concurrent_nmethods_do(NMethodClosure* cl); }; diff --git a/src/hotspot/share/gc/shenandoah/shenandoahRootProcessor.cpp b/src/hotspot/share/gc/shenandoah/shenandoahRootProcessor.cpp index 639b35deca3..804d643e753 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahRootProcessor.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahRootProcessor.cpp @@ -63,7 +63,7 @@ ShenandoahThreadRoots::ShenandoahThreadRoots(ShenandoahPhaseTimings::Phase phase Threads::change_thread_claim_token(); } -void ShenandoahThreadRoots::oops_do(OopClosure* oops_cl, CodeBlobClosure* code_cl, uint worker_id) { +void ShenandoahThreadRoots::oops_do(OopClosure* oops_cl, NMethodClosure* code_cl, uint worker_id) { ShenandoahWorkerTimingsTracker timer(_phase, ShenandoahPhaseTimings::ThreadRoots, worker_id); ResourceMark rm; Threads::possibly_parallel_oops_do(_is_par, oops_cl, code_cl); @@ -82,9 +82,9 @@ ShenandoahThreadRoots::~ShenandoahThreadRoots() { ShenandoahCodeCacheRoots::ShenandoahCodeCacheRoots(ShenandoahPhaseTimings::Phase phase) : _phase(phase) { } -void ShenandoahCodeCacheRoots::code_blobs_do(CodeBlobClosure* blob_cl, uint worker_id) { +void ShenandoahCodeCacheRoots::nmethods_do(NMethodClosure* nmethod_cl, uint worker_id) { ShenandoahWorkerTimingsTracker timer(_phase, ShenandoahPhaseTimings::CodeCacheRoots, worker_id); - _coderoots_iterator.possibly_parallel_blobs_do(blob_cl); + _coderoots_iterator.possibly_parallel_nmethods_do(nmethod_cl); } ShenandoahRootProcessor::ShenandoahRootProcessor(ShenandoahPhaseTimings::Phase phase) : @@ -159,8 +159,8 @@ void ShenandoahConcurrentRootScanner::roots_do(OopClosure* oops, uint worker_id) { ShenandoahWorkerTimingsTracker timer(_phase, ShenandoahPhaseTimings::CodeCacheRoots, worker_id); - CodeBlobToOopClosure blobs(oops, !CodeBlobToOopClosure::FixRelocations); - _codecache_snapshot->parallel_blobs_do(&blobs); + NMethodToOopClosure nmethods(oops, !NMethodToOopClosure::FixRelocations); + _codecache_snapshot->parallel_nmethods_do(&nmethods); } } @@ -203,11 +203,11 @@ ShenandoahRootAdjuster::ShenandoahRootAdjuster(uint n_workers, ShenandoahPhaseTi } void ShenandoahRootAdjuster::roots_do(uint worker_id, OopClosure* oops) { - CodeBlobToOopClosure code_blob_cl(oops, CodeBlobToOopClosure::FixRelocations); - ShenandoahCodeBlobAndDisarmClosure blobs_and_disarm_Cl(oops); - CodeBlobToOopClosure* adjust_code_closure = ShenandoahCodeRoots::use_nmethod_barriers_for_mark() ? - static_cast(&blobs_and_disarm_Cl) : - static_cast(&code_blob_cl); + NMethodToOopClosure code_blob_cl(oops, NMethodToOopClosure::FixRelocations); + ShenandoahNMethodAndDisarmClosure nmethods_and_disarm_Cl(oops); + NMethodToOopClosure* adjust_code_closure = ShenandoahCodeRoots::use_nmethod_barriers_for_mark() ? + static_cast(&nmethods_and_disarm_Cl) : + static_cast(&code_blob_cl); CLDToOopClosure adjust_cld_closure(oops, ClassLoaderData::_claim_strong); // Process light-weight/limited parallel roots then @@ -216,7 +216,7 @@ void ShenandoahRootAdjuster::roots_do(uint worker_id, OopClosure* oops) { _cld_roots.cld_do(&adjust_cld_closure, worker_id); // Process heavy-weight/fully parallel roots the last - _code_roots.code_blobs_do(adjust_code_closure, worker_id); + _code_roots.nmethods_do(adjust_code_closure, worker_id); _thread_roots.oops_do(oops, nullptr, worker_id); } @@ -229,34 +229,32 @@ ShenandoahHeapIterationRootScanner::ShenandoahHeapIterationRootScanner(uint n_wo _code_roots(ShenandoahPhaseTimings::heap_iteration_roots) { } -class ShenandoahMarkCodeBlobClosure : public CodeBlobClosure { +class ShenandoahMarkNMethodClosure : public NMethodClosure { private: OopClosure* const _oops; BarrierSetNMethod* const _bs_nm; public: - ShenandoahMarkCodeBlobClosure(OopClosure* oops) : + ShenandoahMarkNMethodClosure(OopClosure* oops) : _oops(oops), _bs_nm(BarrierSet::barrier_set()->barrier_set_nmethod()) {} - virtual void do_code_blob(CodeBlob* cb) { - nmethod* const nm = cb->as_nmethod_or_null(); - if (nm != nullptr) { - if (_bs_nm != nullptr) { - // Make sure it only sees to-space objects - _bs_nm->nmethod_entry_barrier(nm); - } - ShenandoahNMethod* const snm = ShenandoahNMethod::gc_data(nm); - assert(snm != nullptr, "Sanity"); - snm->oops_do(_oops, false /*fix_relocations*/); + virtual void do_nmethod(nmethod* nm) { + assert(nm != nullptr, "Sanity"); + if (_bs_nm != nullptr) { + // Make sure it only sees to-space objects + _bs_nm->nmethod_entry_barrier(nm); } + ShenandoahNMethod* const snm = ShenandoahNMethod::gc_data(nm); + assert(snm != nullptr, "Sanity"); + snm->oops_do(_oops, false /*fix_relocations*/); } }; void ShenandoahHeapIterationRootScanner::roots_do(OopClosure* oops) { // Must use _claim_other to avoid interfering with concurrent CLDG iteration CLDToOopClosure clds(oops, ClassLoaderData::_claim_other); - ShenandoahMarkCodeBlobClosure code(oops); + ShenandoahMarkNMethodClosure code(oops); ShenandoahParallelOopsDoThreadClosure tc_cl(oops, &code, nullptr); ResourceMark rm; @@ -267,6 +265,6 @@ void ShenandoahHeapIterationRootScanner::roots_do(OopClosure* oops) { _cld_roots.cld_do(&clds, 0); // Process heavy-weight/fully parallel roots the last - _code_roots.code_blobs_do(&code, 0); + _code_roots.nmethods_do(&code, 0); _thread_roots.threads_do(&tc_cl, 0); } diff --git a/src/hotspot/share/gc/shenandoah/shenandoahRootProcessor.hpp b/src/hotspot/share/gc/shenandoah/shenandoahRootProcessor.hpp index fcb28dfbce0..40d4077256d 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahRootProcessor.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahRootProcessor.hpp @@ -92,7 +92,7 @@ class ShenandoahThreadRoots { ShenandoahThreadRoots(ShenandoahPhaseTimings::Phase phase, bool is_par); ~ShenandoahThreadRoots(); - void oops_do(OopClosure* oops_cl, CodeBlobClosure* code_cl, uint worker_id); + void oops_do(OopClosure* oops_cl, NMethodClosure* code_cl, uint worker_id); void threads_do(ThreadClosure* tc, uint worker_id); }; @@ -103,7 +103,7 @@ class ShenandoahCodeCacheRoots { public: ShenandoahCodeCacheRoots(ShenandoahPhaseTimings::Phase phase); - void code_blobs_do(CodeBlobClosure* blob_cl, uint worker_id); + void nmethods_do(NMethodClosure* nmethod_cl, uint worker_id); }; template diff --git a/src/hotspot/share/gc/shenandoah/shenandoahRootProcessor.inline.hpp b/src/hotspot/share/gc/shenandoah/shenandoahRootProcessor.inline.hpp index 3872a5a391c..f1544c1762e 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahRootProcessor.inline.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahRootProcessor.inline.hpp @@ -127,10 +127,10 @@ void ShenandoahClassLoaderDataRoots::cld_do(CLDClosure* clds, uint w class ShenandoahParallelOopsDoThreadClosure : public ThreadClosure { private: OopClosure* _f; - CodeBlobClosure* _cf; + NMethodClosure* _cf; ThreadClosure* _thread_cl; public: - ShenandoahParallelOopsDoThreadClosure(OopClosure* f, CodeBlobClosure* cf, ThreadClosure* thread_cl) : + ShenandoahParallelOopsDoThreadClosure(OopClosure* f, NMethodClosure* cf, ThreadClosure* thread_cl) : _f(f), _cf(cf), _thread_cl(thread_cl) {} void do_thread(Thread* t) { @@ -152,16 +152,16 @@ class ShenandoahParallelOopsDoThreadClosure : public ThreadClosure { // we risk executing that code cache blob, and crashing. template void ShenandoahSTWRootScanner::roots_do(T* oops, uint worker_id) { - MarkingCodeBlobClosure blobs_cl(oops, !CodeBlobToOopClosure::FixRelocations, true /*FIXME*/); + MarkingNMethodClosure nmethods_cl(oops, !NMethodToOopClosure::FixRelocations, true /*FIXME*/); CLDToOopClosure clds(oops, ClassLoaderData::_claim_strong); ResourceMark rm; if (_unload_classes) { - _thread_roots.oops_do(oops, &blobs_cl, worker_id); + _thread_roots.oops_do(oops, &nmethods_cl, worker_id); _cld_roots.always_strong_cld_do(&clds, worker_id); } else { _thread_roots.oops_do(oops, nullptr, worker_id); - _code_roots.code_blobs_do(&blobs_cl, worker_id); + _code_roots.nmethods_do(&nmethods_cl, worker_id); _cld_roots.cld_do(&clds, worker_id); } @@ -170,11 +170,11 @@ void ShenandoahSTWRootScanner::roots_do(T* oops, uint worker_id) { template void ShenandoahRootUpdater::roots_do(uint worker_id, IsAlive* is_alive, KeepAlive* keep_alive) { - CodeBlobToOopClosure update_blobs(keep_alive, CodeBlobToOopClosure::FixRelocations); - ShenandoahCodeBlobAndDisarmClosure blobs_and_disarm_Cl(keep_alive); - CodeBlobToOopClosure* codes_cl = ShenandoahCodeRoots::use_nmethod_barriers_for_mark() ? - static_cast(&blobs_and_disarm_Cl) : - static_cast(&update_blobs); + NMethodToOopClosure update_nmethods(keep_alive, NMethodToOopClosure::FixRelocations); + ShenandoahNMethodAndDisarmClosure nmethods_and_disarm_Cl(keep_alive); + NMethodToOopClosure* codes_cl = ShenandoahCodeRoots::use_nmethod_barriers_for_mark() ? + static_cast(&nmethods_and_disarm_Cl) : + static_cast(&update_nmethods); CLDToOopClosure clds(keep_alive, ClassLoaderData::_claim_strong); @@ -184,7 +184,7 @@ void ShenandoahRootUpdater::roots_do(uint worker_id, IsAlive* is_alive, KeepAliv _cld_roots.cld_do(&clds, worker_id); // Process heavy-weight/fully parallel roots the last - _code_roots.code_blobs_do(codes_cl, worker_id); + _code_roots.nmethods_do(codes_cl, worker_id); _thread_roots.oops_do(keep_alive, nullptr, worker_id); } diff --git a/src/hotspot/share/gc/shenandoah/shenandoahRootVerifier.cpp b/src/hotspot/share/gc/shenandoah/shenandoahRootVerifier.cpp index 35e4b865d97..1b95fcc558f 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahRootVerifier.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahRootVerifier.cpp @@ -57,8 +57,8 @@ void ShenandoahRootVerifier::roots_do(OopClosure* oops) { ShenandoahGCStateResetter resetter; shenandoah_assert_safepoint(); - CodeBlobToOopClosure blobs(oops, !CodeBlobToOopClosure::FixRelocations); - CodeCache::blobs_do(&blobs); + NMethodToOopClosure blobs(oops, !NMethodToOopClosure::FixRelocations); + CodeCache::nmethods_do(&blobs); CLDToOopClosure clds(oops, ClassLoaderData::_claim_none); ClassLoaderDataGraph::cld_do(&clds); @@ -86,6 +86,6 @@ void ShenandoahRootVerifier::strong_roots_do(OopClosure* oops) { // Do thread roots the last. This allows verification code to find // any broken objects from those special roots first, not the accidental // dangling reference from the thread root. - CodeBlobToOopClosure blobs(oops, !CodeBlobToOopClosure::FixRelocations); - Threads::possibly_parallel_oops_do(true, oops, &blobs); + NMethodToOopClosure nmethods(oops, !NMethodToOopClosure::FixRelocations); + Threads::possibly_parallel_oops_do(true, oops, &nmethods); } diff --git a/src/hotspot/share/gc/shenandoah/shenandoahStackWatermark.cpp b/src/hotspot/share/gc/shenandoah/shenandoahStackWatermark.cpp index 8a5b4c29539..68b81bce417 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahStackWatermark.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahStackWatermark.cpp @@ -35,15 +35,13 @@ uint32_t ShenandoahStackWatermark::_epoch_id = 1; -ShenandoahOnStackCodeBlobClosure::ShenandoahOnStackCodeBlobClosure() : +ShenandoahOnStackNMethodClosure::ShenandoahOnStackNMethodClosure() : _bs_nm(BarrierSet::barrier_set()->barrier_set_nmethod()) {} -void ShenandoahOnStackCodeBlobClosure::do_code_blob(CodeBlob* cb) { - nmethod* const nm = cb->as_nmethod_or_null(); - if (nm != nullptr) { - const bool result = _bs_nm->nmethod_entry_barrier(nm); - assert(result, "NMethod on-stack must be alive"); - } +void ShenandoahOnStackNMethodClosure::do_nmethod(nmethod* nm) { + assert(nm != nullptr, "Sanity"); + const bool result = _bs_nm->nmethod_entry_barrier(nm); + assert(result, "NMethod on-stack must be alive"); } ThreadLocalAllocStats& ShenandoahStackWatermark::stats() { @@ -65,7 +63,7 @@ ShenandoahStackWatermark::ShenandoahStackWatermark(JavaThread* jt) : _stats(), _keep_alive_cl(), _evac_update_oop_cl(), - _cb_cl() {} + _nm_cl() {} OopClosure* ShenandoahStackWatermark::closure_from_context(void* context) { if (context != nullptr) { @@ -98,7 +96,7 @@ void ShenandoahStackWatermark::start_processing_impl(void* context) { // It is also a good place to resize the TLAB sizes for future allocations. retire_tlab(); - _jt->oops_do_no_frames(closure_from_context(context), &_cb_cl); + _jt->oops_do_no_frames(closure_from_context(context), &_nm_cl); } else if (heap->is_concurrent_weak_root_in_progress()) { assert(heap->is_evacuation_in_progress(), "Should not be armed"); // Retire the TLABs, which will force threads to reacquire their TLABs. @@ -108,7 +106,7 @@ void ShenandoahStackWatermark::start_processing_impl(void* context) { // be needed for reference updates (would update the large filler instead). retire_tlab(); - _jt->oops_do_no_frames(closure_from_context(context), &_cb_cl); + _jt->oops_do_no_frames(closure_from_context(context), &_nm_cl); } else { ShouldNotReachHere(); } @@ -135,5 +133,5 @@ void ShenandoahStackWatermark::process(const frame& fr, RegisterMap& register_ma assert((heap->is_concurrent_weak_root_in_progress() && heap->is_evacuation_in_progress()) || heap->is_concurrent_mark_in_progress(), "Only these two phases"); - fr.oops_do(oops, &_cb_cl, ®ister_map, DerivedPointerIterationMode::_directly); + fr.oops_do(oops, &_nm_cl, ®ister_map, DerivedPointerIterationMode::_directly); } diff --git a/src/hotspot/share/gc/shenandoah/shenandoahStackWatermark.hpp b/src/hotspot/share/gc/shenandoah/shenandoahStackWatermark.hpp index d76cd2b87c9..7298c42cbb0 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahStackWatermark.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahStackWatermark.hpp @@ -38,13 +38,13 @@ class frame; class JavaThread; -class ShenandoahOnStackCodeBlobClosure : public CodeBlobClosure { +class ShenandoahOnStackNMethodClosure : public NMethodClosure { private: BarrierSetNMethod* _bs_nm; - void do_code_blob(CodeBlob* cb); + void do_nmethod(nmethod* nm); public: - ShenandoahOnStackCodeBlobClosure(); + ShenandoahOnStackNMethodClosure(); }; class ShenandoahStackWatermark : public StackWatermark { @@ -56,7 +56,7 @@ class ShenandoahStackWatermark : public StackWatermark { // Closures ShenandoahKeepAliveClosure _keep_alive_cl; ShenandoahEvacuateUpdateRootsClosure _evac_update_oop_cl; - ShenandoahOnStackCodeBlobClosure _cb_cl; + ShenandoahOnStackNMethodClosure _nm_cl; public: ShenandoahStackWatermark(JavaThread* jt); ThreadLocalAllocStats& stats(); diff --git a/src/hotspot/share/gc/shenandoah/shenandoahUnload.cpp b/src/hotspot/share/gc/shenandoah/shenandoahUnload.cpp index 1017210e23e..4c61e02bb0b 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahUnload.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahUnload.cpp @@ -1,4 +1,5 @@ /* + * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2019, 2021, Red Hat, Inc. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -77,8 +78,7 @@ class ShenandoahIsUnloadingOopClosure : public OopClosure { class ShenandoahIsUnloadingBehaviour : public IsUnloadingBehaviour { public: - virtual bool has_dead_oop(CompiledMethod* method) const { - nmethod* const nm = method->as_nmethod(); + virtual bool has_dead_oop(nmethod* nm) const { assert(ShenandoahHeap::heap()->is_concurrent_weak_root_in_progress(), "Only for this phase"); ShenandoahNMethod* data = ShenandoahNMethod::gc_data(nm); ShenandoahReentrantLocker locker(data->lock()); @@ -90,27 +90,24 @@ class ShenandoahIsUnloadingBehaviour : public IsUnloadingBehaviour { class ShenandoahCompiledICProtectionBehaviour : public CompiledICProtectionBehaviour { public: - virtual bool lock(CompiledMethod* method) { - nmethod* const nm = method->as_nmethod(); + virtual bool lock(nmethod* nm) { ShenandoahReentrantLock* const lock = ShenandoahNMethod::lock_for_nmethod(nm); assert(lock != nullptr, "Not yet registered?"); lock->lock(); return true; } - virtual void unlock(CompiledMethod* method) { - nmethod* const nm = method->as_nmethod(); + virtual void unlock(nmethod* nm) { ShenandoahReentrantLock* const lock = ShenandoahNMethod::lock_for_nmethod(nm); assert(lock != nullptr, "Not yet registered?"); lock->unlock(); } - virtual bool is_safe(CompiledMethod* method) { - if (SafepointSynchronize::is_at_safepoint() || method->is_unloading()) { + virtual bool is_safe(nmethod* nm) { + if (SafepointSynchronize::is_at_safepoint() || nm->is_unloading()) { return true; } - nmethod* const nm = method->as_nmethod(); ShenandoahReentrantLock* const lock = ShenandoahNMethod::lock_for_nmethod(nm); assert(lock != nullptr, "Not yet registered?"); return lock->owned_by_self(); @@ -141,7 +138,7 @@ void ShenandoahUnload::unload() { ClassUnloadingContext ctx(heap->workers()->active_workers(), true /* unregister_nmethods_during_purge */, - true /* lock_codeblob_free_separately */); + true /* lock_nmethod_free_separately */); // Unlink stale metadata and nmethods { diff --git a/src/hotspot/share/gc/x/xHeap.cpp b/src/hotspot/share/gc/x/xHeap.cpp index 75d9bc08460..3872db785f3 100644 --- a/src/hotspot/share/gc/x/xHeap.cpp +++ b/src/hotspot/share/gc/x/xHeap.cpp @@ -323,7 +323,7 @@ void XHeap::process_non_strong_references() { ClassUnloadingContext ctx(_workers.active_workers(), true /* unregister_nmethods_during_purge */, - true /* lock_codeblob_free_separately */); + true /* lock_nmethod_free_separately */); // Unlink stale metadata and nmethods _unload.unlink(); diff --git a/src/hotspot/share/gc/x/xHeapIterator.cpp b/src/hotspot/share/gc/x/xHeapIterator.cpp index 3d3549e7324..47a6db26f69 100644 --- a/src/hotspot/share/gc/x/xHeapIterator.cpp +++ b/src/hotspot/share/gc/x/xHeapIterator.cpp @@ -303,16 +303,16 @@ class XHeapIteratorNMethodClosure : public NMethodClosure { class XHeapIteratorThreadClosure : public ThreadClosure { private: - OopClosure* const _cl; - CodeBlobToNMethodClosure _cb_cl; + OopClosure* const _cl; + NMethodClosure* const _nm_cl; public: XHeapIteratorThreadClosure(OopClosure* cl, NMethodClosure* nm_cl) : _cl(cl), - _cb_cl(nm_cl) {} + _nm_cl(nm_cl) {} void do_thread(Thread* thread) { - thread->oops_do(_cl, &_cb_cl); + thread->oops_do(_cl, _nm_cl); } }; diff --git a/src/hotspot/share/gc/x/xStackWatermark.cpp b/src/hotspot/share/gc/x/xStackWatermark.cpp index 9710b4c5b21..b75113a7529 100644 --- a/src/hotspot/share/gc/x/xStackWatermark.cpp +++ b/src/hotspot/share/gc/x/xStackWatermark.cpp @@ -33,15 +33,12 @@ #include "runtime/frame.inline.hpp" #include "utilities/preserveException.hpp" -XOnStackCodeBlobClosure::XOnStackCodeBlobClosure() : +XOnStackNMethodClosure::XOnStackNMethodClosure() : _bs_nm(BarrierSet::barrier_set()->barrier_set_nmethod()) {} -void XOnStackCodeBlobClosure::do_code_blob(CodeBlob* cb) { - nmethod* const nm = cb->as_nmethod_or_null(); - if (nm != nullptr) { - const bool result = _bs_nm->nmethod_entry_barrier(nm); - assert(result, "NMethod on-stack must be alive"); - } +void XOnStackNMethodClosure::do_nmethod(nmethod* nm) { + const bool result = _bs_nm->nmethod_entry_barrier(nm); + assert(result, "NMethod on-stack must be alive"); } ThreadLocalAllocStats& XStackWatermark::stats() { @@ -55,7 +52,7 @@ uint32_t XStackWatermark::epoch_id() const { XStackWatermark::XStackWatermark(JavaThread* jt) : StackWatermark(jt, StackWatermarkKind::gc, *XAddressBadMaskHighOrderBitsAddr), _jt_cl(), - _cb_cl(), + _nm_cl(), _stats() {} OopClosure* XStackWatermark::closure_from_context(void* context) { @@ -72,7 +69,7 @@ void XStackWatermark::start_processing_impl(void* context) { XVerify::verify_thread_head_bad(_jt); // Process the non-frame part of the thread - _jt->oops_do_no_frames(closure_from_context(context), &_cb_cl); + _jt->oops_do_no_frames(closure_from_context(context), &_nm_cl); XThreadLocalData::do_invisible_root(_jt, XBarrier::load_barrier_on_invisible_root_oop_field); // Verification of frames is done after processing of the "head" (no_frames). @@ -95,5 +92,5 @@ void XStackWatermark::start_processing_impl(void* context) { void XStackWatermark::process(const frame& fr, RegisterMap& register_map, void* context) { XVerify::verify_frame_bad(fr, register_map); - fr.oops_do(closure_from_context(context), &_cb_cl, ®ister_map, DerivedPointerIterationMode::_directly); + fr.oops_do(closure_from_context(context), &_nm_cl, ®ister_map, DerivedPointerIterationMode::_directly); } diff --git a/src/hotspot/share/gc/x/xStackWatermark.hpp b/src/hotspot/share/gc/x/xStackWatermark.hpp index b9f39d0d1d8..9b73860bed0 100644 --- a/src/hotspot/share/gc/x/xStackWatermark.hpp +++ b/src/hotspot/share/gc/x/xStackWatermark.hpp @@ -37,21 +37,21 @@ class frame; class JavaThread; -class XOnStackCodeBlobClosure : public CodeBlobClosure { +class XOnStackNMethodClosure : public NMethodClosure { private: BarrierSetNMethod* _bs_nm; - virtual void do_code_blob(CodeBlob* cb); + virtual void do_nmethod(nmethod* nm); public: - XOnStackCodeBlobClosure(); + XOnStackNMethodClosure(); }; class XStackWatermark : public StackWatermark { private: - XLoadBarrierOopClosure _jt_cl; - XOnStackCodeBlobClosure _cb_cl; - ThreadLocalAllocStats _stats; + XLoadBarrierOopClosure _jt_cl; + XOnStackNMethodClosure _nm_cl; + ThreadLocalAllocStats _stats; OopClosure* closure_from_context(void* context); diff --git a/src/hotspot/share/gc/x/xUnload.cpp b/src/hotspot/share/gc/x/xUnload.cpp index 230dbf613a4..b62521fbf2c 100644 --- a/src/hotspot/share/gc/x/xUnload.cpp +++ b/src/hotspot/share/gc/x/xUnload.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2021, 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 @@ -75,8 +75,7 @@ class XIsUnloadingOopClosure : public OopClosure { class XIsUnloadingBehaviour : public IsUnloadingBehaviour { public: - virtual bool has_dead_oop(CompiledMethod* method) const { - nmethod* const nm = method->as_nmethod(); + virtual bool has_dead_oop(nmethod* nm) const { XReentrantLock* const lock = XNMethod::lock_for_nmethod(nm); XLocker locker(lock); XIsUnloadingOopClosure cl; @@ -87,25 +86,22 @@ class XIsUnloadingBehaviour : public IsUnloadingBehaviour { class XCompiledICProtectionBehaviour : public CompiledICProtectionBehaviour { public: - virtual bool lock(CompiledMethod* method) { - nmethod* const nm = method->as_nmethod(); + virtual bool lock(nmethod* nm) { XReentrantLock* const lock = XNMethod::lock_for_nmethod(nm); lock->lock(); return true; } - virtual void unlock(CompiledMethod* method) { - nmethod* const nm = method->as_nmethod(); + virtual void unlock(nmethod* nm) { XReentrantLock* const lock = XNMethod::lock_for_nmethod(nm); lock->unlock(); } - virtual bool is_safe(CompiledMethod* method) { - if (SafepointSynchronize::is_at_safepoint() || method->is_unloading()) { + virtual bool is_safe(nmethod* nm) { + if (SafepointSynchronize::is_at_safepoint() || nm->is_unloading()) { return true; } - nmethod* const nm = method->as_nmethod(); XReentrantLock* const lock = XNMethod::lock_for_nmethod(nm); return lock->is_owned(); } diff --git a/src/hotspot/share/gc/x/xVerify.cpp b/src/hotspot/share/gc/x/xVerify.cpp index 525c4958d9b..ac6e8ee65d0 100644 --- a/src/hotspot/share/gc/x/xVerify.cpp +++ b/src/hotspot/share/gc/x/xVerify.cpp @@ -97,16 +97,6 @@ class XVerifyRootClosure : public OopClosure { } }; -class XVerifyCodeBlobClosure : public CodeBlobToOopClosure { -public: - XVerifyCodeBlobClosure(XVerifyRootClosure* _cl) : - CodeBlobToOopClosure(_cl, false /* fix_relocations */) {} - - virtual void do_code_blob(CodeBlob* cb) { - CodeBlobToOopClosure::do_code_blob(cb); - } -}; - class XVerifyStack : public OopClosure { private: XVerifyRootClosure* const _cl; @@ -166,12 +156,12 @@ class XVerifyStack : public OopClosure { } void verify_frames() { - XVerifyCodeBlobClosure cb_cl(_cl); + NMethodToOopClosure nm_cl(_cl, false /* fix_relocations */); for (StackFrameStream frames(_jt, true /* update */, false /* process_frames */); !frames.is_done(); frames.next()) { frame& frame = *frames.current(); - frame.oops_do(this, &cb_cl, frames.register_map(), DerivedPointerIterationMode::_ignore); + frame.oops_do(this, &nm_cl, frames.register_map(), DerivedPointerIterationMode::_ignore); prepare_next_frame(frame); } } diff --git a/src/hotspot/share/gc/z/zAddress.inline.hpp b/src/hotspot/share/gc/z/zAddress.inline.hpp index 1b0b55cff96..7f3a52e3594 100644 --- a/src/hotspot/share/gc/z/zAddress.inline.hpp +++ b/src/hotspot/share/gc/z/zAddress.inline.hpp @@ -133,6 +133,10 @@ inline bool operator<(zoffset first, zoffset_end second) { return untype(first) < untype(second); } +inline bool operator<=(zoffset_end first, zoffset second) { + return untype(first) <= untype(second); +} + inline bool operator>(zoffset first, zoffset_end second) { return untype(first) > untype(second); } diff --git a/src/hotspot/share/gc/z/zGeneration.cpp b/src/hotspot/share/gc/z/zGeneration.cpp index 0396a3f7516..50973f25621 100644 --- a/src/hotspot/share/gc/z/zGeneration.cpp +++ b/src/hotspot/share/gc/z/zGeneration.cpp @@ -1323,7 +1323,7 @@ void ZGenerationOld::process_non_strong_references() { ClassUnloadingContext ctx(_workers.active_workers(), true /* unregister_nmethods_during_purge */, - true /* lock_codeblob_free_separately */); + true /* lock_nmethod_free_separately */); // Unlink stale metadata and nmethods _unload.unlink(); diff --git a/src/hotspot/share/gc/z/zHeapIterator.cpp b/src/hotspot/share/gc/z/zHeapIterator.cpp index 8edd4ded636..cbcac39a11b 100644 --- a/src/hotspot/share/gc/z/zHeapIterator.cpp +++ b/src/hotspot/share/gc/z/zHeapIterator.cpp @@ -375,16 +375,16 @@ class ZHeapIteratorNMethodClosure : public NMethodClosure { class ZHeapIteratorThreadClosure : public ThreadClosure { private: - OopClosure* const _cl; - CodeBlobToNMethodClosure _cb_cl; + OopClosure* const _cl; + NMethodClosure* const _nm_cl; public: ZHeapIteratorThreadClosure(OopClosure* cl, NMethodClosure* nm_cl) : _cl(cl), - _cb_cl(nm_cl) {} + _nm_cl(nm_cl) {} void do_thread(Thread* thread) { - thread->oops_do(_cl, &_cb_cl); + thread->oops_do(_cl, _nm_cl); } }; diff --git a/src/hotspot/share/gc/z/zNMethod.cpp b/src/hotspot/share/gc/z/zNMethod.cpp index a7d23124b68..a1639648acd 100644 --- a/src/hotspot/share/gc/z/zNMethod.cpp +++ b/src/hotspot/share/gc/z/zNMethod.cpp @@ -306,6 +306,7 @@ oop ZNMethod::load_oop(oop* p, DecoratorSet decorators) { assert((decorators & ON_WEAK_OOP_REF) == 0, "nmethod oops have phantom strength, not weak"); nmethod* const nm = CodeCache::find_nmethod((void*)p); + assert(nm != nullptr, "did not find nmethod"); if (!is_armed(nm)) { // If the nmethod entry barrier isn't armed, then it has been applied // already. The implication is that the contents of the memory location diff --git a/src/hotspot/share/gc/z/zPhysicalMemory.hpp b/src/hotspot/share/gc/z/zPhysicalMemory.hpp index 2244732a146..e5e0a19d1c5 100644 --- a/src/hotspot/share/gc/z/zPhysicalMemory.hpp +++ b/src/hotspot/share/gc/z/zPhysicalMemory.hpp @@ -32,16 +32,16 @@ class ZPhysicalMemorySegment : public CHeapObj { private: - zoffset _start; - zoffset _end; - bool _committed; + zoffset _start; + zoffset_end _end; + bool _committed; public: ZPhysicalMemorySegment(); ZPhysicalMemorySegment(zoffset start, size_t size, bool committed); zoffset start() const; - zoffset end() const; + zoffset_end end() const; size_t size() const; bool is_committed() const; diff --git a/src/hotspot/share/gc/z/zPhysicalMemory.inline.hpp b/src/hotspot/share/gc/z/zPhysicalMemory.inline.hpp index cbfd3842b35..744c68daa7e 100644 --- a/src/hotspot/share/gc/z/zPhysicalMemory.inline.hpp +++ b/src/hotspot/share/gc/z/zPhysicalMemory.inline.hpp @@ -31,19 +31,19 @@ inline ZPhysicalMemorySegment::ZPhysicalMemorySegment() : _start(zoffset(UINTPTR_MAX)), - _end(zoffset(UINTPTR_MAX)), + _end(zoffset_end(UINTPTR_MAX)), _committed(false) {} inline ZPhysicalMemorySegment::ZPhysicalMemorySegment(zoffset start, size_t size, bool committed) : _start(start), - _end(start + size), + _end(to_zoffset_end(start, size)), _committed(committed) {} inline zoffset ZPhysicalMemorySegment::start() const { return _start; } -inline zoffset ZPhysicalMemorySegment::end() const { +inline zoffset_end ZPhysicalMemorySegment::end() const { return _end; } diff --git a/src/hotspot/share/gc/z/zStackWatermark.cpp b/src/hotspot/share/gc/z/zStackWatermark.cpp index 9454b25b9c9..ead5300e9c3 100644 --- a/src/hotspot/share/gc/z/zStackWatermark.cpp +++ b/src/hotspot/share/gc/z/zStackWatermark.cpp @@ -37,15 +37,13 @@ #include "runtime/thread.hpp" #include "utilities/preserveException.hpp" -ZOnStackCodeBlobClosure::ZOnStackCodeBlobClosure() +ZOnStackNMethodClosure::ZOnStackNMethodClosure() : _bs_nm(BarrierSet::barrier_set()->barrier_set_nmethod()) {} -void ZOnStackCodeBlobClosure::do_code_blob(CodeBlob* cb) { - nmethod* const nm = cb->as_nmethod_or_null(); - if (nm != nullptr) { - const bool result = _bs_nm->nmethod_entry_barrier(nm); - assert(result, "NMethod on-stack must be alive"); - } +void ZOnStackNMethodClosure::do_nmethod(nmethod* nm) { + assert(nm != nullptr, "Sanity"); + const bool result = _bs_nm->nmethod_entry_barrier(nm); + assert(result, "NMethod on-stack must be alive"); } ThreadLocalAllocStats& ZStackWatermark::stats() { @@ -166,9 +164,9 @@ void ZStackWatermark::process_head(void* context) { const uintptr_t color = prev_head_color(); ZStackWatermarkProcessOopClosure cl(context, color); - ZOnStackCodeBlobClosure cb_cl; + ZOnStackNMethodClosure nm_cl; - _jt->oops_do_no_frames(&cl, &cb_cl); + _jt->oops_do_no_frames(&cl, &nm_cl); zaddress_unsafe* const invisible_root = ZThreadLocalData::invisible_root(_jt); if (invisible_root != nullptr) { @@ -209,7 +207,7 @@ void ZStackWatermark::start_processing_impl(void* context) { void ZStackWatermark::process(const frame& fr, RegisterMap& register_map, void* context) { const uintptr_t color = prev_frame_color(fr); ZStackWatermarkProcessOopClosure cl(context, color); - ZOnStackCodeBlobClosure cb_cl; + ZOnStackNMethodClosure nm_cl; - fr.oops_do(&cl, &cb_cl, ®ister_map, DerivedPointerIterationMode::_directly); + fr.oops_do(&cl, &nm_cl, ®ister_map, DerivedPointerIterationMode::_directly); } diff --git a/src/hotspot/share/gc/z/zStackWatermark.hpp b/src/hotspot/share/gc/z/zStackWatermark.hpp index 042ba4dd3f8..fd4efeef761 100644 --- a/src/hotspot/share/gc/z/zStackWatermark.hpp +++ b/src/hotspot/share/gc/z/zStackWatermark.hpp @@ -38,14 +38,14 @@ class frame; class JavaThread; -class ZOnStackCodeBlobClosure : public CodeBlobClosure { +class ZOnStackNMethodClosure : public NMethodClosure { private: BarrierSetNMethod* _bs_nm; - virtual void do_code_blob(CodeBlob* cb); + virtual void do_nmethod(nmethod* nm); public: - ZOnStackCodeBlobClosure(); + ZOnStackNMethodClosure(); }; struct ZColorWatermark { diff --git a/src/hotspot/share/gc/z/zUnload.cpp b/src/hotspot/share/gc/z/zUnload.cpp index 3ab4cd5b19f..1bbfa040ba8 100644 --- a/src/hotspot/share/gc/z/zUnload.cpp +++ b/src/hotspot/share/gc/z/zUnload.cpp @@ -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 @@ -74,8 +74,7 @@ class ZIsUnloadingOopClosure : public OopClosure { class ZIsUnloadingBehaviour : public IsUnloadingBehaviour { public: - virtual bool has_dead_oop(CompiledMethod* method) const { - nmethod* const nm = method->as_nmethod(); + virtual bool has_dead_oop(nmethod* nm) const { ZReentrantLock* const lock = ZNMethod::lock_for_nmethod(nm); ZLocker locker(lock); if (!ZNMethod::is_armed(nm)) { @@ -90,25 +89,22 @@ class ZIsUnloadingBehaviour : public IsUnloadingBehaviour { class ZCompiledICProtectionBehaviour : public CompiledICProtectionBehaviour { public: - virtual bool lock(CompiledMethod* method) { - nmethod* const nm = method->as_nmethod(); + virtual bool lock(nmethod* nm) { ZReentrantLock* const lock = ZNMethod::lock_for_nmethod(nm); lock->lock(); return true; } - virtual void unlock(CompiledMethod* method) { - nmethod* const nm = method->as_nmethod(); + virtual void unlock(nmethod* nm) { ZReentrantLock* const lock = ZNMethod::lock_for_nmethod(nm); lock->unlock(); } - virtual bool is_safe(CompiledMethod* method) { - if (SafepointSynchronize::is_at_safepoint() || method->is_unloading()) { + virtual bool is_safe(nmethod* nm) { + if (SafepointSynchronize::is_at_safepoint() || nm->is_unloading()) { return true; } - nmethod* const nm = method->as_nmethod(); ZReentrantLock* const lock = ZNMethod::lock_for_nmethod(nm); return lock->is_owned(); } diff --git a/src/hotspot/share/gc/z/zVerify.cpp b/src/hotspot/share/gc/z/zVerify.cpp index c88d7ad7978..f7c373903db 100644 --- a/src/hotspot/share/gc/z/zVerify.cpp +++ b/src/hotspot/share/gc/z/zVerify.cpp @@ -240,16 +240,6 @@ class ZVerifyUncoloredRootClosure : public OopClosure { } }; -class ZVerifyCodeBlobClosure : public CodeBlobToOopClosure { -public: - ZVerifyCodeBlobClosure(OopClosure* cl) - : CodeBlobToOopClosure(cl, false /* fix_relocations */) {} - - virtual void do_code_blob(CodeBlob* cb) { - CodeBlobToOopClosure::do_code_blob(cb); - } -}; - class ZVerifyOldOopClosure : public BasicOopIterateClosure { private: const bool _verify_weaks; diff --git a/src/hotspot/share/interpreter/zero/bytecodeInterpreter.cpp b/src/hotspot/share/interpreter/zero/bytecodeInterpreter.cpp index 616ce240869..f8b194da7b7 100644 --- a/src/hotspot/share/interpreter/zero/bytecodeInterpreter.cpp +++ b/src/hotspot/share/interpreter/zero/bytecodeInterpreter.cpp @@ -1607,10 +1607,10 @@ void BytecodeInterpreter::run(interpreterState istate) { ARRAY_INTRO(-3); int item = STACK_INT(-1); // if it is a T_BOOLEAN array, mask the stored value to 0/1 - if (arrObj->klass() == Universe::boolArrayKlassObj()) { + if (arrObj->klass() == Universe::boolArrayKlass()) { item &= 1; } else { - assert(arrObj->klass() == Universe::byteArrayKlassObj(), + assert(arrObj->klass() == Universe::byteArrayKlass(), "should be byte array otherwise"); } ((typeArrayOop)arrObj)->byte_at_put(index, item); diff --git a/src/hotspot/share/jfr/recorder/checkpoint/types/jfrTypeSet.cpp b/src/hotspot/share/jfr/recorder/checkpoint/types/jfrTypeSet.cpp index 3ef7abd8a43..0c947655752 100644 --- a/src/hotspot/share/jfr/recorder/checkpoint/types/jfrTypeSet.cpp +++ b/src/hotspot/share/jfr/recorder/checkpoint/types/jfrTypeSet.cpp @@ -450,9 +450,9 @@ static void write_primitive(JfrCheckpointWriter* writer, KlassPtr type_array_kla assert(writer != nullptr, "invariant"); assert(_artifacts != nullptr, "invariant"); writer->write(primitive_id(type_array_klass)); - writer->write(cld_id(get_cld(Universe::boolArrayKlassObj()), false)); + writer->write(cld_id(get_cld(Universe::boolArrayKlass()), false)); writer->write(mark_symbol(primitive_symbol(type_array_klass), false)); - writer->write(package_id(Universe::boolArrayKlassObj(), false)); + writer->write(package_id(Universe::boolArrayKlass(), false)); writer->write(get_primitive_flags()); writer->write(false); } @@ -468,14 +468,14 @@ static bool is_initial_typeset_for_chunk() { // It will use a reserved constant. static void do_primitives() { assert(is_initial_typeset_for_chunk(), "invariant"); - write_primitive(_writer, Universe::boolArrayKlassObj()); - write_primitive(_writer, Universe::byteArrayKlassObj()); - write_primitive(_writer, Universe::charArrayKlassObj()); - write_primitive(_writer, Universe::shortArrayKlassObj()); - write_primitive(_writer, Universe::intArrayKlassObj()); - write_primitive(_writer, Universe::longArrayKlassObj()); - write_primitive(_writer, Universe::floatArrayKlassObj()); - write_primitive(_writer, Universe::doubleArrayKlassObj()); + write_primitive(_writer, Universe::boolArrayKlass()); + write_primitive(_writer, Universe::byteArrayKlass()); + write_primitive(_writer, Universe::charArrayKlass()); + write_primitive(_writer, Universe::shortArrayKlass()); + write_primitive(_writer, Universe::intArrayKlass()); + write_primitive(_writer, Universe::longArrayKlass()); + write_primitive(_writer, Universe::floatArrayKlass()); + write_primitive(_writer, Universe::doubleArrayKlass()); write_primitive(_writer, nullptr); // void.class } diff --git a/src/hotspot/share/jvmci/jvmciCodeInstaller.cpp b/src/hotspot/share/jvmci/jvmciCodeInstaller.cpp index a5a20a1310e..9b1cb351a68 100644 --- a/src/hotspot/share/jvmci/jvmciCodeInstaller.cpp +++ b/src/hotspot/share/jvmci/jvmciCodeInstaller.cpp @@ -485,8 +485,8 @@ ScopeValue* CodeInstaller::get_scope_value(HotSpotCompiledCodeStream* stream, u1 void CodeInstaller::record_object_value(ObjectValue* sv, HotSpotCompiledCodeStream* stream, JVMCI_TRAPS) { oop javaMirror = JNIHandles::resolve(sv->klass()->as_ConstantOopWriteValue()->value()); Klass* klass = java_lang_Class::as_Klass(javaMirror); - bool isLongArray = klass == Universe::longArrayKlassObj(); - bool isByteArray = klass == Universe::byteArrayKlassObj(); + bool isLongArray = klass == Universe::longArrayKlass(); + bool isByteArray = klass == Universe::byteArrayKlass(); u2 length = stream->read_u2("values:length"); for (jint i = 0; i < length; i++) { diff --git a/src/hotspot/share/jvmci/jvmciCompilerToVM.cpp b/src/hotspot/share/jvmci/jvmciCompilerToVM.cpp index 23e726fb180..8a033492bbb 100644 --- a/src/hotspot/share/jvmci/jvmciCompilerToVM.cpp +++ b/src/hotspot/share/jvmci/jvmciCompilerToVM.cpp @@ -636,7 +636,7 @@ C2V_VMENTRY_NULL(jobject, lookupType, (JNIEnv* env, jobject, jstring jname, ARGU resolved_klass = resolved_klass->array_klass(ndim, CHECK_NULL); } } else { - resolved_klass = TypeArrayKlass::cast(Universe::typeArrayKlassObj(ss.type()))->array_klass(ndim, CHECK_NULL); + resolved_klass = Universe::typeArrayKlass(ss.type())->array_klass(ndim, CHECK_NULL); } } else { resolved_klass = SystemDictionary::find_instance_klass(THREAD, class_name, @@ -656,7 +656,7 @@ C2V_VMENTRY_NULL(jobject, getArrayType, (JNIEnv* env, jobject, jchar type_char, if (type == T_VOID) { return nullptr; } - array_klass = Universe::typeArrayKlassObj(type); + array_klass = Universe::typeArrayKlass(type); if (array_klass == nullptr) { JVMCI_THROW_MSG_NULL(InternalError, err_msg("No array klass for primitive type %s", type2name(type))); } @@ -1305,7 +1305,7 @@ C2V_VMENTRY(void, reprofile, (JNIEnv* env, jobject, ARGUMENT_PAIR(method))) } NOT_PRODUCT(method->set_compiled_invocation_count(0)); - CompiledMethod* code = method->code(); + nmethod* code = method->code(); if (code != nullptr) { code->make_not_entrant(); } @@ -1750,8 +1750,7 @@ C2V_VMENTRY(void, materializeVirtualObjects, (JNIEnv* env, jobject, jobject _hs_ if (!fst.current()->is_compiled_frame()) { JVMCI_THROW_MSG(IllegalStateException, "compiled stack frame expected"); } - assert(fst.current()->cb()->is_nmethod(), "nmethod expected"); - ((nmethod*) fst.current()->cb())->make_not_entrant(); + fst.current()->cb()->as_nmethod()->make_not_entrant(); } Deoptimization::deoptimize(thread, *fst.current(), Deoptimization::Reason_none); // look for the frame again as it has been updated by deopt (pc, deopt state...) diff --git a/src/hotspot/share/jvmci/jvmciEnv.cpp b/src/hotspot/share/jvmci/jvmciEnv.cpp index 8a56beb9d02..4260094c849 100644 --- a/src/hotspot/share/jvmci/jvmciEnv.cpp +++ b/src/hotspot/share/jvmci/jvmciEnv.cpp @@ -1430,7 +1430,7 @@ JVMCIPrimitiveArray JVMCIEnv::new_byteArray(int length, JVMCI_TRAPS) { JVMCIObjectArray JVMCIEnv::new_byte_array_array(int length, JVMCI_TRAPS) { JavaThread* THREAD = JavaThread::current(); // For exception macros. if (is_hotspot()) { - Klass* byteArrayArrayKlass = TypeArrayKlass::cast(Universe::byteArrayKlassObj ())->array_klass(CHECK_(JVMCIObject())); + Klass* byteArrayArrayKlass = TypeArrayKlass::cast(Universe::byteArrayKlass())->array_klass(CHECK_(JVMCIObject())); objArrayOop result = ObjArrayKlass::cast(byteArrayArrayKlass) ->allocate(length, CHECK_(JVMCIObject())); return wrap(result); } else { diff --git a/src/hotspot/share/jvmci/jvmciRuntime.cpp b/src/hotspot/share/jvmci/jvmciRuntime.cpp index b095008fe0b..6bab80ddae6 100644 --- a/src/hotspot/share/jvmci/jvmciRuntime.cpp +++ b/src/hotspot/share/jvmci/jvmciRuntime.cpp @@ -256,7 +256,7 @@ extern void vm_exit(int code); // been deoptimized. If that is the case we return the deopt blob // unpack_with_exception entry instead. This makes life for the exception blob easier // because making that same check and diverting is painful from assembly language. -JRT_ENTRY_NO_ASYNC(static address, exception_handler_for_pc_helper(JavaThread* current, oopDesc* ex, address pc, CompiledMethod*& cm)) +JRT_ENTRY_NO_ASYNC(static address, exception_handler_for_pc_helper(JavaThread* current, oopDesc* ex, address pc, nmethod*& nm)) // Reset method handle flag. current->set_is_method_handle_return(false); @@ -267,10 +267,10 @@ JRT_ENTRY_NO_ASYNC(static address, exception_handler_for_pc_helper(JavaThread* c // has updated oops. StackWatermarkSet::after_unwind(current); - cm = CodeCache::find_compiled(pc); - assert(cm != nullptr, "this is not a compiled method"); + nm = CodeCache::find_nmethod(pc); + assert(nm != nullptr, "did not find nmethod"); // Adjust the pc as needed/ - if (cm->is_deopt_pc(pc)) { + if (nm->is_deopt_pc(pc)) { RegisterMap map(current, RegisterMap::UpdateMap::skip, RegisterMap::ProcessFrames::include, @@ -291,10 +291,10 @@ JRT_ENTRY_NO_ASYNC(static address, exception_handler_for_pc_helper(JavaThread* c if (log_is_enabled(Info, exceptions)) { ResourceMark rm; stringStream tempst; - assert(cm->method() != nullptr, "Unexpected null method()"); + assert(nm->method() != nullptr, "Unexpected null method()"); tempst.print("JVMCI compiled method <%s>\n" " at PC" INTPTR_FORMAT " for thread " INTPTR_FORMAT, - cm->method()->print_value_string(), p2i(pc), p2i(current)); + nm->method()->print_value_string(), p2i(pc), p2i(current)); Exceptions::log_exception(exception, tempst.as_string()); } // for AbortVMOnException flag @@ -332,10 +332,10 @@ JRT_ENTRY_NO_ASYNC(static address, exception_handler_for_pc_helper(JavaThread* c // ExceptionCache is used only for exceptions at call sites and not for implicit exceptions if (guard_pages_enabled) { - address fast_continuation = cm->handler_for_exception_and_pc(exception, pc); + address fast_continuation = nm->handler_for_exception_and_pc(exception, pc); if (fast_continuation != nullptr) { // Set flag if return address is a method handle call site. - current->set_is_method_handle_return(cm->is_method_handle_return(pc)); + current->set_is_method_handle_return(nm->is_method_handle_return(pc)); return fast_continuation; } } @@ -356,7 +356,7 @@ JRT_ENTRY_NO_ASYNC(static address, exception_handler_for_pc_helper(JavaThread* c current->clear_exception_oop_and_pc(); bool recursive_exception = false; - continuation = SharedRuntime::compute_compiled_exc_handler(cm, pc, exception, false, false, recursive_exception); + continuation = SharedRuntime::compute_compiled_exc_handler(nm, pc, exception, false, false, recursive_exception); // If an exception was thrown during exception dispatch, the exception oop may have changed current->set_exception_oop(exception()); current->set_exception_pc(pc); @@ -368,12 +368,12 @@ JRT_ENTRY_NO_ASYNC(static address, exception_handler_for_pc_helper(JavaThread* c // Checking for exception oop equality is not // sufficient because some exceptions are pre-allocated and reused. if (continuation != nullptr && !recursive_exception && !SharedRuntime::deopt_blob()->contains(continuation)) { - cm->add_handler_for_exception_and_pc(exception, pc, continuation); + nm->add_handler_for_exception_and_pc(exception, pc, continuation); } } // Set flag if return address is a method handle call site. - current->set_is_method_handle_return(cm->is_method_handle_return(pc)); + current->set_is_method_handle_return(nm->is_method_handle_return(pc)); if (log_is_enabled(Info, exceptions)) { ResourceMark rm; @@ -395,18 +395,18 @@ address JVMCIRuntime::exception_handler_for_pc(JavaThread* current) { address pc = current->exception_pc(); // Still in Java mode DEBUG_ONLY(NoHandleMark nhm); - CompiledMethod* cm = nullptr; + nmethod* nm = nullptr; address continuation = nullptr; { // Enter VM mode by calling the helper ResetNoHandleMark rnhm; - continuation = exception_handler_for_pc_helper(current, exception, pc, cm); + continuation = exception_handler_for_pc_helper(current, exception, pc, nm); } // Back in JAVA, use no oops DON'T safepoint // Now check to see if the compiled method we were called from is now deoptimized. // If so we must return to the deopt blob and deoptimize the nmethod - if (cm != nullptr && caller_is_deopted()) { + if (nm != nullptr && caller_is_deopted()) { continuation = SharedRuntime::deopt_blob()->unpack_with_exception_in_tls(); } @@ -675,7 +675,7 @@ static void decipher(jlong v, bool ignoreZero) { if (cb) { if (cb->is_nmethod()) { char buf[O_BUFLEN]; - tty->print("%s [" INTPTR_FORMAT "+" JLONG_FORMAT "]", cb->as_nmethod_or_null()->method()->name_and_sig_as_C_string(buf, O_BUFLEN), p2i(cb->code_begin()), (jlong)((address)v - cb->code_begin())); + tty->print("%s [" INTPTR_FORMAT "+" JLONG_FORMAT "]", cb->as_nmethod()->method()->name_and_sig_as_C_string(buf, O_BUFLEN), p2i(cb->code_begin()), (jlong)((address)v - cb->code_begin())); return; } cb->print_value_on(tty); @@ -2208,7 +2208,7 @@ JVMCI::CodeInstallResult JVMCIRuntime::register_method(JVMCIEnv* JVMCIENV, assert(!nmethod_mirror.is_hotspot() || data->get_nmethod_mirror(nm, /* phantom_ref */ false) == nullptr, "must be"); if (entry_bci == InvocationEntryBci) { // If there is an old version we're done with it - CompiledMethod* old = method->code(); + nmethod* old = method->code(); if (TraceMethodReplacement && old != nullptr) { ResourceMark rm; char *method_name = method->name_and_sig_as_C_string(); @@ -2226,7 +2226,7 @@ JVMCI::CodeInstallResult JVMCIRuntime::register_method(JVMCIEnv* JVMCIENV, comp_level, method_name, nm->entry_point()); } // Allow the code to be executed - MutexLocker ml(CompiledMethod_lock, Mutex::_no_safepoint_check_flag); + MutexLocker ml(NMethodState_lock, Mutex::_no_safepoint_check_flag); if (nm->make_in_use()) { method->set_code(method, nm); } else { @@ -2240,7 +2240,7 @@ JVMCI::CodeInstallResult JVMCIRuntime::register_method(JVMCIEnv* JVMCIENV, lt.print("Installing osr method (%d) %s @ %d", comp_level, method_name, entry_bci); } - MutexLocker ml(CompiledMethod_lock, Mutex::_no_safepoint_check_flag); + MutexLocker ml(NMethodState_lock, Mutex::_no_safepoint_check_flag); if (nm->make_in_use()) { InstanceKlass::cast(method->method_holder())->add_osr_nmethod(nm); } else { @@ -2249,7 +2249,7 @@ JVMCI::CodeInstallResult JVMCIRuntime::register_method(JVMCIEnv* JVMCIENV, } } else { assert(!nmethod_mirror.is_hotspot() || data->get_nmethod_mirror(nm, /* phantom_ref */ false) == HotSpotJVMCI::resolve(nmethod_mirror), "must be"); - MutexLocker ml(CompiledMethod_lock, Mutex::_no_safepoint_check_flag); + MutexLocker ml(NMethodState_lock, Mutex::_no_safepoint_check_flag); if (!nm->make_in_use()) { result = JVMCI::nmethod_reclaimed; } diff --git a/src/hotspot/share/jvmci/vmStructs_jvmci.cpp b/src/hotspot/share/jvmci/vmStructs_jvmci.cpp index 242933c18af..2a67a6791b4 100644 --- a/src/hotspot/share/jvmci/vmStructs_jvmci.cpp +++ b/src/hotspot/share/jvmci/vmStructs_jvmci.cpp @@ -266,7 +266,7 @@ nonstatic_field(Method, _vtable_index, int) \ nonstatic_field(Method, _intrinsic_id, u2) \ nonstatic_field(Method, _flags._status, u4) \ - volatile_nonstatic_field(Method, _code, CompiledMethod*) \ + volatile_nonstatic_field(Method, _code, nmethod*) \ volatile_nonstatic_field(Method, _from_compiled_entry, address) \ \ nonstatic_field(MethodCounters, _invoke_mask, int) \ diff --git a/src/hotspot/share/logging/logConfiguration.cpp b/src/hotspot/share/logging/logConfiguration.cpp index 18f225f7dd4..3a54d1f4e63 100644 --- a/src/hotspot/share/logging/logConfiguration.cpp +++ b/src/hotspot/share/logging/logConfiguration.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2023, 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 @@ -614,7 +614,7 @@ void LogConfiguration::print_command_line_help(outputStream* out) { out->print_cr("Available log outputs:"); out->print_cr(" stdout/stderr"); out->print_cr(" file="); - out->print_cr(" If the filename contains %%p and/or %%t, they will expand to the JVM's PID and startup timestamp, respectively."); + out->print_cr(" If the filename contains %%p, %%t and/or %%hn, they will expand to the JVM's PID, startup timestamp and host name, respectively."); out->cr(); out->print_cr("Available log output options:"); diff --git a/src/hotspot/share/logging/logFileOutput.cpp b/src/hotspot/share/logging/logFileOutput.cpp index 2350b37e726..783be865861 100644 --- a/src/hotspot/share/logging/logFileOutput.cpp +++ b/src/hotspot/share/logging/logFileOutput.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2023, 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 @@ -38,6 +38,7 @@ const char* const LogFileOutput::FileOpenMode = "a"; const char* const LogFileOutput::PidFilenamePlaceholder = "%p"; const char* const LogFileOutput::TimestampFilenamePlaceholder = "%t"; const char* const LogFileOutput::TimestampFormat = "%Y-%m-%d_%H-%M-%S"; +const char* const LogFileOutput::HostnameFilenamePlaceholder = "%hn"; const char* const LogFileOutput::FileSizeOptionKey = "filesize"; const char* const LogFileOutput::FileCountOptionKey = "filecount"; char LogFileOutput::_pid_str[PidBufferSize]; @@ -378,81 +379,81 @@ void LogFileOutput::rotate() { char* LogFileOutput::make_file_name(const char* file_name, const char* pid_string, const char* timestamp_string) { + char hostname_string[HostnameBufferSize]; char* result = nullptr; - // Lets start finding out if we have any %d and/or %t in the name. + // Lets start finding out if we have any %p, %t and/or %hn in the name. // We will only replace the first occurrence of any placeholder const char* pid = strstr(file_name, PidFilenamePlaceholder); const char* timestamp = strstr(file_name, TimestampFilenamePlaceholder); + const char* hostname = strstr(file_name, HostnameFilenamePlaceholder); - if (pid == nullptr && timestamp == nullptr) { + if (pid == nullptr && timestamp == nullptr && hostname == nullptr) { // We found no place-holders, return the simple filename return os::strdup_check_oom(file_name, mtLogging); } // At least one of the place-holders were found in the file_name - const char* first = ""; - size_t first_pos = SIZE_MAX; - size_t first_replace_len = 0; - - const char* second = ""; - size_t second_pos = SIZE_MAX; - size_t second_replace_len = 0; - - // If we found a %p, then setup our variables accordingly + size_t result_len = strlen(file_name); if (pid != nullptr) { - if (timestamp == nullptr || pid < timestamp) { - first = pid_string; - first_pos = pid - file_name; - first_replace_len = strlen(PidFilenamePlaceholder); - } else { - second = pid_string; - second_pos = pid - file_name; - second_replace_len = strlen(PidFilenamePlaceholder); - } + result_len -= strlen(PidFilenamePlaceholder); + result_len += strlen(pid_string); } - if (timestamp != nullptr) { - if (pid == nullptr || timestamp < pid) { - first = timestamp_string; - first_pos = timestamp - file_name; - first_replace_len = strlen(TimestampFilenamePlaceholder); - } else { - second = timestamp_string; - second_pos = timestamp - file_name; - second_replace_len = strlen(TimestampFilenamePlaceholder); + result_len -= strlen(TimestampFilenamePlaceholder); + result_len += strlen(timestamp_string); + } + if (hostname != nullptr) { + if (!os::get_host_name(hostname_string, sizeof(hostname_string))) { + int res = jio_snprintf(hostname_string, sizeof(hostname_string), "unknown-host"); + assert(res > 0, "Hostname buffer too small"); } + result_len -= strlen(HostnameFilenamePlaceholder); + result_len += strlen(hostname_string); } - - size_t first_len = strlen(first); - size_t second_len = strlen(second); - // Allocate the new buffer, size it to hold all we want to put in there +1. - size_t result_len = strlen(file_name) + first_len - first_replace_len + second_len - second_replace_len; result = NEW_C_HEAP_ARRAY(char, result_len + 1, mtLogging); // Assemble the strings size_t file_name_pos = 0; size_t i = 0; while (i < result_len) { - if (file_name_pos == first_pos) { - // We are in the range of the first placeholder - strcpy(result + i, first); - // Bump output buffer position with length of replacing string - i += first_len; - // Bump source buffer position to skip placeholder - file_name_pos += first_replace_len; - } else if (file_name_pos == second_pos) { - // We are in the range of the second placeholder - strcpy(result + i, second); - i += second_len; - file_name_pos += second_replace_len; - } else { - // Else, copy char by char of the original file - result[i] = file_name[file_name_pos++]; - i++; + if (file_name[file_name_pos] == '%') { + // Replace the first occurrence of any placeholder + if (pid != nullptr && strncmp(&file_name[file_name_pos], + PidFilenamePlaceholder, + strlen(PidFilenamePlaceholder)) == 0) { + strcpy(result + i, pid_string); + i += strlen(pid_string); + file_name_pos += strlen(PidFilenamePlaceholder); + pid = nullptr; + continue; + } + if (timestamp != nullptr && strncmp(&file_name[file_name_pos], + TimestampFilenamePlaceholder, + strlen(TimestampFilenamePlaceholder)) == 0) { + strcpy(result + i, timestamp_string); + i += strlen(timestamp_string); + file_name_pos += strlen(TimestampFilenamePlaceholder); + timestamp = nullptr; + continue; + } + if (hostname != nullptr && strncmp(&file_name[file_name_pos], + HostnameFilenamePlaceholder, + strlen(HostnameFilenamePlaceholder)) == 0) { + strcpy(result + i, hostname_string); + i += strlen(hostname_string); + file_name_pos += strlen(HostnameFilenamePlaceholder); + hostname = nullptr; + continue; + } } + // Else, copy char by char of the original file + result[i++] = file_name[file_name_pos++]; } + assert(i == result_len, "should be"); + assert(file_name[file_name_pos] == '\0', "should be"); + // Add terminating char result[result_len] = '\0'; return result; diff --git a/src/hotspot/share/logging/logFileOutput.hpp b/src/hotspot/share/logging/logFileOutput.hpp index aeac7f98f2d..6189cd08682 100644 --- a/src/hotspot/share/logging/logFileOutput.hpp +++ b/src/hotspot/share/logging/logFileOutput.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2021, 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 @@ -39,10 +39,12 @@ class LogFileOutput : public LogFileStreamOutput { static const char* const PidFilenamePlaceholder; static const char* const TimestampFilenamePlaceholder; static const char* const TimestampFormat; + static const char* const HostnameFilenamePlaceholder; static const size_t DefaultFileCount = 5; static const size_t DefaultFileSize = 20 * M; static const size_t StartTimeBufferSize = 20; static const size_t PidBufferSize = 21; + static const size_t HostnameBufferSize = 512; static const uint MaxRotationFileCount = 1000; static char _pid_str[PidBufferSize]; static char _vm_start_time_str[StartTimeBufferSize]; diff --git a/src/hotspot/share/logging/logTag.hpp b/src/hotspot/share/logging/logTag.hpp index baa3891b2d1..eb289957b5c 100644 --- a/src/hotspot/share/logging/logTag.hpp +++ b/src/hotspot/share/logging/logTag.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2023, 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 @@ -104,6 +104,7 @@ class outputStream; LOG_TAG(itables) \ LOG_TAG(jfr) \ LOG_TAG(jit) \ + LOG_TAG(jmethod) \ LOG_TAG(jni) \ LOG_TAG(jvmci) \ LOG_TAG(jvmti) \ diff --git a/src/hotspot/share/memory/heapInspection.cpp b/src/hotspot/share/memory/heapInspection.cpp index 262dc62d977..b5b9e9506c7 100644 --- a/src/hotspot/share/memory/heapInspection.cpp +++ b/src/hotspot/share/memory/heapInspection.cpp @@ -83,14 +83,14 @@ const char* KlassInfoEntry::name() const { if (_klass->name() != nullptr) { name = _klass->external_name(); } else { - if (_klass == Universe::boolArrayKlassObj()) name = ""; else - if (_klass == Universe::charArrayKlassObj()) name = ""; else - if (_klass == Universe::floatArrayKlassObj()) name = ""; else - if (_klass == Universe::doubleArrayKlassObj()) name = ""; else - if (_klass == Universe::byteArrayKlassObj()) name = ""; else - if (_klass == Universe::shortArrayKlassObj()) name = ""; else - if (_klass == Universe::intArrayKlassObj()) name = ""; else - if (_klass == Universe::longArrayKlassObj()) name = ""; else + if (_klass == Universe::boolArrayKlass()) name = ""; else + if (_klass == Universe::charArrayKlass()) name = ""; else + if (_klass == Universe::floatArrayKlass()) name = ""; else + if (_klass == Universe::doubleArrayKlass()) name = ""; else + if (_klass == Universe::byteArrayKlass()) name = ""; else + if (_klass == Universe::shortArrayKlass()) name = ""; else + if (_klass == Universe::intArrayKlass()) name = ""; else + if (_klass == Universe::longArrayKlass()) name = ""; else name = ""; } return name; @@ -170,7 +170,7 @@ class KlassInfoTable::AllClassesFinder : public LockedClassesDo { KlassInfoTable::KlassInfoTable(bool add_all_classes) { _size_of_instances_in_words = 0; - _ref = (HeapWord*) Universe::boolArrayKlassObj(); + _ref = (uintptr_t) Universe::boolArrayKlass(); _buckets = (KlassInfoBucket*) AllocateHeap(sizeof(KlassInfoBucket) * _num_buckets, mtInternal, CURRENT_PC, AllocFailStrategy::RETURN_NULL); @@ -196,7 +196,7 @@ KlassInfoTable::~KlassInfoTable() { } uint KlassInfoTable::hash(const Klass* p) { - return (uint)(((uintptr_t)p - (uintptr_t)_ref) >> 2); + return (uint)(((uintptr_t)p - _ref) >> 2); } KlassInfoEntry* KlassInfoTable::lookup(Klass* k) { diff --git a/src/hotspot/share/memory/heapInspection.hpp b/src/hotspot/share/memory/heapInspection.hpp index 4282e99a199..7c4848030c6 100644 --- a/src/hotspot/share/memory/heapInspection.hpp +++ b/src/hotspot/share/memory/heapInspection.hpp @@ -108,9 +108,8 @@ class KlassInfoTable: public StackObj { size_t _size_of_instances_in_words; // An aligned reference address (typically the least - // address in the perm gen) used for hashing klass - // objects. - HeapWord* _ref; + // address in the metaspace) used for hashing klasses. + uintptr_t _ref; KlassInfoBucket* _buckets; uint hash(const Klass* p); diff --git a/src/hotspot/share/memory/iterator.cpp b/src/hotspot/share/memory/iterator.cpp index d9dedf6e211..e83b2a59646 100644 --- a/src/hotspot/share/memory/iterator.cpp +++ b/src/hotspot/share/memory/iterator.cpp @@ -41,23 +41,16 @@ void ObjectToOopClosure::do_object(oop obj) { obj->oop_iterate(_cl); } -void CodeBlobToOopClosure::do_nmethod(nmethod* nm) { +void NMethodToOopClosure::do_nmethod(nmethod* nm) { nm->oops_do(_cl); if (_fix_relocations) { nm->fix_oop_relocations(); } } -void CodeBlobToOopClosure::do_code_blob(CodeBlob* cb) { - nmethod* nm = cb->as_nmethod_or_null(); - if (nm != nullptr) { - do_nmethod(nm); - } -} - -void MarkingCodeBlobClosure::do_code_blob(CodeBlob* cb) { - nmethod* nm = cb->as_nmethod_or_null(); - if (nm != nullptr && nm->oops_do_try_claim()) { +void MarkingNMethodClosure::do_nmethod(nmethod* nm) { + assert(nm != nullptr, "Unexpected nullptr"); + if (nm->oops_do_try_claim()) { // Process the oops in the nmethod nm->oops_do(_cl); @@ -76,10 +69,3 @@ void MarkingCodeBlobClosure::do_code_blob(CodeBlob* cb) { } } } - -void CodeBlobToNMethodClosure::do_code_blob(CodeBlob* cb) { - nmethod* nm = cb->as_nmethod_or_null(); - if (nm != nullptr) { - _nm_cl->do_nmethod(nm); - } -} diff --git a/src/hotspot/share/memory/iterator.hpp b/src/hotspot/share/memory/iterator.hpp index d29b11f3271..044951142b0 100644 --- a/src/hotspot/share/memory/iterator.hpp +++ b/src/hotspot/share/memory/iterator.hpp @@ -232,56 +232,40 @@ class ObjectToOopClosure: public ObjectClosure { ObjectToOopClosure(OopIterateClosure* cl) : _cl(cl) {} }; -// CodeBlobClosure is used for iterating through code blobs +// NMethodClosure is used for iterating through nmethods // in the code cache or on thread stacks -class CodeBlobClosure : public Closure { +class NMethodClosure : public Closure { public: - // Called for each code blob. - virtual void do_code_blob(CodeBlob* cb) = 0; + virtual void do_nmethod(nmethod* n) = 0; }; -// Applies an oop closure to all ref fields in code blobs +// Applies an oop closure to all ref fields in nmethods // iterated over in an object iteration. -class CodeBlobToOopClosure : public CodeBlobClosure { +class NMethodToOopClosure : public NMethodClosure { protected: OopClosure* _cl; bool _fix_relocations; - void do_nmethod(nmethod* nm); public: // If fix_relocations(), then cl must copy objects to their new location immediately to avoid // patching nmethods with the old locations. - CodeBlobToOopClosure(OopClosure* cl, bool fix_relocations) : _cl(cl), _fix_relocations(fix_relocations) {} - virtual void do_code_blob(CodeBlob* cb); + NMethodToOopClosure(OopClosure* cl, bool fix_relocations) : _cl(cl), _fix_relocations(fix_relocations) {} + void do_nmethod(nmethod* nm) override; bool fix_relocations() const { return _fix_relocations; } const static bool FixRelocations = true; }; -class MarkingCodeBlobClosure : public CodeBlobToOopClosure { +class MarkingNMethodClosure : public NMethodToOopClosure { bool _keepalive_nmethods; public: - MarkingCodeBlobClosure(OopClosure* cl, bool fix_relocations, bool keepalive_nmethods) : - CodeBlobToOopClosure(cl, fix_relocations), + MarkingNMethodClosure(OopClosure* cl, bool fix_relocations, bool keepalive_nmethods) : + NMethodToOopClosure(cl, fix_relocations), _keepalive_nmethods(keepalive_nmethods) {} - // Called for each code blob, but at most once per unique blob. - virtual void do_code_blob(CodeBlob* cb); -}; - -class NMethodClosure : public Closure { - public: - virtual void do_nmethod(nmethod* n) = 0; -}; - -class CodeBlobToNMethodClosure : public CodeBlobClosure { - NMethodClosure* const _nm_cl; - - public: - CodeBlobToNMethodClosure(NMethodClosure* nm_cl) : _nm_cl(nm_cl) {} - - virtual void do_code_blob(CodeBlob* cb); + // Called for each nmethod. + virtual void do_nmethod(nmethod* nm); }; // MonitorClosure is used for iterating over monitors in the monitors cache diff --git a/src/hotspot/share/memory/oopFactory.cpp b/src/hotspot/share/memory/oopFactory.cpp index 2e08e62a688..02cd7108cdf 100644 --- a/src/hotspot/share/memory/oopFactory.cpp +++ b/src/hotspot/share/memory/oopFactory.cpp @@ -41,41 +41,41 @@ #include "utilities/utf8.hpp" typeArrayOop oopFactory::new_boolArray(int length, TRAPS) { - return TypeArrayKlass::cast(Universe::boolArrayKlassObj())->allocate(length, THREAD); + return Universe::boolArrayKlass()->allocate(length, THREAD); } typeArrayOop oopFactory::new_charArray(int length, TRAPS) { - return TypeArrayKlass::cast(Universe::charArrayKlassObj())->allocate(length, THREAD); + return Universe::charArrayKlass()->allocate(length, THREAD); } typeArrayOop oopFactory::new_floatArray(int length, TRAPS) { - return TypeArrayKlass::cast(Universe::floatArrayKlassObj())->allocate(length, THREAD); + return Universe::floatArrayKlass()->allocate(length, THREAD); } typeArrayOop oopFactory::new_doubleArray(int length, TRAPS) { - return TypeArrayKlass::cast(Universe::doubleArrayKlassObj())->allocate(length, THREAD); + return Universe::doubleArrayKlass()->allocate(length, THREAD); } typeArrayOop oopFactory::new_byteArray(int length, TRAPS) { - return TypeArrayKlass::cast(Universe::byteArrayKlassObj())->allocate(length, THREAD); + return Universe::byteArrayKlass()->allocate(length, THREAD); } typeArrayOop oopFactory::new_shortArray(int length, TRAPS) { - return TypeArrayKlass::cast(Universe::shortArrayKlassObj())->allocate(length, THREAD); + return Universe::shortArrayKlass()->allocate(length, THREAD); } typeArrayOop oopFactory::new_intArray(int length, TRAPS) { - return TypeArrayKlass::cast(Universe::intArrayKlassObj())->allocate(length, THREAD); + return Universe::intArrayKlass()->allocate(length, THREAD); } typeArrayOop oopFactory::new_longArray(int length, TRAPS) { - return TypeArrayKlass::cast(Universe::longArrayKlassObj())->allocate(length, THREAD); + return Universe::longArrayKlass()->allocate(length, THREAD); } // create java.lang.Object[] objArrayOop oopFactory::new_objectArray(int length, TRAPS) { - assert(Universe::objectArrayKlassObj() != nullptr, "Too early?"); - return ObjArrayKlass::cast(Universe::objectArrayKlassObj())->allocate(length, THREAD); + assert(Universe::objectArrayKlass() != nullptr, "Too early?"); + return Universe::objectArrayKlass()->allocate(length, THREAD); } typeArrayOop oopFactory::new_charArray(const char* utf8_str, TRAPS) { @@ -88,10 +88,8 @@ typeArrayOop oopFactory::new_charArray(const char* utf8_str, TRAPS) { } typeArrayOop oopFactory::new_typeArray(BasicType type, int length, TRAPS) { - Klass* type_asKlassOop = Universe::typeArrayKlassObj(type); - TypeArrayKlass* type_asArrayKlass = TypeArrayKlass::cast(type_asKlassOop); - typeArrayOop result = type_asArrayKlass->allocate(length, THREAD); - return result; + TypeArrayKlass* klass = Universe::typeArrayKlass(type); + return klass->allocate(length, THREAD); } // Create a Java array that points to Symbol. @@ -100,17 +98,12 @@ typeArrayOop oopFactory::new_typeArray(BasicType type, int length, TRAPS) { // this. They cast Symbol* into this type. typeArrayOop oopFactory::new_symbolArray(int length, TRAPS) { BasicType type = LP64_ONLY(T_LONG) NOT_LP64(T_INT); - Klass* type_asKlassOop = Universe::typeArrayKlassObj(type); - TypeArrayKlass* type_asArrayKlass = TypeArrayKlass::cast(type_asKlassOop); - typeArrayOop result = type_asArrayKlass->allocate(length, THREAD); - return result; + return new_typeArray(type, length, THREAD); } typeArrayOop oopFactory::new_typeArray_nozero(BasicType type, int length, TRAPS) { - Klass* type_asKlassOop = Universe::typeArrayKlassObj(type); - TypeArrayKlass* type_asArrayKlass = TypeArrayKlass::cast(type_asKlassOop); - typeArrayOop result = type_asArrayKlass->allocate_common(length, false, THREAD); - return result; + TypeArrayKlass* klass = Universe::typeArrayKlass(type); + return klass->allocate_common(length, false, THREAD); } diff --git a/src/hotspot/share/memory/universe.cpp b/src/hotspot/share/memory/universe.cpp index eacede462db..3769285d08c 100644 --- a/src/hotspot/share/memory/universe.cpp +++ b/src/hotspot/share/memory/universe.cpp @@ -111,9 +111,9 @@ static LatestMethodCache _throw_no_such_method_error_cache; // Unsafe.throwNoSuc static LatestMethodCache _do_stack_walk_cache; // AbstractStackWalker.doStackWalk() // Known objects -Klass* Universe::_typeArrayKlassObjs[T_LONG+1] = { nullptr /*, nullptr...*/ }; -Klass* Universe::_objectArrayKlassObj = nullptr; -Klass* Universe::_fillerArrayKlassObj = nullptr; +TypeArrayKlass* Universe::_typeArrayKlasses[T_LONG+1] = { nullptr /*, nullptr...*/ }; +ObjArrayKlass* Universe::_objectArrayKlass = nullptr; +Klass* Universe::_fillerArrayKlass = nullptr; OopHandle Universe::_basic_type_mirrors[T_VOID+1]; #if INCLUDE_CDS_JAVA_HEAP int Universe::_archived_basic_type_mirror_indices[T_VOID+1]; @@ -265,21 +265,21 @@ oop Universe::java_mirror(BasicType t) { void Universe::basic_type_classes_do(KlassClosure *closure) { for (int i = T_BOOLEAN; i < T_LONG+1; i++) { - closure->do_klass(_typeArrayKlassObjs[i]); + closure->do_klass(_typeArrayKlasses[i]); } // We don't do the following because it will confuse JVMTI. - // _fillerArrayKlassObj is used only by GC, which doesn't need to see + // _fillerArrayKlass is used only by GC, which doesn't need to see // this klass from basic_type_classes_do(). // - // closure->do_klass(_fillerArrayKlassObj); + // closure->do_klass(_fillerArrayKlass); } void Universe::metaspace_pointers_do(MetaspaceClosure* it) { - it->push(&_fillerArrayKlassObj); + it->push(&_fillerArrayKlass); for (int i = 0; i < T_LONG+1; i++) { - it->push(&_typeArrayKlassObjs[i]); + it->push(&_typeArrayKlasses[i]); } - it->push(&_objectArrayKlassObj); + it->push(&_objectArrayKlass); it->push(&_the_empty_int_array); it->push(&_the_empty_short_array); @@ -334,12 +334,12 @@ void Universe::serialize(SerializeClosure* f) { _virtual_machine_error.serialize(f); #endif - f->do_ptr(&_fillerArrayKlassObj); + f->do_ptr(&_fillerArrayKlass); for (int i = 0; i < T_LONG+1; i++) { - f->do_ptr(&_typeArrayKlassObjs[i]); + f->do_ptr(&_typeArrayKlasses[i]); } - f->do_ptr(&_objectArrayKlassObj); + f->do_ptr(&_objectArrayKlass); f->do_ptr(&_the_array_interfaces_array); f->do_ptr(&_the_empty_int_array); f->do_ptr(&_the_empty_short_array); @@ -396,9 +396,9 @@ void Universe::genesis(TRAPS) { // Initialization of the fillerArrayKlass must come before regular // int-TypeArrayKlass so that the int-Array mirror points to the // int-TypeArrayKlass. - _fillerArrayKlassObj = TypeArrayKlass::create_klass(T_INT, "[Ljdk/internal/vm/FillerElement;", CHECK); + _fillerArrayKlass = TypeArrayKlass::create_klass(T_INT, "[Ljdk/internal/vm/FillerElement;", CHECK); for (int i = T_BOOLEAN; i < T_LONG+1; i++) { - _typeArrayKlassObjs[i] = TypeArrayKlass::create_klass((BasicType)i, CHECK); + _typeArrayKlasses[i] = TypeArrayKlass::create_klass((BasicType)i, CHECK); } ClassLoaderData* null_cld = ClassLoaderData::the_null_class_loader_data(); @@ -437,18 +437,18 @@ void Universe::genesis(TRAPS) { _the_array_interfaces_array->at_put(1, vmClasses::Serializable_klass()); } - initialize_basic_type_klass(_fillerArrayKlassObj, CHECK); + initialize_basic_type_klass(_fillerArrayKlass, CHECK); - initialize_basic_type_klass(boolArrayKlassObj(), CHECK); - initialize_basic_type_klass(charArrayKlassObj(), CHECK); - initialize_basic_type_klass(floatArrayKlassObj(), CHECK); - initialize_basic_type_klass(doubleArrayKlassObj(), CHECK); - initialize_basic_type_klass(byteArrayKlassObj(), CHECK); - initialize_basic_type_klass(shortArrayKlassObj(), CHECK); - initialize_basic_type_klass(intArrayKlassObj(), CHECK); - initialize_basic_type_klass(longArrayKlassObj(), CHECK); + initialize_basic_type_klass(boolArrayKlass(), CHECK); + initialize_basic_type_klass(charArrayKlass(), CHECK); + initialize_basic_type_klass(floatArrayKlass(), CHECK); + initialize_basic_type_klass(doubleArrayKlass(), CHECK); + initialize_basic_type_klass(byteArrayKlass(), CHECK); + initialize_basic_type_klass(shortArrayKlass(), CHECK); + initialize_basic_type_klass(intArrayKlass(), CHECK); + initialize_basic_type_klass(longArrayKlass(), CHECK); - assert(_fillerArrayKlassObj != intArrayKlassObj(), + assert(_fillerArrayKlass != intArrayKlass(), "Internal filler array klass should be different to int array Klass"); } // end of core bootstrapping @@ -472,15 +472,17 @@ void Universe::genesis(TRAPS) { // ordinary object arrays, _objectArrayKlass will be loaded when // SystemDictionary::initialize(CHECK); is run. See the extra check // for Object_klass_loaded in objArrayKlassKlass::allocate_objArray_klass_impl. - _objectArrayKlassObj = InstanceKlass:: - cast(vmClasses::Object_klass())->array_klass(1, CHECK); + { + Klass* oak = vmClasses::Object_klass()->array_klass(CHECK); + _objectArrayKlass = ObjArrayKlass::cast(oak); + } // OLD // Add the class to the class hierarchy manually to make sure that // its vtable is initialized after core bootstrapping is completed. // --- // New // Have already been initialized. - _objectArrayKlassObj->append_to_sibling_list(); + _objectArrayKlass->append_to_sibling_list(); #ifdef ASSERT if (FullGCALot) { diff --git a/src/hotspot/share/memory/universe.hpp b/src/hotspot/share/memory/universe.hpp index f56889559b8..c5e366f507f 100644 --- a/src/hotspot/share/memory/universe.hpp +++ b/src/hotspot/share/memory/universe.hpp @@ -47,7 +47,7 @@ class SerializeClosure; class Universe: AllStatic { // Ugh. Universe is much too friendly. - friend class MarkSweep; + friend class SerialFullGC; friend class oopDesc; friend class ClassLoader; friend class SystemDictionary; @@ -65,11 +65,11 @@ class Universe: AllStatic { private: // Known classes in the VM - static Klass* _typeArrayKlassObjs[T_LONG+1]; - static Klass* _objectArrayKlassObj; + static TypeArrayKlass* _typeArrayKlasses[T_LONG+1]; + static ObjArrayKlass* _objectArrayKlass; // Special int-Array that represents filler objects that are used by GC to overwrite // dead objects. References to them are generally an error. - static Klass* _fillerArrayKlassObj; + static Klass* _fillerArrayKlass; // Known objects in the VM static OopHandle _main_thread_group; // Reference to the main thread group object @@ -174,24 +174,24 @@ class Universe: AllStatic { static void set_verify_data(uintptr_t mask, uintptr_t bits) PRODUCT_RETURN; // Known classes in the VM - static Klass* boolArrayKlassObj() { return typeArrayKlassObj(T_BOOLEAN); } - static Klass* byteArrayKlassObj() { return typeArrayKlassObj(T_BYTE); } - static Klass* charArrayKlassObj() { return typeArrayKlassObj(T_CHAR); } - static Klass* intArrayKlassObj() { return typeArrayKlassObj(T_INT); } - static Klass* shortArrayKlassObj() { return typeArrayKlassObj(T_SHORT); } - static Klass* longArrayKlassObj() { return typeArrayKlassObj(T_LONG); } - static Klass* floatArrayKlassObj() { return typeArrayKlassObj(T_FLOAT); } - static Klass* doubleArrayKlassObj() { return typeArrayKlassObj(T_DOUBLE); } + static TypeArrayKlass* boolArrayKlass() { return typeArrayKlass(T_BOOLEAN); } + static TypeArrayKlass* byteArrayKlass() { return typeArrayKlass(T_BYTE); } + static TypeArrayKlass* charArrayKlass() { return typeArrayKlass(T_CHAR); } + static TypeArrayKlass* intArrayKlass() { return typeArrayKlass(T_INT); } + static TypeArrayKlass* shortArrayKlass() { return typeArrayKlass(T_SHORT); } + static TypeArrayKlass* longArrayKlass() { return typeArrayKlass(T_LONG); } + static TypeArrayKlass* floatArrayKlass() { return typeArrayKlass(T_FLOAT); } + static TypeArrayKlass* doubleArrayKlass() { return typeArrayKlass(T_DOUBLE); } - static Klass* objectArrayKlassObj() { return _objectArrayKlassObj; } + static ObjArrayKlass* objectArrayKlass() { return _objectArrayKlass; } - static Klass* fillerArrayKlassObj() { return _fillerArrayKlassObj; } + static Klass* fillerArrayKlass() { return _fillerArrayKlass; } - static Klass* typeArrayKlassObj(BasicType t) { + static TypeArrayKlass* typeArrayKlass(BasicType t) { assert((uint)t >= T_BOOLEAN, "range check for type: %s", type2name(t)); assert((uint)t < T_LONG+1, "range check for type: %s", type2name(t)); - assert(_typeArrayKlassObjs[t] != nullptr, "domain check"); - return _typeArrayKlassObjs[t]; + assert(_typeArrayKlasses[t] != nullptr, "domain check"); + return _typeArrayKlasses[t]; } // Known objects in the VM diff --git a/src/hotspot/share/memory/virtualspace.cpp b/src/hotspot/share/memory/virtualspace.cpp index 919ab3a6c6a..a75d9f076ad 100644 --- a/src/hotspot/share/memory/virtualspace.cpp +++ b/src/hotspot/share/memory/virtualspace.cpp @@ -314,15 +314,18 @@ ReservedSpace ReservedSpace::first_part(size_t partition_size, size_t alignment) return result; } - -ReservedSpace -ReservedSpace::last_part(size_t partition_size, size_t alignment) { +ReservedSpace ReservedSpace::last_part(size_t partition_size, size_t alignment) { assert(partition_size <= size(), "partition failed"); ReservedSpace result(base() + partition_size, size() - partition_size, alignment, page_size(), special(), executable()); return result; } +ReservedSpace ReservedSpace::partition(size_t offset, size_t partition_size, size_t alignment) { + assert(offset + partition_size <= size(), "partition failed"); + ReservedSpace result(base() + offset, partition_size, alignment, page_size(), special(), executable()); + return result; +} size_t ReservedSpace::page_align_size_up(size_t size) { return align_up(size, os::vm_page_size()); diff --git a/src/hotspot/share/memory/virtualspace.hpp b/src/hotspot/share/memory/virtualspace.hpp index 264ed0d9749..046ad0cf7a4 100644 --- a/src/hotspot/share/memory/virtualspace.hpp +++ b/src/hotspot/share/memory/virtualspace.hpp @@ -95,10 +95,12 @@ class ReservedSpace { // This splits the space into two spaces, the first part of which will be returned. ReservedSpace first_part(size_t partition_size, size_t alignment); ReservedSpace last_part (size_t partition_size, size_t alignment); + ReservedSpace partition (size_t offset, size_t partition_size, size_t alignment); // These simply call the above using the default alignment. inline ReservedSpace first_part(size_t partition_size); inline ReservedSpace last_part (size_t partition_size); + inline ReservedSpace partition (size_t offset, size_t partition_size); // Alignment static size_t page_align_size_up(size_t size); @@ -113,8 +115,7 @@ class ReservedSpace { size_t page_size, bool special, bool executable); }; -ReservedSpace -ReservedSpace::first_part(size_t partition_size) +ReservedSpace ReservedSpace::first_part(size_t partition_size) { return first_part(partition_size, alignment()); } @@ -124,6 +125,11 @@ ReservedSpace ReservedSpace::last_part(size_t partition_size) return last_part(partition_size, alignment()); } +ReservedSpace ReservedSpace::partition(size_t offset, size_t partition_size) +{ + return partition(offset, partition_size, alignment()); +} + // Class encapsulating behavior specific of memory space reserved for Java heap. class ReservedHeapSpace : public ReservedSpace { private: diff --git a/src/hotspot/share/oops/compressedKlass.hpp b/src/hotspot/share/oops/compressedKlass.hpp index e871fe5bdcc..1c1bce101a4 100644 --- a/src/hotspot/share/oops/compressedKlass.hpp +++ b/src/hotspot/share/oops/compressedKlass.hpp @@ -45,6 +45,7 @@ const uint64_t KlassEncodingMetaspaceMax = (uint64_t(max_juint) + 1) << LogKlas // For UseCompressedClassPointers. class CompressedKlassPointers : public AllStatic { friend class VMStructs; + friend class ArchiveBuilder; static address _base; static int _shift; @@ -64,6 +65,11 @@ class CompressedKlassPointers : public AllStatic { DEBUG_ONLY(static void assert_is_valid_encoding(address addr, size_t len, address base, int shift);) + static inline Klass* decode_not_null_without_asserts(narrowKlass v, address base, int shift); + static inline Klass* decode_not_null(narrowKlass v, address base, int shift); + + static inline narrowKlass encode_not_null(Klass* v, address base, int shift); + public: // Reserve a range of memory that is to contain Klass strucutures which are referenced by narrow Klass IDs. @@ -92,15 +98,15 @@ class CompressedKlassPointers : public AllStatic { static bool is_null(Klass* v) { return v == nullptr; } static bool is_null(narrowKlass v) { return v == 0; } - static inline Klass* decode_raw(narrowKlass v, address base, int shift); - static inline Klass* decode_raw(narrowKlass v); + // Versions without asserts + static inline Klass* decode_not_null_without_asserts(narrowKlass v); + static inline Klass* decode_without_asserts(narrowKlass v); + static inline Klass* decode_not_null(narrowKlass v); - static inline Klass* decode_not_null(narrowKlass v, address base, int shift); static inline Klass* decode(narrowKlass v); + static inline narrowKlass encode_not_null(Klass* v); - static inline narrowKlass encode_not_null(Klass* v, address base, int shift); static inline narrowKlass encode(Klass* v); - }; #endif // SHARE_OOPS_COMPRESSEDKLASS_HPP diff --git a/src/hotspot/share/oops/compressedKlass.inline.hpp b/src/hotspot/share/oops/compressedKlass.inline.hpp index 134e9fec863..87ef2102b38 100644 --- a/src/hotspot/share/oops/compressedKlass.inline.hpp +++ b/src/hotspot/share/oops/compressedKlass.inline.hpp @@ -36,33 +36,17 @@ static inline bool check_alignment(Klass* v) { return (intptr_t)v % KlassAlignmentInBytes == 0; } -inline Klass* CompressedKlassPointers::decode_raw(narrowKlass v) { - return decode_raw(v, base(), shift()); -} - -inline Klass* CompressedKlassPointers::decode_raw(narrowKlass v, address narrow_base, int shift) { +inline Klass* CompressedKlassPointers::decode_not_null_without_asserts(narrowKlass v, address narrow_base, int shift) { return (Klass*)((uintptr_t)narrow_base +((uintptr_t)v << shift)); } -inline Klass* CompressedKlassPointers::decode_not_null(narrowKlass v) { - return decode_not_null(v, base(), shift()); -} - inline Klass* CompressedKlassPointers::decode_not_null(narrowKlass v, address narrow_base, int shift) { assert(!is_null(v), "narrow klass value can never be zero"); - Klass* result = decode_raw(v, narrow_base, shift); + Klass* result = decode_not_null_without_asserts(v, narrow_base, shift); assert(check_alignment(result), "address not aligned: " PTR_FORMAT, p2i(result)); return result; } -inline Klass* CompressedKlassPointers::decode(narrowKlass v) { - return is_null(v) ? nullptr : decode_not_null(v); -} - -inline narrowKlass CompressedKlassPointers::encode_not_null(Klass* v) { - return encode_not_null(v, base(), shift()); -} - inline narrowKlass CompressedKlassPointers::encode_not_null(Klass* v, address narrow_base, int shift) { assert(!is_null(v), "klass value can never be zero"); assert(check_alignment(v), "Address not aligned"); @@ -74,6 +58,26 @@ inline narrowKlass CompressedKlassPointers::encode_not_null(Klass* v, address na return (narrowKlass)result; } +inline Klass* CompressedKlassPointers::decode_not_null_without_asserts(narrowKlass v) { + return decode_not_null_without_asserts(v, base(), shift()); +} + +inline Klass* CompressedKlassPointers::decode_without_asserts(narrowKlass v) { + return is_null(v) ? nullptr : decode_not_null_without_asserts(v); +} + +inline Klass* CompressedKlassPointers::decode_not_null(narrowKlass v) { + return decode_not_null(v, base(), shift()); +} + +inline Klass* CompressedKlassPointers::decode(narrowKlass v) { + return is_null(v) ? nullptr : decode_not_null(v); +} + +inline narrowKlass CompressedKlassPointers::encode_not_null(Klass* v) { + return encode_not_null(v, base(), shift()); +} + inline narrowKlass CompressedKlassPointers::encode(Klass* v) { return is_null(v) ? (narrowKlass)0 : encode_not_null(v); } diff --git a/src/hotspot/share/oops/instanceKlass.cpp b/src/hotspot/share/oops/instanceKlass.cpp index 288944c466d..ec92a9e8227 100644 --- a/src/hotspot/share/oops/instanceKlass.cpp +++ b/src/hotspot/share/oops/instanceKlass.cpp @@ -2267,16 +2267,26 @@ void InstanceKlass::set_enclosing_method_indices(u2 class_index, } } +jmethodID InstanceKlass::update_jmethod_id(jmethodID* jmeths, Method* method, int idnum) { + if (method->is_old() && !method->is_obsolete()) { + // If the method passed in is old (but not obsolete), use the current version. + method = method_with_idnum((int)idnum); + assert(method != nullptr, "old and but not obsolete, so should exist"); + } + jmethodID new_id = Method::make_jmethod_id(class_loader_data(), method); + Atomic::release_store(&jmeths[idnum + 1], new_id); + return new_id; +} + // Lookup or create a jmethodID. // This code is called by the VMThread and JavaThreads so the // locking has to be done very carefully to avoid deadlocks // and/or other cache consistency problems. // jmethodID InstanceKlass::get_jmethod_id(const methodHandle& method_h) { - size_t idnum = (size_t)method_h->method_idnum(); + Method* method = method_h(); + int idnum = method->method_idnum(); jmethodID* jmeths = methods_jmethod_ids_acquire(); - size_t length = 0; - jmethodID id = nullptr; // We use a double-check locking idiom here because this cache is // performance sensitive. In the normal system, this cache only @@ -2288,82 +2298,65 @@ jmethodID InstanceKlass::get_jmethod_id(const methodHandle& method_h) { // seen either. Cache reads of existing jmethodIDs proceed without a // lock, but cache writes of a new jmethodID requires uniqueness and // creation of the cache itself requires no leaks so a lock is - // generally acquired in those two cases. + // acquired in those two cases. // - // If the RedefineClasses() API has been used, then this cache can - // grow and we'll have transitions from non-null to bigger non-null. - // Cache creation requires no leaks and we require safety between all - // cache accesses and freeing of the old cache so a lock is generally - // acquired when the RedefineClasses() API has been used. - - if (jmeths != nullptr) { - // the cache already exists - if (!idnum_can_increment()) { - // the cache can't grow so we can just get the current values - get_jmethod_id_length_value(jmeths, idnum, &length, &id); - } else { - MutexLocker ml(JmethodIdCreation_lock, Mutex::_no_safepoint_check_flag); - get_jmethod_id_length_value(jmeths, idnum, &length, &id); - } - } - // implied else: - // we need to allocate a cache so default length and id values are good - - if (jmeths == nullptr || // no cache yet - length <= idnum || // cache is too short - id == nullptr) { // cache doesn't contain entry - - // This function can be called by the VMThread or GC worker threads so we - // have to do all things that might block on a safepoint before grabbing the lock. - // Otherwise, we can deadlock with the VMThread or have a cache - // consistency issue. These vars keep track of what we might have - // to free after the lock is dropped. - jmethodID to_dealloc_id = nullptr; - jmethodID* to_dealloc_jmeths = nullptr; - - // may not allocate new_jmeths or use it if we allocate it - jmethodID* new_jmeths = nullptr; - if (length <= idnum) { - // allocate a new cache that might be used - size_t size = MAX2(idnum+1, (size_t)idnum_allocated_count()); - new_jmeths = NEW_C_HEAP_ARRAY(jmethodID, size+1, mtClass); - memset(new_jmeths, 0, (size+1)*sizeof(jmethodID)); + // If the RedefineClasses() API has been used, then this cache grows + // in the redefinition safepoint. + + if (jmeths == nullptr) { + MutexLocker ml(JmethodIdCreation_lock, Mutex::_no_safepoint_check_flag); + jmeths = methods_jmethod_ids_acquire(); + // Still null? + if (jmeths == nullptr) { + size_t size = idnum_allocated_count(); + assert(size > (size_t)idnum, "should already have space"); + jmeths = NEW_C_HEAP_ARRAY(jmethodID, size + 1, mtClass); + memset(jmeths, 0, (size + 1) * sizeof(jmethodID)); // cache size is stored in element[0], other elements offset by one - new_jmeths[0] = (jmethodID)size; - } - - // allocate a new jmethodID that might be used - { - MutexLocker ml(JmethodIdCreation_lock, Mutex::_no_safepoint_check_flag); - jmethodID new_id = nullptr; - if (method_h->is_old() && !method_h->is_obsolete()) { - // The method passed in is old (but not obsolete), we need to use the current version - Method* current_method = method_with_idnum((int)idnum); - assert(current_method != nullptr, "old and but not obsolete, so should exist"); - new_id = Method::make_jmethod_id(class_loader_data(), current_method); - } else { - // It is the current version of the method or an obsolete method, - // use the version passed in - new_id = Method::make_jmethod_id(class_loader_data(), method_h()); - } + jmeths[0] = (jmethodID)size; + jmethodID new_id = update_jmethod_id(jmeths, method, idnum); - id = get_jmethod_id_fetch_or_update(idnum, new_id, new_jmeths, - &to_dealloc_id, &to_dealloc_jmeths); + // publish jmeths + release_set_methods_jmethod_ids(jmeths); + return new_id; } + } - // The lock has been dropped so we can free resources. - // Free up either the old cache or the new cache if we allocated one. - if (to_dealloc_jmeths != nullptr) { - FreeHeap(to_dealloc_jmeths); - } - // free up the new ID since it wasn't needed - if (to_dealloc_id != nullptr) { - Method::destroy_jmethod_id(class_loader_data(), to_dealloc_id); + jmethodID id = Atomic::load_acquire(&jmeths[idnum + 1]); + if (id == nullptr) { + MutexLocker ml(JmethodIdCreation_lock, Mutex::_no_safepoint_check_flag); + id = jmeths[idnum + 1]; + // Still null? + if (id == nullptr) { + return update_jmethod_id(jmeths, method, idnum); } } return id; } +void InstanceKlass::update_methods_jmethod_cache() { + assert(SafepointSynchronize::is_at_safepoint(), "only called at safepoint"); + jmethodID* cache = _methods_jmethod_ids; + if (cache != nullptr) { + size_t size = idnum_allocated_count(); + size_t old_size = (size_t)cache[0]; + if (old_size < size + 1) { + // Allocate a larger one and copy entries to the new one. + // They've already been updated to point to new methods where applicable (i.e., not obsolete). + jmethodID* new_cache = NEW_C_HEAP_ARRAY(jmethodID, size + 1, mtClass); + memset(new_cache, 0, (size + 1) * sizeof(jmethodID)); + // The cache size is stored in element[0]; the other elements are offset by one. + new_cache[0] = (jmethodID)size; + + for (int i = 1; i <= (int)old_size; i++) { + new_cache[i] = cache[i]; + } + _methods_jmethod_ids = new_cache; + FREE_C_HEAP_ARRAY(jmethodID, cache); + } + } +} + // Figure out how many jmethodIDs haven't been allocated, and make // sure space for them is pre-allocated. This makes getting all // method ids much, much faster with classes with more than 8 @@ -2384,88 +2377,11 @@ void InstanceKlass::ensure_space_for_methodids(int start_offset) { } } -// Common code to fetch the jmethodID from the cache or update the -// cache with the new jmethodID. This function should never do anything -// that causes the caller to go to a safepoint or we can deadlock with -// the VMThread or have cache consistency issues. -// -jmethodID InstanceKlass::get_jmethod_id_fetch_or_update( - size_t idnum, jmethodID new_id, - jmethodID* new_jmeths, jmethodID* to_dealloc_id_p, - jmethodID** to_dealloc_jmeths_p) { - assert(new_id != nullptr, "sanity check"); - assert(to_dealloc_id_p != nullptr, "sanity check"); - assert(to_dealloc_jmeths_p != nullptr, "sanity check"); - assert(JmethodIdCreation_lock->owned_by_self(), "sanity check"); - - // reacquire the cache - we are locked, single threaded or at a safepoint - jmethodID* jmeths = methods_jmethod_ids_acquire(); - jmethodID id = nullptr; - size_t length = 0; - - if (jmeths == nullptr || // no cache yet - (length = (size_t)jmeths[0]) <= idnum) { // cache is too short - if (jmeths != nullptr) { - // copy any existing entries from the old cache - for (size_t index = 0; index < length; index++) { - new_jmeths[index+1] = jmeths[index+1]; - } - *to_dealloc_jmeths_p = jmeths; // save old cache for later delete - } - release_set_methods_jmethod_ids(jmeths = new_jmeths); - } else { - // fetch jmethodID (if any) from the existing cache - id = jmeths[idnum+1]; - *to_dealloc_jmeths_p = new_jmeths; // save new cache for later delete - } - if (id == nullptr) { - // No matching jmethodID in the existing cache or we have a new - // cache or we just grew the cache. This cache write is done here - // by the first thread to win the foot race because a jmethodID - // needs to be unique once it is generally available. - id = new_id; - - // The jmethodID cache can be read while unlocked so we have to - // make sure the new jmethodID is complete before installing it - // in the cache. - Atomic::release_store(&jmeths[idnum+1], id); - } else { - *to_dealloc_id_p = new_id; // save new id for later delete - } - return id; -} - - -// Common code to get the jmethodID cache length and the jmethodID -// value at index idnum if there is one. -// -void InstanceKlass::get_jmethod_id_length_value(jmethodID* cache, - size_t idnum, size_t *length_p, jmethodID* id_p) { - assert(cache != nullptr, "sanity check"); - assert(length_p != nullptr, "sanity check"); - assert(id_p != nullptr, "sanity check"); - - // cache size is stored in element[0], other elements offset by one - *length_p = (size_t)cache[0]; - if (*length_p <= idnum) { // cache is too short - *id_p = nullptr; - } else { - *id_p = cache[idnum+1]; // fetch jmethodID (if any) - } -} - - // Lookup a jmethodID, null if not found. Do no blocking, no allocations, no handles jmethodID InstanceKlass::jmethod_id_or_null(Method* method) { - size_t idnum = (size_t)method->method_idnum(); + int idnum = method->method_idnum(); jmethodID* jmeths = methods_jmethod_ids_acquire(); - size_t length; // length assigned as debugging crumb - jmethodID id = nullptr; - if (jmeths != nullptr && // If there is a cache - (length = (size_t)jmeths[0]) > idnum) { // and if it is long enough, - id = jmeths[idnum+1]; // Look up the id (may be null) - } - return id; + return (jmeths != nullptr) ? jmeths[idnum + 1] : nullptr; } inline DependencyContext InstanceKlass::dependencies() { @@ -2884,7 +2800,7 @@ void InstanceKlass::release_C_heap_structures(bool release_sub_metadata) { set_jni_ids(nullptr); jmethodID* jmeths = methods_jmethod_ids_acquire(); - if (jmeths != (jmethodID*)nullptr) { + if (jmeths != nullptr) { release_set_methods_jmethod_ids(nullptr); FreeHeap(jmeths); } @@ -3439,7 +3355,7 @@ void InstanceKlass::adjust_default_methods(bool* trace_name_printed) { // On-stack replacement stuff void InstanceKlass::add_osr_nmethod(nmethod* n) { - assert_lock_strong(CompiledMethod_lock); + assert_lock_strong(NMethodState_lock); #ifndef PRODUCT nmethod* prev = lookup_osr_nmethod(n->method(), n->osr_entry_bci(), n->comp_level(), true); assert(prev == nullptr || !prev->is_in_use() COMPILER2_PRESENT(|| StressRecompilation), @@ -3464,7 +3380,7 @@ void InstanceKlass::add_osr_nmethod(nmethod* n) { // Remove osr nmethod from the list. Return true if found and removed. bool InstanceKlass::remove_osr_nmethod(nmethod* n) { // This is a short non-blocking critical region, so the no safepoint check is ok. - ConditionalMutexLocker ml(CompiledMethod_lock, !CompiledMethod_lock->owned_by_self(), Mutex::_no_safepoint_check_flag); + ConditionalMutexLocker ml(NMethodState_lock, !NMethodState_lock->owned_by_self(), Mutex::_no_safepoint_check_flag); assert(n->is_osr_method(), "wrong kind of nmethod"); nmethod* last = nullptr; nmethod* cur = osr_nmethods_head(); @@ -3505,7 +3421,7 @@ bool InstanceKlass::remove_osr_nmethod(nmethod* n) { } int InstanceKlass::mark_osr_nmethods(DeoptimizationScope* deopt_scope, const Method* m) { - ConditionalMutexLocker ml(CompiledMethod_lock, !CompiledMethod_lock->owned_by_self(), Mutex::_no_safepoint_check_flag); + ConditionalMutexLocker ml(NMethodState_lock, !NMethodState_lock->owned_by_self(), Mutex::_no_safepoint_check_flag); nmethod* osr = osr_nmethods_head(); int found = 0; while (osr != nullptr) { @@ -3520,7 +3436,7 @@ int InstanceKlass::mark_osr_nmethods(DeoptimizationScope* deopt_scope, const Met } nmethod* InstanceKlass::lookup_osr_nmethod(const Method* m, int bci, int comp_level, bool match_level) const { - ConditionalMutexLocker ml(CompiledMethod_lock, !CompiledMethod_lock->owned_by_self(), Mutex::_no_safepoint_check_flag); + ConditionalMutexLocker ml(NMethodState_lock, !NMethodState_lock->owned_by_self(), Mutex::_no_safepoint_check_flag); nmethod* osr = osr_nmethods_head(); nmethod* best = nullptr; while (osr != nullptr) { diff --git a/src/hotspot/share/oops/instanceKlass.hpp b/src/hotspot/share/oops/instanceKlass.hpp index 62c861be89f..b5f598030ef 100644 --- a/src/hotspot/share/oops/instanceKlass.hpp +++ b/src/hotspot/share/oops/instanceKlass.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 @@ -237,9 +237,9 @@ class InstanceKlass: public Klass { JavaThread* volatile _init_thread; // Pointer to current thread doing initialization (to handle recursive initialization) OopMapCache* volatile _oop_map_cache; // OopMapCache for all methods in the klass (allocated lazily) - JNIid* _jni_ids; // First JNI identifier for static fields in this class - jmethodID* volatile _methods_jmethod_ids; // jmethodIDs corresponding to method_idnum, or null if none - nmethodBucket* volatile _dep_context; // packed DependencyContext structure + JNIid* _jni_ids; // First JNI identifier for static fields in this class + jmethodID* volatile _methods_jmethod_ids; // jmethodIDs corresponding to method_idnum, or null if none + nmethodBucket* volatile _dep_context; // packed DependencyContext structure uint64_t volatile _dep_context_last_cleaned; nmethod* _osr_nmethods_head; // Head of list of on-stack replacement nmethods for this class #if INCLUDE_JVMTI @@ -794,14 +794,9 @@ class InstanceKlass: public Klass { // jmethodID support jmethodID get_jmethod_id(const methodHandle& method_h); - jmethodID get_jmethod_id_fetch_or_update(size_t idnum, - jmethodID new_id, jmethodID* new_jmeths, - jmethodID* to_dealloc_id_p, - jmethodID** to_dealloc_jmeths_p); - static void get_jmethod_id_length_value(jmethodID* cache, size_t idnum, - size_t *length_p, jmethodID* id_p); void ensure_space_for_methodids(int start_offset = 0); jmethodID jmethod_id_or_null(Method* method); + void update_methods_jmethod_cache(); // annotations support Annotations* annotations() const { return _annotations; } @@ -1073,17 +1068,12 @@ class InstanceKlass: public Klass { Atomic::store(&_init_thread, thread); } - // The RedefineClasses() API can cause new method idnums to be needed - // which will cause the caches to grow. Safety requires different - // cache management logic if the caches can grow instead of just - // going from null to non-null. - bool idnum_can_increment() const { return has_been_redefined(); } inline jmethodID* methods_jmethod_ids_acquire() const; inline void release_set_methods_jmethod_ids(jmethodID* jmeths); // This nulls out jmethodIDs for all methods in 'klass' static void clear_jmethod_ids(InstanceKlass* klass); + jmethodID update_jmethod_id(jmethodID* jmeths, Method* method, int idnum); - // Lock during initialization public: // Returns the array class for the n'th dimension virtual ArrayKlass* array_klass(int n, TRAPS); diff --git a/src/hotspot/share/oops/markWord.cpp b/src/hotspot/share/oops/markWord.cpp index ad49fea3076..e861ab87182 100644 --- a/src/hotspot/share/oops/markWord.cpp +++ b/src/hotspot/share/oops/markWord.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 @@ -80,8 +80,8 @@ void markWord::print_on(outputStream* st, bool print_monitor_info) const { st->print(" locked(" INTPTR_FORMAT ")", value()); } else { st->print(" mark("); - if (is_neutral()) { // last bits = 01 - st->print("is_neutral"); + if (is_unlocked()) { // last bits = 01 + st->print("is_unlocked"); if (has_no_hash()) { st->print(" no_hash"); } else { diff --git a/src/hotspot/share/oops/markWord.hpp b/src/hotspot/share/oops/markWord.hpp index be85fb8ba82..ba89f947dcf 100644 --- a/src/hotspot/share/oops/markWord.hpp +++ b/src/hotspot/share/oops/markWord.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 @@ -143,7 +143,7 @@ class markWord { bool is_marked() const { return (mask_bits(value(), lock_mask_in_place) == marked_value); } - bool is_neutral() const { + bool is_neutral() const { // Not locked, or marked - a "clean" neutral state return (mask_bits(value(), lock_mask_in_place) == unlocked_value); } diff --git a/src/hotspot/share/oops/method.cpp b/src/hotspot/share/oops/method.cpp index a36974fc3f0..d2e25feef40 100644 --- a/src/hotspot/share/oops/method.cpp +++ b/src/hotspot/share/oops/method.cpp @@ -1011,7 +1011,7 @@ void Method::set_native_function(address function, bool post_event_flag) { // This function can be called more than once. We must make sure that we always // use the latest registered method -> check if a stub already has been generated. // If so, we have to make it not_entrant. - CompiledMethod* nm = code(); // Put it into local variable to guard against concurrent updates + nmethod* nm = code(); // Put it into local variable to guard against concurrent updates if (nm != nullptr) { nm->make_not_entrant(); } @@ -1159,8 +1159,8 @@ void Method::clear_code() { _code = nullptr; } -void Method::unlink_code(CompiledMethod *compare) { - ConditionalMutexLocker ml(CompiledMethod_lock, !CompiledMethod_lock->owned_by_self(), Mutex::_no_safepoint_check_flag); +void Method::unlink_code(nmethod *compare) { + ConditionalMutexLocker ml(NMethodState_lock, !NMethodState_lock->owned_by_self(), Mutex::_no_safepoint_check_flag); // We need to check if either the _code or _from_compiled_code_entry_point // refer to this nmethod because there is a race in setting these two fields // in Method* as seen in bugid 4947125. @@ -1171,7 +1171,7 @@ void Method::unlink_code(CompiledMethod *compare) { } void Method::unlink_code() { - ConditionalMutexLocker ml(CompiledMethod_lock, !CompiledMethod_lock->owned_by_self(), Mutex::_no_safepoint_check_flag); + ConditionalMutexLocker ml(NMethodState_lock, !NMethodState_lock->owned_by_self(), Mutex::_no_safepoint_check_flag); clear_code(); } @@ -1303,13 +1303,13 @@ address Method::verified_code_entry() { // Not inline to avoid circular ref. bool Method::check_code() const { // cached in a register or local. There's a race on the value of the field. - CompiledMethod *code = Atomic::load_acquire(&_code); + nmethod *code = Atomic::load_acquire(&_code); return code == nullptr || (code->method() == nullptr) || (code->method() == (Method*)this && !code->is_osr_method()); } // Install compiled code. Instantly it can execute. -void Method::set_code(const methodHandle& mh, CompiledMethod *code) { - assert_lock_strong(CompiledMethod_lock); +void Method::set_code(const methodHandle& mh, nmethod *code) { + assert_lock_strong(NMethodState_lock); assert( code, "use clear_code to remove code" ); assert( mh->check_code(), "" ); @@ -2143,14 +2143,6 @@ class JNIMethodBlock : public CHeapObj { return false; // not found } - // Doesn't really destroy it, just marks it as free so it can be reused. - void destroy_method(Method** m) { -#ifdef ASSERT - assert(contains(m), "should be a methodID"); -#endif // ASSERT - *m = _free_method; - } - // During class unloading the methods are cleared, which is different // than freed. void clear_all_methods() { @@ -2203,6 +2195,9 @@ jmethodID Method::make_jmethod_id(ClassLoaderData* cld, Method* m) { // Also have to add the method to the list safely, which the lock // protects as well. assert(JmethodIdCreation_lock->owned_by_self(), "sanity check"); + + ResourceMark rm; + log_debug(jmethod)("Creating jmethodID for Method %s", m->external_name()); if (cld->jmethod_ids() == nullptr) { cld->set_jmethod_ids(new JNIMethodBlock()); } @@ -2215,14 +2210,6 @@ jmethodID Method::jmethod_id() { return method_holder()->get_jmethod_id(mh); } -// Mark a jmethodID as free. This is called when there is a data race in -// InstanceKlass while creating the jmethodID cache. -void Method::destroy_jmethod_id(ClassLoaderData* cld, jmethodID m) { - Method** ptr = (Method**)m; - assert(cld->jmethod_ids() != nullptr, "should have method handles"); - cld->jmethod_ids()->destroy_method(ptr); -} - void Method::change_method_associated_with_jmethod_id(jmethodID jmid, Method* new_method) { // Can't assert the method_holder is the same because the new method has the // scratch method holder. diff --git a/src/hotspot/share/oops/method.hpp b/src/hotspot/share/oops/method.hpp index 2a247ea5bb8..838178d2de2 100644 --- a/src/hotspot/share/oops/method.hpp +++ b/src/hotspot/share/oops/method.hpp @@ -62,7 +62,7 @@ class MethodData; class MethodCounters; class ConstMethod; class InlineTableSizes; -class CompiledMethod; +class nmethod; class InterpreterOopMap; class Method : public Metadata { @@ -93,14 +93,14 @@ class Method : public Metadata { address _i2i_entry; // All-args-on-stack calling convention // Entry point for calling from compiled code, to compiled code if it exists // or else the interpreter. - volatile address _from_compiled_entry; // Cache of: _code ? _code->entry_point() : _adapter->c2i_entry() + volatile address _from_compiled_entry; // Cache of: _code ? _code->entry_point() : _adapter->c2i_entry() // The entry point for calling both from and to compiled code is // "_code->entry_point()". Because of tiered compilation and de-opt, this // field can come and go. It can transition from null to not-null at any // time (whenever a compile completes). It can transition from not-null to // null only at safepoints (because of a de-opt). - CompiledMethod* volatile _code; // Points to the corresponding piece of native code - volatile address _from_interpreted_entry; // Cache of _code ? _adapter->i2c_entry() : _i2i_entry + nmethod* volatile _code; // Points to the corresponding piece of native code + volatile address _from_interpreted_entry; // Cache of _code ? _adapter->i2c_entry() : _i2i_entry // Constructor Method(ConstMethod* xconst, AccessFlags access_flags, Symbol* name); @@ -357,15 +357,15 @@ class Method : public Metadata { // nmethod/verified compiler entry address verified_code_entry(); bool check_code() const; // Not inline to avoid circular ref - CompiledMethod* code() const; + nmethod* code() const; - // Locks CompiledMethod_lock if not held. - void unlink_code(CompiledMethod *compare); - // Locks CompiledMethod_lock if not held. + // Locks NMethodState_lock if not held. + void unlink_code(nmethod *compare); + // Locks NMethodState_lock if not held. void unlink_code(); private: - // Either called with CompiledMethod_lock held or from constructor. + // Either called with NMethodState_lock held or from constructor. void clear_code(); void clear_method_data() { @@ -373,7 +373,7 @@ class Method : public Metadata { } public: - static void set_code(const methodHandle& mh, CompiledMethod* code); + static void set_code(const methodHandle& mh, nmethod* code); void set_adapter_entry(AdapterHandlerEntry* adapter) { _adapter = adapter; } @@ -700,7 +700,6 @@ class Method : public Metadata { // made obsolete or deleted -- in these cases, the jmethodID // refers to null (as is the case for any weak reference). static jmethodID make_jmethod_id(ClassLoaderData* cld, Method* mh); - static void destroy_jmethod_id(ClassLoaderData* cld, jmethodID mid); // Ensure there is enough capacity in the internal tracking data // structures to hold the number of jmethodIDs you plan to generate. diff --git a/src/hotspot/share/oops/method.inline.hpp b/src/hotspot/share/oops/method.inline.hpp index bb83615d39e..f27834de30b 100644 --- a/src/hotspot/share/oops/method.inline.hpp +++ b/src/hotspot/share/oops/method.inline.hpp @@ -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 @@ -39,7 +39,7 @@ inline address Method::from_interpreted_entry() const { return Atomic::load_acquire(&_from_interpreted_entry); } -inline CompiledMethod* Method::code() const { +inline nmethod* Method::code() const { assert( check_code(), "" ); return Atomic::load_acquire(&_code); } diff --git a/src/hotspot/share/oops/oop.cpp b/src/hotspot/share/oops/oop.cpp index 65727374df8..7d4492ea21a 100644 --- a/src/hotspot/share/oops/oop.cpp +++ b/src/hotspot/share/oops/oop.cpp @@ -165,16 +165,6 @@ void oopDesc::set_narrow_klass(narrowKlass nk) { } #endif -void* oopDesc::load_klass_raw(oop obj) { - if (UseCompressedClassPointers) { - narrowKlass narrow_klass = obj->_metadata._compressed_klass; - if (narrow_klass == 0) return nullptr; - return (void*)CompressedKlassPointers::decode_raw(narrow_klass); - } else { - return obj->_metadata._klass; - } -} - void* oopDesc::load_oop_raw(oop obj, int offset) { uintptr_t addr = (uintptr_t)(void*)obj + (uint)offset; if (UseCompressedOops) { diff --git a/src/hotspot/share/oops/oop.hpp b/src/hotspot/share/oops/oop.hpp index 75bc3d9af72..6766b683731 100644 --- a/src/hotspot/share/oops/oop.hpp +++ b/src/hotspot/share/oops/oop.hpp @@ -85,8 +85,8 @@ class oopDesc { inline Klass* klass() const; inline Klass* klass_or_null() const; inline Klass* klass_or_null_acquire() const; - // Get the raw value without any checks. - inline Klass* klass_raw() const; + // Get the klass without running any asserts. + inline Klass* klass_without_asserts() const; void set_narrow_klass(narrowKlass nk) NOT_CDS_JAVA_HEAP_RETURN; inline void set_klass(Klass* k); @@ -316,7 +316,6 @@ class oopDesc { } // for error reporting - static void* load_klass_raw(oop obj); static void* load_oop_raw(oop obj, int offset); DEBUG_ONLY(bool size_might_change();) diff --git a/src/hotspot/share/oops/oop.inline.hpp b/src/hotspot/share/oops/oop.inline.hpp index a9b88e32651..bd00847869d 100644 --- a/src/hotspot/share/oops/oop.inline.hpp +++ b/src/hotspot/share/oops/oop.inline.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 @@ -111,9 +111,9 @@ Klass* oopDesc::klass_or_null_acquire() const { } } -Klass* oopDesc::klass_raw() const { +Klass* oopDesc::klass_without_asserts() const { if (UseCompressedClassPointers) { - return CompressedKlassPointers::decode_raw(_metadata._compressed_klass); + return CompressedKlassPointers::decode_without_asserts(_metadata._compressed_klass); } else { return _metadata._klass; } @@ -256,7 +256,6 @@ bool oopDesc::is_unlocked() const { return mark().is_unlocked(); } -// Used only for markSweep, scavenging bool oopDesc::is_gc_marked() const { return mark().is_marked(); } diff --git a/src/hotspot/share/oops/stackChunkOop.cpp b/src/hotspot/share/oops/stackChunkOop.cpp index e114161625b..a8c6cbc2bd2 100644 --- a/src/hotspot/share/oops/stackChunkOop.cpp +++ b/src/hotspot/share/oops/stackChunkOop.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, 2022, 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,7 +23,7 @@ */ #include "precompiled.hpp" -#include "code/compiledMethod.hpp" +#include "code/nmethod.hpp" #include "code/scopeDesc.hpp" #include "gc/shared/barrierSet.hpp" #include "gc/shared/barrierSetStackChunk.hpp" @@ -108,9 +108,9 @@ frame stackChunkOopDesc::sender(const frame& f, RegisterMap* map) { return Continuation::continuation_parent_frame(map); } -static int num_java_frames(CompiledMethod* cm, address pc) { +static int num_java_frames(nmethod* nm, address pc) { int count = 0; - for (ScopeDesc* scope = cm->scope_desc_at(pc); scope != nullptr; scope = scope->sender()) { + for (ScopeDesc* scope = nm->scope_desc_at(pc); scope != nullptr; scope = scope->sender()) { count++; } return count; @@ -118,8 +118,8 @@ static int num_java_frames(CompiledMethod* cm, address pc) { static int num_java_frames(const StackChunkFrameStream& f) { assert(f.is_interpreted() - || (f.cb() != nullptr && f.cb()->is_compiled() && f.cb()->as_compiled_method()->is_java_method()), ""); - return f.is_interpreted() ? 1 : num_java_frames(f.cb()->as_compiled_method(), f.orig_pc()); + || (f.cb() != nullptr && f.cb()->is_nmethod() && f.cb()->as_nmethod()->is_java_method()), ""); + return f.is_interpreted() ? 1 : num_java_frames(f.cb()->as_nmethod(), f.orig_pc()); } int stackChunkOopDesc::num_java_frames() const { @@ -560,11 +560,11 @@ bool stackChunkOopDesc::verify(size_t* out_size, int* out_oops, int* out_frames, iterate_stack(&closure); assert(!is_empty() || closure._cb == nullptr, ""); - if (closure._cb != nullptr && closure._cb->is_compiled()) { + if (closure._cb != nullptr && closure._cb->is_nmethod()) { assert(argsize() == - (closure._cb->as_compiled_method()->method()->num_stack_arg_slots()*VMRegImpl::stack_slot_size) >>LogBytesPerWord, + (closure._cb->as_nmethod()->method()->num_stack_arg_slots()*VMRegImpl::stack_slot_size) >>LogBytesPerWord, "chunk argsize: %d bottom frame argsize: %d", argsize(), - (closure._cb->as_compiled_method()->method()->num_stack_arg_slots()*VMRegImpl::stack_slot_size) >>LogBytesPerWord); + (closure._cb->as_nmethod()->method()->num_stack_arg_slots()*VMRegImpl::stack_slot_size) >>LogBytesPerWord); } assert(closure._num_interpreted_frames == 0 || has_mixed_frames(), ""); diff --git a/src/hotspot/share/opto/castnode.hpp b/src/hotspot/share/opto/castnode.hpp index 3214dd22ad5..3e20a92e848 100644 --- a/src/hotspot/share/opto/castnode.hpp +++ b/src/hotspot/share/opto/castnode.hpp @@ -180,6 +180,7 @@ class CastPPNode: public ConstraintCastNode { public: CastPPNode (Node* ctrl, Node* n, const Type* t, DependencyType dependency = RegularDependency, const TypeTuple* types = nullptr) : ConstraintCastNode(ctrl, n, t, dependency, types) { + init_class_id(Class_CastPP); } virtual int Opcode() const; virtual uint ideal_reg() const { return Op_RegP; } diff --git a/src/hotspot/share/opto/compile.cpp b/src/hotspot/share/opto/compile.cpp index 417f828013f..d8881689678 100644 --- a/src/hotspot/share/opto/compile.cpp +++ b/src/hotspot/share/opto/compile.cpp @@ -5014,16 +5014,7 @@ void Compile::remove_speculative_types(PhaseIterGVN &igvn) { const Type* t_no_spec = t->remove_speculative(); if (t_no_spec != t) { bool in_hash = igvn.hash_delete(n); -#ifdef ASSERT - if (!in_hash) { - tty->print_cr("current graph:"); - n->dump_bfs(MaxNodeLimit, nullptr, "S$"); - tty->cr(); - tty->print_cr("erroneous node:"); - n->dump(); - assert(false, "node should be in igvn hash table"); - } -#endif + assert(in_hash || n->hash() == Node::NO_HASH, "node should be in igvn hash table"); tn->set_type(t_no_spec); igvn.hash_insert(n); igvn._worklist.push(n); // give it a chance to go away diff --git a/src/hotspot/share/opto/escape.cpp b/src/hotspot/share/opto/escape.cpp index 99a96a45be6..8e08cde6861 100644 --- a/src/hotspot/share/opto/escape.cpp +++ b/src/hotspot/share/opto/escape.cpp @@ -40,6 +40,8 @@ #include "opto/locknode.hpp" #include "opto/phaseX.hpp" #include "opto/movenode.hpp" +#include "opto/narrowptrnode.hpp" +#include "opto/castnode.hpp" #include "opto/rootnode.hpp" #include "utilities/macros.hpp" @@ -410,20 +412,28 @@ bool ConnectionGraph::compute_escape() { #endif } - // 6. Remove reducible allocation merges from ideal graph - if (reducible_merges.size() > 0) { - bool delay = _igvn->delay_transform(); - _igvn->set_delay_transform(true); - for (uint i = 0; i < reducible_merges.size(); i++ ) { - Node* n = reducible_merges.at(i); - reduce_phi(n->as_Phi()); - if (C->failing()) { + // 6. Reduce allocation merges used as debug information. This is done after + // split_unique_types because the methods used to create SafePointScalarObject + // need to traverse the memory graph to find values for object fields. We also + // set to null the scalarized inputs of reducible Phis so that the Allocate + // that they point can be later scalar replaced. + bool delay = _igvn->delay_transform(); + _igvn->set_delay_transform(true); + for (uint i = 0; i < reducible_merges.size(); i++) { + Node* n = reducible_merges.at(i); + if (n->outcnt() > 0) { + if (!reduce_phi_on_safepoints(n->as_Phi())) { NOT_PRODUCT(escape_state_statistics(java_objects_worklist);) + C->record_failure(C2Compiler::retry_no_reduce_allocation_merges()); return false; } + + // Now we set the scalar replaceable inputs of ophi to null, which is + // the last piece that would prevent it from being scalar replaceable. + reset_scalar_replaceable_entries(n->as_Phi()); } - _igvn->set_delay_transform(delay); } + _igvn->set_delay_transform(delay); // Annotate at safepoints if they have <= ArgEscape objects in their scope and at // java calls if they pass ArgEscape objects as parameters. @@ -448,29 +458,25 @@ bool ConnectionGraph::compute_escape() { } // Check if it's profitable to reduce the Phi passed as parameter. Returns true -// if at least one scalar replaceable allocation participates in the merge and -// no input to the Phi is nullable. +// if at least one scalar replaceable allocation participates in the merge. bool ConnectionGraph::can_reduce_phi_check_inputs(PhiNode* ophi) const { - // Check if there is a scalar replaceable allocate in the Phi bool found_sr_allocate = false; for (uint i = 1; i < ophi->req(); i++) { - // Right now we can't restore a "null" pointer during deoptimization - const Type* inp_t = _igvn->type(ophi->in(i)); - if (inp_t == nullptr || inp_t->make_oopptr() == nullptr || inp_t->make_oopptr()->maybe_null()) { - NOT_PRODUCT(if (TraceReduceAllocationMerges) tty->print_cr("Can NOT reduce Phi %d on invocation %d. Input %d is nullable.", ophi->_idx, _invocation, i);) - return false; - } - - // We are looking for at least one SR object in the merge JavaObjectNode* ptn = unique_java_object(ophi->in(i)); if (ptn != nullptr && ptn->scalar_replaceable()) { - assert(ptn->ideal_node() != nullptr && ptn->ideal_node()->is_Allocate(), "sanity"); AllocateNode* alloc = ptn->ideal_node()->as_Allocate(); + // Don't handle arrays. + if (alloc->Opcode() != Op_Allocate) { + assert(alloc->Opcode() == Op_AllocateArray, "Unexpected type of allocation."); + continue; + } + if (PhaseMacroExpand::can_eliminate_allocation(_igvn, alloc, nullptr)) { found_sr_allocate = true; } else { + NOT_PRODUCT(if (TraceReduceAllocationMerges) tty->print_cr("%dth input of Phi %d is SR but can't be eliminated.", i, ophi->_idx);) ptn->set_scalar_replaceable(false); } } @@ -480,28 +486,107 @@ bool ConnectionGraph::can_reduce_phi_check_inputs(PhiNode* ophi) const { return found_sr_allocate; } -// Check if we are able to untangle the merge. Right now we only reduce Phis -// which are only used as debug information. -bool ConnectionGraph::can_reduce_phi_check_users(PhiNode* ophi) const { - for (DUIterator_Fast imax, i = ophi->fast_outs(imax); i < imax; i++) { - Node* use = ophi->fast_out(i); +// We can reduce the Cmp if it's a comparison between the Phi and a constant. +// I require the 'other' input to be a constant so that I can move the Cmp +// around safely. +bool ConnectionGraph::can_reduce_cmp(Node* n, Node* cmp) const { + Node* left = cmp->in(1); + Node* right = cmp->in(2); + + return (cmp->Opcode() == Op_CmpP || cmp->Opcode() == Op_CmpN) && + (left == n || right == n) && + (left->is_Con() || right->is_Con()) && + cmp->outcnt() == 1; +} + +// We are going to check if any of the SafePointScalarMerge entries +// in the SafePoint reference the Phi that we are checking. +bool ConnectionGraph::has_been_reduced(PhiNode* n, SafePointNode* sfpt) const { + JVMState *jvms = sfpt->jvms(); + + for (uint i = jvms->debug_start(); i < jvms->debug_end(); i++) { + Node* sfpt_in = sfpt->in(i); + if (sfpt_in->is_SafePointScalarMerge()) { + SafePointScalarMergeNode* smerge = sfpt_in->as_SafePointScalarMerge(); + Node* nsr_ptr = sfpt->in(smerge->merge_pointer_idx(jvms)); + if (nsr_ptr == n) { + return true; + } + } + } + + return false; +} + +// Check if we are able to untangle the merge. The following patterns are +// supported: +// - Phi -> SafePoints +// - Phi -> CmpP/N +// - Phi -> AddP -> Load +// - Phi -> CastPP -> SafePoints +// - Phi -> CastPP -> AddP -> Load +bool ConnectionGraph::can_reduce_check_users(Node* n, uint nesting) const { + for (DUIterator_Fast imax, i = n->fast_outs(imax); i < imax; i++) { + Node* use = n->fast_out(i); if (use->is_SafePoint()) { - if (use->is_Call() && use->as_Call()->has_non_debug_use(ophi)) { - NOT_PRODUCT(if (TraceReduceAllocationMerges) tty->print_cr("Can NOT reduce Phi %d on invocation %d. Call has non_debug_use().", ophi->_idx, _invocation);) + if (use->is_Call() && use->as_Call()->has_non_debug_use(n)) { + NOT_PRODUCT(if (TraceReduceAllocationMerges) tty->print_cr("Can NOT reduce Phi %d on invocation %d. Call has non_debug_use().", n->_idx, _invocation);) + return false; + } else if (has_been_reduced(n->is_Phi() ? n->as_Phi() : n->as_CastPP()->in(1)->as_Phi(), use->as_SafePoint())) { + NOT_PRODUCT(if (TraceReduceAllocationMerges) tty->print_cr("Can NOT reduce Phi %d on invocation %d. It has already been reduced.", n->_idx, _invocation);) return false; } } else if (use->is_AddP()) { Node* addp = use; for (DUIterator_Fast jmax, j = addp->fast_outs(jmax); j < jmax; j++) { Node* use_use = addp->fast_out(j); + const Type* load_type = _igvn->type(use_use); + if (!use_use->is_Load() || !use_use->as_Load()->can_split_through_phi_base(_igvn)) { - NOT_PRODUCT(if (TraceReduceAllocationMerges) tty->print_cr("Can NOT reduce Phi %d on invocation %d. AddP user isn't a [splittable] Load(): %s", ophi->_idx, _invocation, use_use->Name());) + NOT_PRODUCT(if (TraceReduceAllocationMerges) tty->print_cr("Can NOT reduce Phi %d on invocation %d. AddP user isn't a [splittable] Load(): %s", n->_idx, _invocation, use_use->Name());) return false; + } else if (nesting > 0 && load_type->isa_narrowklass()) { + NOT_PRODUCT(if (TraceReduceAllocationMerges) tty->print_cr("Can NOT reduce Phi %d on invocation %d. Nested NarrowKlass Load: %s", n->_idx, _invocation, use_use->Name());) + return false; + } + } + } else if (nesting > 0) { + NOT_PRODUCT(if (TraceReduceAllocationMerges) tty->print_cr("Can NOT reduce Phi %d on invocation %d. Unsupported user %s at nesting level %d.", n->_idx, _invocation, use->Name(), nesting);) + return false; + } else if (use->is_CastPP()) { + const Type* cast_t = _igvn->type(use); + if (cast_t == nullptr || cast_t->make_ptr()->isa_instptr() == nullptr) { + NOT_PRODUCT(use->dump();) + NOT_PRODUCT(if (TraceReduceAllocationMerges) tty->print_cr("Can NOT reduce Phi %d on invocation %d. CastPP is not to an instance.", n->_idx, _invocation);) + return false; + } + + bool is_trivial_control = use->in(0) == nullptr || use->in(0) == n->in(0); + if (!is_trivial_control) { + // If it's not a trivial control then we check if we can reduce the + // CmpP/N used by the If controlling the cast. + if (use->in(0)->is_IfTrue() || use->in(0)->is_IfFalse()) { + Node* iff = use->in(0)->in(0); + Node* iff_cmp = iff->in(1)->in(1); // if->bool->cmp + if (!can_reduce_cmp(n, iff_cmp)) { + NOT_PRODUCT(if (TraceReduceAllocationMerges) tty->print_cr("Can NOT reduce Phi %d on invocation %d. CastPP %d doesn't have simple control.", n->_idx, _invocation, use->_idx);) + NOT_PRODUCT(n->dump(5);) + return false; + } } } + + if (!can_reduce_check_users(use, nesting+1)) { + return false; + } + } else if (use->Opcode() == Op_CmpP || use->Opcode() == Op_CmpN) { + if (!can_reduce_cmp(n, use)) { + NOT_PRODUCT(if (TraceReduceAllocationMerges) tty->print_cr("Can NOT reduce Phi %d on invocation %d. CmpP/N %d isn't reducible.", n->_idx, _invocation, use->_idx);) + return false; + } } else { - NOT_PRODUCT(if (TraceReduceAllocationMerges) tty->print_cr("Can NOT reduce Phi %d on invocation %d. One of the uses is: %d %s", ophi->_idx, _invocation, use->_idx, use->Name());) + NOT_PRODUCT(if (TraceReduceAllocationMerges) tty->print_cr("Can NOT reduce Phi %d on invocation %d. One of the uses is: %d %s", n->_idx, _invocation, use->_idx, use->Name());) return false; } } @@ -517,20 +602,18 @@ bool ConnectionGraph::can_reduce_phi(PhiNode* ophi) const { // If there was an error attempting to reduce allocation merges for this // method we might have disabled the compilation and be retrying with RAM // disabled. - // If EliminateAllocations is False, there is no point in reducing merges. - if (!_compile->do_reduce_allocation_merges()) { + if (!_compile->do_reduce_allocation_merges() || ophi->region()->Opcode() != Op_Region) { return false; } const Type* phi_t = _igvn->type(ophi); - if (phi_t == nullptr || phi_t->make_ptr() == nullptr || - phi_t->make_ptr()->isa_instptr() == nullptr || - !phi_t->make_ptr()->isa_instptr()->klass_is_exact()) { - NOT_PRODUCT(if (TraceReduceAllocationMerges) { tty->print_cr("Can NOT reduce Phi %d during invocation %d because it's nullable.", ophi->_idx, _invocation); }) + if (phi_t == nullptr || + phi_t->make_ptr() == nullptr || + phi_t->make_ptr()->isa_aryptr() != nullptr) { return false; } - if (!can_reduce_phi_check_inputs(ophi) || !can_reduce_phi_check_users(ophi)) { + if (!can_reduce_phi_check_inputs(ophi) || !can_reduce_check_users(ophi, /* nesting: */ 0)) { return false; } @@ -538,123 +621,457 @@ bool ConnectionGraph::can_reduce_phi(PhiNode* ophi) const { return true; } -void ConnectionGraph::reduce_phi_on_field_access(PhiNode* ophi, GrowableArray &alloc_worklist) { - // We'll pass this to 'split_through_phi' so that it'll do the split even - // though the load doesn't have an unique instance type. - bool ignore_missing_instance_id = true; - -#ifdef ASSERT - if (VerifyReduceAllocationMerges && !can_reduce_phi(ophi)) { - TraceReduceAllocationMerges = true; - ophi->dump(2); - ophi->dump(-2); - assert(can_reduce_phi(ophi), "Sanity: previous reducible Phi is no longer reducible inside reduce_phi_on_field_access."); +// This method will return a CmpP/N that we need to use on the If controlling a +// CastPP after it was split. This method is only called on bases that are +// nullable therefore we always need a controlling if for the splitted CastPP. +// +// 'curr_ctrl' is the control of the CastPP that we want to split through phi. +// If the CastPP currently doesn't have a control then the CmpP/N will be +// against the NULL constant, otherwise it will be against the constant input of +// the existing CmpP/N. It's guaranteed that there will be a CmpP/N in the later +// case because we have constraints on it and because the CastPP has a control +// input. +Node* ConnectionGraph::specialize_cmp(Node* base, Node* curr_ctrl) { + const Type* t = base->bottom_type(); + Node* con = nullptr; + + if (curr_ctrl == nullptr || curr_ctrl->is_Region()) { + con = _igvn->zerocon(t->basic_type()); + } else { + Node* curr_cmp = curr_ctrl->in(0)->in(1)->in(1); // true/false -> if -> bool -> cmp + con = curr_cmp->in(1)->is_Con() ? curr_cmp->in(1) : curr_cmp->in(2); } -#endif - // Iterate over Phi outputs looking for an AddP - for (int j = ophi->outcnt()-1; j >= 0;) { - Node* previous_addp = ophi->raw_out(j); - if (previous_addp->is_AddP()) { - // All AddPs are present in the connection graph - FieldNode* fn = ptnode_adr(previous_addp->_idx)->as_Field(); - - // Iterate over AddP looking for a Load - for (int k = previous_addp->outcnt()-1; k >= 0;) { - Node* previous_load = previous_addp->raw_out(k); - if (previous_load->is_Load()) { - Node* data_phi = previous_load->as_Load()->split_through_phi(_igvn, ignore_missing_instance_id); - _igvn->replace_node(previous_load, data_phi); - assert(data_phi != nullptr, "Output of split_through_phi is null."); - assert(data_phi != previous_load, "Output of split_through_phi is same as input."); - assert(data_phi->is_Phi(), "Return of split_through_phi should be a Phi."); - - // Push the newly created AddP on alloc_worklist and patch - // the connection graph. Note that the changes in the CG below - // won't affect the ES of objects since the new nodes have the - // same status as the old ones. - for (uint i = 1; i < data_phi->req(); i++) { - Node* new_load = data_phi->in(i); - if (new_load->is_Load()) { - Node* new_addp = new_load->in(MemNode::Address); - Node* base = get_addp_base(new_addp); - - // The base might not be something that we can create an unique - // type for. If that's the case we are done with that input. - PointsToNode* jobj_ptn = unique_java_object(base); - if (jobj_ptn == nullptr || !jobj_ptn->scalar_replaceable()) { - continue; - } + return CmpNode::make(base, con, t->basic_type()); +} - // Push to alloc_worklist since the base has an unique_type - alloc_worklist.append_if_missing(new_addp); - - // Now let's add the node to the connection graph - _nodes.at_grow(new_addp->_idx, nullptr); - add_field(new_addp, fn->escape_state(), fn->offset()); - add_base(ptnode_adr(new_addp->_idx)->as_Field(), ptnode_adr(base->_idx)); - - // If the load doesn't load an object then it won't be - // part of the connection graph - PointsToNode* curr_load_ptn = ptnode_adr(previous_load->_idx); - if (curr_load_ptn != nullptr) { - _nodes.at_grow(new_load->_idx, nullptr); - add_local_var(new_load, curr_load_ptn->escape_state()); - add_edge(ptnode_adr(new_load->_idx), ptnode_adr(new_addp->_idx)->as_Field()); - } - } - } - } - k = MIN2(--k, (int)previous_addp->outcnt()-1); +// This method 'specializes' the CastPP passed as parameter to the base passed +// as parameter. Note that the existing CastPP input is a Phi. "Specialize" +// means that the CastPP now will be specific for a given base instead of a Phi. +// An If-Then-Else-Region block is inserted to control the CastPP. The control +// of the CastPP is a copy of the current one (if there is one) or a check +// against NULL. +// +// Before: +// +// C1 C2 ... Cn +// \ | / +// \ | / +// \ | / +// \ | / +// \ | / +// \ | / +// \|/ +// Region B1 B2 ... Bn +// | \ | / +// | \ | / +// | \ | / +// | \ | / +// | \ | / +// | \ | / +// ---------------> Phi +// | +// X | +// | | +// | | +// ------> CastPP +// +// After (only partial illustration; base = B2, current_control = C2): +// +// C2 +// | +// If +// / \ +// / \ +// T F +// /\ / +// / \ / +// / \ / +// C1 CastPP Reg Cn +// | | | +// | | | +// | | | +// -------------- | ---------- +// | | | +// Region +// +Node* ConnectionGraph::specialize_castpp(Node* castpp, Node* base, Node* current_control) { + Node* control_successor = current_control->unique_ctrl_out(); + Node* minus_one = _igvn->transform(ConINode::make(-1)); + Node* cmp = _igvn->transform(specialize_cmp(base, castpp->in(0))); + Node* boll = _igvn->transform(new BoolNode(cmp, BoolTest::ne)); + IfNode* if_ne = _igvn->transform(new IfNode(current_control, boll, PROB_MIN, COUNT_UNKNOWN))->as_If(); + Node* not_eq_control = _igvn->transform(new IfTrueNode(if_ne)); + Node* yes_eq_control = _igvn->transform(new IfFalseNode(if_ne)); + Node* end_region = _igvn->transform(new RegionNode(3)); + + // Insert the new if-else-region block into the graph + end_region->set_req(1, not_eq_control); + end_region->set_req(2, yes_eq_control); + control_successor->replace_edge(current_control, end_region, _igvn); + + _igvn->_worklist.push(current_control); + _igvn->_worklist.push(control_successor); + + return _igvn->transform(ConstraintCastNode::make_cast_for_type(not_eq_control, base, _igvn->type(castpp), ConstraintCastNode::UnconditionalDependency, nullptr)); +} + +Node* ConnectionGraph::split_castpp_load_through_phi(Node* curr_addp, Node* curr_load, Node* region, GrowableArray* bases_for_loads, GrowableArray &alloc_worklist) { + const Type* load_type = _igvn->type(curr_load); + Node* nsr_value = _igvn->zerocon(load_type->basic_type()); + Node* data_phi = _igvn->transform(PhiNode::make(region, nsr_value, load_type)); + Node* memory = curr_load->in(MemNode::Memory); + + for (int i = 1; i < bases_for_loads->length(); i++) { + Node* base = bases_for_loads->at(i); + Node* cmp_region = nullptr; + if (base != nullptr) { + if (base->is_CFG()) { // means that we added a CastPP as child of this CFG node + cmp_region = base->unique_ctrl_out_or_null(); + assert(cmp_region != nullptr, "There should be."); + base = base->find_out_with(Op_CastPP); } - // Remove the old AddP from the processing list because it's dead now - alloc_worklist.remove_if_existing(previous_addp); - _igvn->remove_globally_dead_node(previous_addp); + Node* addr = _igvn->transform(new AddPNode(base, base, curr_addp->in(AddPNode::Offset))); + Node* mem = (memory->is_Phi() && (memory->in(0) == region)) ? memory->in(i) : memory; + Node* load = _igvn->transform(curr_load->clone()); + load->set_req(0, nullptr); + load->set_req(1, mem); + load->set_req(2, addr); + + if (cmp_region != nullptr) { // see comment on previous if + Node* intermediate_phi = _igvn->transform(PhiNode::make(cmp_region, nsr_value, load_type)); + intermediate_phi->set_req(1, load); + load = intermediate_phi; + } + + data_phi->set_req(i, load); + } else { + // Just use the default, which is already in phi } - j = MIN2(--j, (int)ophi->outcnt()-1); } -#ifdef ASSERT - if (VerifyReduceAllocationMerges) { - for (uint j = 0; j < ophi->outcnt(); j++) { - Node* use = ophi->raw_out(j); - if (!use->is_SafePoint()) { - ophi->dump(2); - ophi->dump(-2); - assert(false, "Should be a SafePoint."); + // Takes care of updating CG and split_unique_types worklists due to cloned + // AddP->Load. + updates_after_load_split(data_phi, curr_load, alloc_worklist); + + return data_phi; +} + +// This method only reduces CastPP fields loads; SafePoints are handled +// separately. The idea here is basically to clone the CastPP and place copies +// on each input of the Phi, including non-scalar replaceable inputs. +// Experimentation shows that the resulting IR graph is simpler that way than if +// we just split the cast through scalar-replaceable inputs. +// +// The reduction process requires that CastPP's control be one of: +// 1) no control, +// 2) the same region as Ophi, or +// 3) an IfTrue/IfFalse coming from an CmpP/N between Ophi and a constant. +// +// After splitting the CastPP we'll put it under an If-Then-Else-Region control +// flow. If the CastPP originally had an IfTrue/False control input then we'll +// use a similar CmpP/N to control the new If-Then-Else-Region. Otherwise, we'll +// juse use a CmpP/N against the NULL constant. +// +// The If-Then-Else-Region isn't always needed. For instance, if input to +// splitted cast was not nullable (or if it was the NULL constant) then we don't +// need (shouldn't) use a CastPP at all. +// +// After the casts are splitted we'll split the AddP->Loads through the Phi and +// connect them to the just split CastPPs. +// +// Before (CastPP control is same as Phi): +// +// Region Allocate Null Call +// | \ | / +// | \ | / +// | \ | / +// | \ | / +// | \ | / +// | \ | / +// ------------------> Phi # Oop Phi +// | | +// | | +// | | +// | | +// ----------------> CastPP +// | +// AddP +// | +// Load +// +// After (Very much simplified): +// +// Call NULL +// \ / +// CmpP +// | +// Bool#NE +// | +// If +// / \ +// T F +// / \ / +// / R +// CastPP | +// | | +// AddP | +// | | +// Load | +// \ | 0 +// Allocate \ | / +// \ \ | / +// AddP Phi +// \ / +// Load / +// \ 0 / +// \ | / +// \|/ +// Phi # "Field" Phi +// +void ConnectionGraph::reduce_phi_on_castpp_field_load(Node* curr_castpp, GrowableArray &alloc_worklist, GrowableArray &memnode_worklist) { + Node* ophi = curr_castpp->in(1); + assert(ophi->is_Phi(), "Expected this to be a Phi node."); + + // Identify which base should be used for AddP->Load later when spliting the + // CastPP->Loads through ophi. Three kind of values may be stored in this + // array, depending on the nullability status of the corresponding input in + // ophi. + // + // - nullptr: Meaning that the base is actually the NULL constant and therefore + // we won't try to load from it. + // + // - CFG Node: Meaning that the base is a CastPP that was specialized for + // this input of Ophi. I.e., we added an If->Then->Else-Region + // that will 'activate' the CastPp only when the input is not Null. + // + // - Other Node: Meaning that the base is not nullable and therefore we'll try + // to load directly from it. + GrowableArray bases_for_loads(ophi->req(), ophi->req(), nullptr); + + for (uint i = 1; i < ophi->req(); i++) { + Node* base = ophi->in(i); + const Type* base_t = _igvn->type(base); + + if (base_t->maybe_null()) { + if (base->is_Con()) { + // Nothing todo as bases_for_loads[i] is already nullptr + } else { + Node* new_castpp = specialize_castpp(curr_castpp, base, ophi->in(0)->in(i)); + bases_for_loads.at_put(i, new_castpp->in(0)); // Use the ctrl of the new node just as a flag } + } else { + bases_for_loads.at_put(i, base); } } -#endif + + // Now let's split the CastPP->Loads through the Phi + for (int i = curr_castpp->outcnt()-1; i >= 0;) { + Node* use = curr_castpp->raw_out(i); + if (use->is_AddP()) { + for (int j = use->outcnt()-1; j >= 0;) { + Node* use_use = use->raw_out(j); + assert(use_use->is_Load(), "Expected this to be a Load node."); + + // We can't make an unconditional load from a nullable input. The + // 'split_castpp_load_through_phi` method will add an + // 'If-Then-Else-Region` around nullable bases and only load from them + // when the input is not null. + Node* phi = split_castpp_load_through_phi(use, use_use, ophi->in(0), &bases_for_loads, alloc_worklist); + _igvn->replace_node(use_use, phi); + + --j; + j = MIN2(j, (int)use->outcnt()-1); + } + + _igvn->remove_dead_node(use); + } + --i; + i = MIN2(i, (int)curr_castpp->outcnt()-1); + } } -// This method will create a SafePointScalarObjectNode for each combination of -// scalar replaceable allocation in 'ophi' and SafePoint node in 'safepoints'. -// The method will create a SafePointScalarMERGEnode for each combination of -// 'ophi' and SafePoint node in 'safepoints'. -// Each SafePointScalarMergeNode created here may describe multiple scalar -// replaced objects - check detailed description in SafePointScalarMergeNode -// class header. +// This method split a given CmpP/N through the Phi used in one of its inputs. +// As a result we convert a comparison with a pointer to a comparison with an +// integer. +// The only requirement is that one of the inputs of the CmpP/N must be a Phi +// while the other must be a constant. +// The splitting process is basically just cloning the CmpP/N above the input +// Phi. However, some (most) of the cloned CmpP/Ns won't be requred because we +// can prove at compile time the result of the comparison. // -// This method will set entries in the Phi that are scalar replaceable to 'null'. -void ConnectionGraph::reduce_phi_on_safepoints(PhiNode* ophi, Unique_Node_List* safepoints) { - Node* minus_one = _igvn->register_new_node_with_optimizer(ConINode::make(-1)); - Node* selector = _igvn->register_new_node_with_optimizer(PhiNode::make(ophi->region(), minus_one, TypeInt::INT)); - Node* null_ptr = _igvn->makecon(TypePtr::NULL_PTR); - const TypeOopPtr* merge_t = _igvn->type(ophi)->make_oopptr(); - uint number_of_sr_objects = 0; - PhaseMacroExpand mexp(*_igvn); +// Before: +// +// in1 in2 ... inN +// \ | / +// \ | / +// \ | / +// \ | / +// \ | / +// \ | / +// Phi +// | Other +// | / +// | / +// | / +// CmpP/N +// +// After: +// +// in1 Other in2 Other inN Other +// | | | | | | +// \ | | | | | +// \ / | / | / +// CmpP/N CmpP/N CmpP/N +// Bool Bool Bool +// \ | / +// \ | / +// \ | / +// \ | / +// \ | / +// \ | / +// \ | / +// \ | / +// Phi +// | +// | Zero +// | / +// | / +// | / +// CmpI +// +// +void ConnectionGraph::reduce_phi_on_cmp(Node* cmp) { + Node* ophi = cmp->in(1)->is_Con() ? cmp->in(2) : cmp->in(1); + assert(ophi->is_Phi(), "Expected this to be a Phi node."); - _igvn->hash_delete(ophi); + Node* other = cmp->in(1)->is_Con() ? cmp->in(1) : cmp->in(2); + Node* zero = _igvn->intcon(0); + BoolTest::mask mask = cmp->unique_out()->as_Bool()->_test._test; + + // This Phi will merge the result of the Cmps split through the Phi + Node* res_phi = _igvn->transform(PhiNode::make(ophi->in(0), zero, TypeInt::INT)); + + for (uint i=1; ireq(); i++) { + Node* ophi_input = ophi->in(i); + Node* res_phi_input = nullptr; + + const TypeInt* tcmp = optimize_ptr_compare(ophi_input, other); + if (tcmp->singleton()) { + res_phi_input = _igvn->makecon(tcmp); + } else { + Node* ncmp = _igvn->transform(cmp->clone()); + ncmp->set_req(1, ophi_input); + ncmp->set_req(2, other); + Node* boll = _igvn->transform(new BoolNode(ncmp, mask)); + res_phi_input = boll->as_Bool()->as_int_value(_igvn); + } + + res_phi->set_req(i, res_phi_input); + } + + Node* new_cmp = _igvn->transform(new CmpINode(res_phi, zero)); + _igvn->replace_node(cmp, new_cmp); +} - // Fill in the 'selector' Phi. If index 'i' of the selector is: - // -> a '-1' constant, the i'th input of the original Phi is NSR. - // -> a 'x' constant >=0, the i'th input of of original Phi will be SR and the - // info about the scalarized object will be at index x of - // ObjectMergeValue::possible_objects +// Push the newly created AddP on alloc_worklist and patch +// the connection graph. Note that the changes in the CG below +// won't affect the ES of objects since the new nodes have the +// same status as the old ones. +void ConnectionGraph::updates_after_load_split(Node* data_phi, Node* previous_load, GrowableArray &alloc_worklist) { + assert(data_phi != nullptr, "Output of split_through_phi is null."); + assert(data_phi != previous_load, "Output of split_through_phi is same as input."); + assert(data_phi->is_Phi(), "Output of split_through_phi isn't a Phi."); + + if (data_phi == nullptr || !data_phi->is_Phi()) { + // Make this a retry? + return ; + } + + Node* previous_addp = previous_load->in(MemNode::Address); + FieldNode* fn = ptnode_adr(previous_addp->_idx)->as_Field(); + for (uint i = 1; i < data_phi->req(); i++) { + Node* new_load = data_phi->in(i); + + if (new_load->is_Phi()) { + // new_load is currently the "intermediate_phi" from an specialized + // CastPP. + new_load = new_load->in(1); + } + + // "new_load" might actually be a constant, parameter, etc. + if (new_load->is_Load()) { + Node* new_addp = new_load->in(MemNode::Address); + Node* base = get_addp_base(new_addp); + + // The base might not be something that we can create an unique + // type for. If that's the case we are done with that input. + PointsToNode* jobj_ptn = unique_java_object(base); + if (jobj_ptn == nullptr || !jobj_ptn->scalar_replaceable()) { + continue; + } + + // Push to alloc_worklist since the base has an unique_type + alloc_worklist.append_if_missing(new_addp); + + // Now let's add the node to the connection graph + _nodes.at_grow(new_addp->_idx, nullptr); + add_field(new_addp, fn->escape_state(), fn->offset()); + add_base(ptnode_adr(new_addp->_idx)->as_Field(), ptnode_adr(base->_idx)); + + // If the load doesn't load an object then it won't be + // part of the connection graph + PointsToNode* curr_load_ptn = ptnode_adr(previous_load->_idx); + if (curr_load_ptn != nullptr) { + _nodes.at_grow(new_load->_idx, nullptr); + add_local_var(new_load, curr_load_ptn->escape_state()); + add_edge(ptnode_adr(new_load->_idx), ptnode_adr(new_addp->_idx)->as_Field()); + } + } + } +} + +void ConnectionGraph::reduce_phi_on_field_access(Node* previous_addp, GrowableArray &alloc_worklist) { + // We'll pass this to 'split_through_phi' so that it'll do the split even + // though the load doesn't have an unique instance type. + bool ignore_missing_instance_id = true; + + // All AddPs are present in the connection graph + FieldNode* fn = ptnode_adr(previous_addp->_idx)->as_Field(); + + // Iterate over AddP looking for a Load + for (int k = previous_addp->outcnt()-1; k >= 0;) { + Node* previous_load = previous_addp->raw_out(k); + if (previous_load->is_Load()) { + Node* data_phi = previous_load->as_Load()->split_through_phi(_igvn, ignore_missing_instance_id); + + // Takes care of updating CG and split_unique_types worklists due to cloned + // AddP->Load. + updates_after_load_split(data_phi, previous_load, alloc_worklist); + + _igvn->replace_node(previous_load, data_phi); + } + --k; + k = MIN2(k, (int)previous_addp->outcnt()-1); + } + + // Remove the old AddP from the processing list because it's dead now + assert(previous_addp->outcnt() == 0, "AddP should be dead now."); + alloc_worklist.remove_if_existing(previous_addp); +} + +// Create a 'selector' Phi based on the inputs of 'ophi'. If index 'i' of the +// selector is: +// -> a '-1' constant, the i'th input of the original Phi is NSR. +// -> a 'x' constant >=0, the i'th input of of original Phi will be SR and +// the info about the scalarized object will be at index x of ObjectMergeValue::possible_objects +PhiNode* ConnectionGraph::create_selector(PhiNode* ophi) const { + Node* minus_one = _igvn->register_new_node_with_optimizer(ConINode::make(-1)); + Node* selector = _igvn->register_new_node_with_optimizer(PhiNode::make(ophi->region(), minus_one, TypeInt::INT)); + uint number_of_sr_objects = 0; for (uint i = 1; i < ophi->req(); i++) { - Node* base = ophi->in(i); + Node* base = ophi->in(i); JavaObjectNode* ptn = unique_java_object(base); if (ptn != nullptr && ptn->scalar_replaceable()) { @@ -664,9 +1081,110 @@ void ConnectionGraph::reduce_phi_on_safepoints(PhiNode* ophi, Unique_Node_List* } } - // Update the debug information of all safepoints in turn - for (uint spi = 0; spi < safepoints->size(); spi++) { - SafePointNode* sfpt = safepoints->at(spi)->as_SafePoint(); + return selector->as_Phi(); +} + +// Returns true if the AddP node 'n' has at least one base that is a reducible +// merge. If the base is a CastPP/CheckCastPP then the input of the cast is +// checked instead. +bool ConnectionGraph::has_reducible_merge_base(AddPNode* n, Unique_Node_List &reducible_merges) { + PointsToNode* ptn = ptnode_adr(n->_idx); + if (ptn == nullptr || !ptn->is_Field() || ptn->as_Field()->base_count() < 2) { + return false; + } + + for (BaseIterator i(ptn->as_Field()); i.has_next(); i.next()) { + Node* base = i.get()->ideal_node(); + + if (reducible_merges.member(base)) { + return true; + } + + if (base->is_CastPP() || base->is_CheckCastPP()) { + base = base->in(1); + if (reducible_merges.member(base)) { + return true; + } + } + } + + return false; +} + +// This method will call its helper method to reduce SafePoint nodes that use +// 'ophi' or a casted version of 'ophi'. All SafePoint nodes using the same +// "version" of Phi use the same debug information (regarding the Phi). +// Therefore, I collect all safepoints and patch them all at once. +// +// The safepoints using the Phi node have to be processed before safepoints of +// CastPP nodes. The reason is, when reducing a CastPP we add a reference (the +// NSR merge pointer) to the input of the CastPP (i.e., the Phi) in the +// safepoint. If we process CastPP's safepoints before Phi's safepoints the +// algorithm that process Phi's safepoints will think that the added Phi +// reference is a regular reference. +bool ConnectionGraph::reduce_phi_on_safepoints(PhiNode* ophi) { + PhiNode* selector = create_selector(ophi); + Unique_Node_List safepoints; + Unique_Node_List casts; + + // Just collect the users of the Phis for later processing + // in the needed order. + for (uint i = 0; i < ophi->outcnt(); i++) { + Node* use = ophi->raw_out(i); + if (use->is_SafePoint()) { + safepoints.push(use); + } else if (use->is_CastPP()) { + casts.push(use); + } else { + assert(use->outcnt() == 0, "Only CastPP & SafePoint users should be left."); + } + } + + // Need to process safepoints using the Phi first + if (!reduce_phi_on_safepoints_helper(ophi, nullptr, selector, safepoints)) { + return false; + } + + // Now process CastPP->safepoints + for (uint i = 0; i < casts.size(); i++) { + Node* cast = casts.at(i); + Unique_Node_List cast_sfpts; + + for (DUIterator_Fast jmax, j = cast->fast_outs(jmax); j < jmax; j++) { + Node* use_use = cast->fast_out(j); + if (use_use->is_SafePoint()) { + cast_sfpts.push(use_use); + } else { + assert(use_use->outcnt() == 0, "Only SafePoint users should be left."); + } + } + + if (!reduce_phi_on_safepoints_helper(ophi, cast, selector, cast_sfpts)) { + return false; + } + } + + return true; +} + +// This method will create a SafePointScalarMERGEnode for each SafePoint in +// 'safepoints'. It then will iterate on the inputs of 'ophi' and create a +// SafePointScalarObjectNode for each scalar replaceable input. Each +// SafePointScalarMergeNode may describe multiple scalar replaced objects - +// check detailed description in SafePointScalarMergeNode class header. +bool ConnectionGraph::reduce_phi_on_safepoints_helper(Node* ophi, Node* cast, Node* selector, Unique_Node_List& safepoints) { + PhaseMacroExpand mexp(*_igvn); + Node* original_sfpt_parent = cast != nullptr ? cast : ophi; + const TypeOopPtr* merge_t = _igvn->type(original_sfpt_parent)->make_oopptr(); + + Node* nsr_merge_pointer = ophi; + if (cast != nullptr) { + const Type* new_t = merge_t->meet(TypePtr::NULL_PTR); + nsr_merge_pointer = _igvn->transform(ConstraintCastNode::make_cast_for_type(cast->in(0), cast->in(1), new_t, ConstraintCastNode::RegularDependency, nullptr)); + } + + for (uint spi = 0; spi < safepoints.size(); spi++) { + SafePointNode* sfpt = safepoints.at(spi)->as_SafePoint(); JVMState *jvms = sfpt->jvms(); uint merge_idx = (sfpt->req() - jvms->scloff()); int debug_start = jvms->debug_start(); @@ -680,11 +1198,11 @@ void ConnectionGraph::reduce_phi_on_safepoints(PhiNode* ophi, Unique_Node_List* // (2) A selector, used to decide if we need to rematerialize an object // or use the pointer to a NSR object. // See more details of these fields in the declaration of SafePointScalarMergeNode - sfpt->add_req(ophi); + sfpt->add_req(nsr_merge_pointer); sfpt->add_req(selector); for (uint i = 1; i < ophi->req(); i++) { - Node* base = ophi->in(i); + Node* base = ophi->in(i); JavaObjectNode* ptn = unique_java_object(base); // If the base is not scalar replaceable we don't need to register information about @@ -696,8 +1214,7 @@ void ConnectionGraph::reduce_phi_on_safepoints(PhiNode* ophi, Unique_Node_List* AllocateNode* alloc = ptn->ideal_node()->as_Allocate(); SafePointScalarObjectNode* sobj = mexp.create_scalarized_object_description(alloc, sfpt); if (sobj == nullptr) { - _compile->record_failure(C2Compiler::retry_no_reduce_allocation_merges()); - return; + return false; } // Now make a pass over the debug information replacing any references @@ -709,20 +1226,69 @@ void ConnectionGraph::reduce_phi_on_safepoints(PhiNode* ophi, Unique_Node_List* smerge->add_req(sobj); } - // Replaces debug information references to "ophi" in "sfpt" with references to "smerge" - sfpt->replace_edges_in_range(ophi, smerge, debug_start, jvms->debug_end(), _igvn); + // Replaces debug information references to "original_sfpt_parent" in "sfpt" with references to "smerge" + sfpt->replace_edges_in_range(original_sfpt_parent, smerge, debug_start, jvms->debug_end(), _igvn); // The call to 'replace_edges_in_range' above might have removed the // reference to ophi that we need at _merge_pointer_idx. The line below make // sure the reference is maintained. - sfpt->set_req(smerge->merge_pointer_idx(jvms), ophi); + sfpt->set_req(smerge->merge_pointer_idx(jvms), nsr_merge_pointer); _igvn->_worklist.push(sfpt); } - // Now we can change ophi since we don't need to know the types - // of the input allocations anymore. - const Type* new_t = merge_t->meet(TypePtr::NULL_PTR); - Node* new_phi = _igvn->register_new_node_with_optimizer(PhiNode::make(ophi->region(), null_ptr, new_t)); + return true; +} + +void ConnectionGraph::reduce_phi(PhiNode* ophi, GrowableArray &alloc_worklist, GrowableArray &memnode_worklist) { + bool delay = _igvn->delay_transform(); + _igvn->set_delay_transform(true); + _igvn->hash_delete(ophi); + + // Copying all users first because some will be removed and others won't. + // Ophi also may acquire some new users as part of Cast reduction. + // CastPPs also need to be processed before CmpPs. + Unique_Node_List castpps; + Unique_Node_List others; + for (DUIterator_Fast imax, i = ophi->fast_outs(imax); i < imax; i++) { + Node* use = ophi->fast_out(i); + + if (use->is_CastPP()) { + castpps.push(use); + } else if (use->is_AddP() || use->is_Cmp()) { + others.push(use); + } else if (use->is_SafePoint()) { + // processed later + } else { + assert(use->is_SafePoint(), "Unexpected user of reducible Phi %d -> %d:%s:%d", ophi->_idx, use->_idx, use->Name(), use->outcnt()); + } + } + + // CastPPs need to be processed before Cmps because during the process of + // splitting CastPPs we make reference to the inputs of the Cmp that is used + // by the If controlling the CastPP. + for (uint i = 0; i < castpps.size(); i++) { + reduce_phi_on_castpp_field_load(castpps.at(i), alloc_worklist, memnode_worklist); + } + + for (uint i = 0; i < others.size(); i++) { + Node* use = others.at(i); + + if (use->is_AddP()) { + reduce_phi_on_field_access(use, alloc_worklist); + } else if(use->is_Cmp()) { + reduce_phi_on_cmp(use); + } + } + + _igvn->set_delay_transform(delay); +} + +void ConnectionGraph::reset_scalar_replaceable_entries(PhiNode* ophi) { + Node* null_ptr = _igvn->makecon(TypePtr::NULL_PTR); + const TypeOopPtr* merge_t = _igvn->type(ophi)->make_oopptr(); + const Type* new_t = merge_t->meet(TypePtr::NULL_PTR); + Node* new_phi = _igvn->register_new_node_with_optimizer(PhiNode::make(ophi->region(), null_ptr, new_t)); + for (uint i = 1; i < ophi->req(); i++) { Node* base = ophi->in(i); JavaObjectNode* ptn = unique_java_object(base); @@ -734,36 +1300,34 @@ void ConnectionGraph::reduce_phi_on_safepoints(PhiNode* ophi, Unique_Node_List* } } - _igvn->replace_node(ophi, new_phi); - _igvn->hash_insert(ophi); - _igvn->_worklist.push(ophi); -} + for (int i = ophi->outcnt()-1; i >= 0;) { + Node* out = ophi->raw_out(i); -void ConnectionGraph::reduce_phi(PhiNode* ophi) { - Unique_Node_List safepoints; + if (out->is_ConstraintCast()) { + const Type* out_t = _igvn->type(out)->make_ptr(); + const Type* out_new_t = out_t->meet(TypePtr::NULL_PTR); + bool change = out_new_t != out_t; - for (uint i = 0; i < ophi->outcnt(); i++) { - Node* use = ophi->raw_out(i); + for (int j = out->outcnt()-1; change && j >= 0; --j) { + Node* out2 = out->raw_out(j); + if (!out2->is_SafePoint()) { + change = false; + break; + } + } - // All SafePoint nodes using the same Phi node use the same debug - // information (regarding the Phi). Furthermore, reducing the Phi used by a - // SafePoint requires changing the Phi. Therefore, I collect all safepoints - // and patch them all at once later. - if (use->is_SafePoint()) { - safepoints.push(use->as_SafePoint()); - } else { -#ifdef ASSERT - ophi->dump(-3); - assert(false, "Unexpected user of reducible Phi %d -> %d:%s", ophi->_idx, use->_idx, use->Name()); -#endif - _compile->record_failure(C2Compiler::retry_no_reduce_allocation_merges()); - return; + if (change) { + Node* new_cast = ConstraintCastNode::make_cast_for_type(out->in(0), out->in(1), out_new_t, ConstraintCastNode::StrongDependency, nullptr); + _igvn->replace_node(out, new_cast); + _igvn->register_new_node_with_optimizer(new_cast); + } } - } - if (safepoints.size() > 0) { - reduce_phi_on_safepoints(ophi, &safepoints); + --i; + i = MIN2(i, (int)ophi->outcnt()-1); } + + _igvn->replace_node(ophi, new_phi); } void ConnectionGraph::verify_ram_nodes(Compile* C, Node* root) { @@ -2328,11 +2892,14 @@ void ConnectionGraph::adjust_scalar_replaceable_state(JavaObjectNode* jobj, Uniq if (ptn->is_JavaObject() && ptn != jobj) { Node* use_n = use->ideal_node(); + // These other local vars may point to multiple objects through a Phi + // In this case we skip them and see if we can reduce the Phi. + if (use_n->is_CastPP() || use_n->is_CheckCastPP()) { + use_n = use_n->in(1); + } + // If it's already a candidate or confirmed reducible merge we can skip verification - if (candidates.member(use_n)) { - continue; - } else if (reducible_merges.member(use_n)) { - candidates.push(use_n); + if (candidates.member(use_n) || reducible_merges.member(use_n)) { continue; } @@ -2406,20 +2973,22 @@ void ConnectionGraph::adjust_scalar_replaceable_state(JavaObjectNode* jobj, Uniq // if ( x ) p[0] = new Point(); // Will be not scalar replaced // if (field->base_count() > 1 && candidates.size() == 0) { - for (BaseIterator i(field); i.has_next(); i.next()) { - PointsToNode* base = i.get(); - // Don't take into account LocalVar nodes which - // may point to only one object which should be also - // this field's base by now. - if (base->is_JavaObject() && base != jobj) { - // Mark all bases. - set_not_scalar_replaceable(jobj NOT_PRODUCT(COMMA "may point to more than one object")); - set_not_scalar_replaceable(base NOT_PRODUCT(COMMA "may point to more than one object")); + if (has_non_reducible_merge(field, reducible_merges)) { + for (BaseIterator i(field); i.has_next(); i.next()) { + PointsToNode* base = i.get(); + // Don't take into account LocalVar nodes which + // may point to only one object which should be also + // this field's base by now. + if (base->is_JavaObject() && base != jobj) { + // Mark all bases. + set_not_scalar_replaceable(jobj NOT_PRODUCT(COMMA "may point to more than one object")); + set_not_scalar_replaceable(base NOT_PRODUCT(COMMA "may point to more than one object")); + } } - } - if (!jobj->scalar_replaceable()) { - return; + if (!jobj->scalar_replaceable()) { + return; + } } } } @@ -2434,6 +3003,16 @@ void ConnectionGraph::adjust_scalar_replaceable_state(JavaObjectNode* jobj, Uniq } } +bool ConnectionGraph::has_non_reducible_merge(FieldNode* field, Unique_Node_List& reducible_merges) { + for (BaseIterator i(field); i.has_next(); i.next()) { + Node* base = i.get()->ideal_node(); + if (base->is_Phi() && !reducible_merges.member(base)) { + return true; + } + } + return false; +} + // Propagate NSR (Not scalar replaceable) state. void ConnectionGraph::find_scalar_replaceable_allocs(GrowableArray& jobj_worklist) { int jobj_length = jobj_worklist.length(); @@ -2566,7 +3145,8 @@ void ConnectionGraph::optimize_ideal_graph(GrowableArray& ptr_cmp_worklis if (OptimizePtrCompare) { for (int i = 0; i < ptr_cmp_worklist.length(); i++) { Node *n = ptr_cmp_worklist.at(i); - const TypeInt* tcmp = optimize_ptr_compare(n); + assert(n->Opcode() == Op_CmpN || n->Opcode() == Op_CmpP, "must be"); + const TypeInt* tcmp = optimize_ptr_compare(n->in(1), n->in(2)); if (tcmp->singleton()) { Node* cmp = igvn->makecon(tcmp); #ifndef PRODUCT @@ -2599,17 +3179,25 @@ void ConnectionGraph::optimize_ideal_graph(GrowableArray& ptr_cmp_worklis } // Optimize objects compare. -const TypeInt* ConnectionGraph::optimize_ptr_compare(Node* n) { +const TypeInt* ConnectionGraph::optimize_ptr_compare(Node* left, Node* right) { assert(OptimizePtrCompare, "sanity"); - assert(n->Opcode() == Op_CmpN || n->Opcode() == Op_CmpP, "must be"); const TypeInt* EQ = TypeInt::CC_EQ; // [0] == ZERO const TypeInt* NE = TypeInt::CC_GT; // [1] == ONE const TypeInt* UNKNOWN = TypeInt::CC; // [-1, 0,1] - PointsToNode* ptn1 = ptnode_adr(n->in(1)->_idx); - PointsToNode* ptn2 = ptnode_adr(n->in(2)->_idx); - JavaObjectNode* jobj1 = unique_java_object(n->in(1)); - JavaObjectNode* jobj2 = unique_java_object(n->in(2)); + PointsToNode* ptn1 = ptnode_adr(left->_idx); + PointsToNode* ptn2 = ptnode_adr(right->_idx); + JavaObjectNode* jobj1 = unique_java_object(left); + JavaObjectNode* jobj2 = unique_java_object(right); + + // The use of this method during allocation merge reduction may cause 'left' + // or 'right' be something (e.g., a Phi) that isn't in the connection graph or + // that doesn't reference an unique java object. + if (ptn1 == nullptr || ptn2 == nullptr || + jobj1 == nullptr || jobj2 == nullptr) { + return UNKNOWN; + } + assert(ptn1->is_JavaObject() || ptn1->is_LocalVar(), "sanity"); assert(ptn2->is_JavaObject() || ptn2->is_LocalVar(), "sanity"); @@ -3800,11 +4388,11 @@ void ConnectionGraph::split_unique_types(GrowableArray &alloc_worklist, } } } else if (n->is_AddP()) { - Node* addp_base = get_addp_base(n); - if (addp_base != nullptr && reducible_merges.member(addp_base)) { + if (has_reducible_merge_base(n->as_AddP(), reducible_merges)) { // This AddP will go away when we reduce the the Phi continue; } + Node* addp_base = get_addp_base(n); JavaObjectNode* jobj = unique_java_object(addp_base); if (jobj == nullptr || jobj == phantom_obj) { #ifdef ASSERT @@ -3826,16 +4414,21 @@ void ConnectionGraph::split_unique_types(GrowableArray &alloc_worklist, assert(n->is_Phi(), "loops only through Phi's"); continue; // already processed } - // Reducible Phi's will be removed from the graph after split_unique_types finishes + // Reducible Phi's will be removed from the graph after split_unique_types + // finishes. For now we just try to split out the SR inputs of the merge. + Node* parent = n->in(1); if (reducible_merges.member(n)) { - // Split loads through phi - reduce_phi_on_field_access(n->as_Phi(), alloc_worklist); + reduce_phi(n->as_Phi(), alloc_worklist, memnode_worklist); #ifdef ASSERT if (VerifyReduceAllocationMerges) { reduced_merges.push(n); } #endif continue; + } else if (reducible_merges.member(parent)) { + // 'n' is an user of a reducible merge (a Phi). It will be simplified as + // part of reduce_merge. + continue; } JavaObjectNode* jobj = unique_java_object(n); if (jobj == nullptr || jobj == phantom_obj) { @@ -3948,7 +4541,6 @@ void ConnectionGraph::split_unique_types(GrowableArray &alloc_worklist, #ifdef ASSERT if (VerifyReduceAllocationMerges) { - // At this point reducible Phis shouldn't have AddP users anymore; only SafePoints. for (uint i = 0; i < reducible_merges.size(); i++) { Node* phi = reducible_merges.at(i); @@ -3958,9 +4550,10 @@ void ConnectionGraph::split_unique_types(GrowableArray &alloc_worklist, assert(false, "This reducible merge wasn't reduced."); } + // At this point reducible Phis shouldn't have AddP users anymore; only SafePoints or Casts. for (DUIterator_Fast jmax, j = phi->fast_outs(jmax); j < jmax; j++) { Node* use = phi->fast_out(j); - if (!use->is_SafePoint()) { + if (!use->is_SafePoint() && !use->is_CastPP()) { phi->dump(2); phi->dump(-2); assert(false, "Unexpected user of reducible Phi -> %d:%s:%d", use->_idx, use->Name(), use->outcnt()); diff --git a/src/hotspot/share/opto/escape.hpp b/src/hotspot/share/opto/escape.hpp index 4ed7fb7f054..658c8f6e8fe 100644 --- a/src/hotspot/share/opto/escape.hpp +++ b/src/hotspot/share/opto/escape.hpp @@ -479,7 +479,7 @@ class ConnectionGraph: public ArenaObj { void optimize_ideal_graph(GrowableArray& ptr_cmp_worklist, GrowableArray& storestore_worklist); // Optimize objects compare. - const TypeInt* optimize_ptr_compare(Node* n); + const TypeInt* optimize_ptr_compare(Node* left, Node* right); // Returns unique corresponding java object or null. JavaObjectNode* unique_java_object(Node *n) const; @@ -590,14 +590,27 @@ class ConnectionGraph: public ArenaObj { // ------------------------------------------- // Methods related to Reduce Allocation Merges - + bool has_non_reducible_merge(FieldNode* field, Unique_Node_List& reducible_merges); + PhiNode* create_selector(PhiNode* ophi) const; + void updates_after_load_split(Node* data_phi, Node* previous_load, GrowableArray &alloc_worklist); + Node* split_castpp_load_through_phi(Node* curr_addp, Node* curr_load, Node* region, GrowableArray* bases_for_loads, GrowableArray &alloc_worklist); + void reset_scalar_replaceable_entries(PhiNode* ophi); + bool has_reducible_merge_base(AddPNode* n, Unique_Node_List &reducible_merges); + Node* specialize_cmp(Node* base, Node* curr_ctrl); + Node* specialize_castpp(Node* castpp, Node* base, Node* current_control); + + bool can_reduce_cmp(Node* n, Node* cmp) const; + bool has_been_reduced(PhiNode* n, SafePointNode* sfpt) const; bool can_reduce_phi(PhiNode* ophi) const; - bool can_reduce_phi_check_users(PhiNode* ophi) const; + bool can_reduce_check_users(Node* n, uint nesting) const; bool can_reduce_phi_check_inputs(PhiNode* ophi) const; - void reduce_phi_on_field_access(PhiNode* ophi, GrowableArray &alloc_worklist); - void reduce_phi_on_safepoints(PhiNode* ophi, Unique_Node_List* safepoints); - void reduce_phi(PhiNode* ophi); + void reduce_phi_on_field_access(Node* previous_addp, GrowableArray &alloc_worklist); + void reduce_phi_on_castpp_field_load(Node* castpp, GrowableArray &alloc_worklist, GrowableArray &memnode_worklist); + void reduce_phi_on_cmp(Node* cmp); + bool reduce_phi_on_safepoints(PhiNode* ophi); + bool reduce_phi_on_safepoints_helper(Node* ophi, Node* cast, Node* selector, Unique_Node_List& safepoints); + void reduce_phi(PhiNode* ophi, GrowableArray &alloc_worklist, GrowableArray &memnode_worklist); void set_not_scalar_replaceable(PointsToNode* ptn NOT_PRODUCT(COMMA const char* reason)) const { #ifndef PRODUCT diff --git a/src/hotspot/share/opto/loopTransform.cpp b/src/hotspot/share/opto/loopTransform.cpp index 31ef298d3af..5fd98251af5 100644 --- a/src/hotspot/share/opto/loopTransform.cpp +++ b/src/hotspot/share/opto/loopTransform.cpp @@ -1488,96 +1488,26 @@ void PhaseIdealLoop::count_opaque_loop_nodes(Node* n, uint& init, uint& stride) } } -// Create a new Bool node from the provided Template Assertion Predicate. -// Unswitched loop: new_init and new_stride are both null. Clone OpaqueLoopInit and OpaqueLoopStride. -// Otherwise: Replace found OpaqueLoop* nodes with new_init and new_stride, respectively. -Node* PhaseIdealLoop::create_bool_from_template_assertion_predicate(Node* template_assertion_predicate, Node* new_init, - Node* new_stride, Node* control) { - Node_Stack to_clone(2); - Node* opaque4 = template_assertion_predicate->in(1); - assert(opaque4->Opcode() == Op_Opaque4, "must be Opaque4"); - to_clone.push(opaque4, 1); - uint current = C->unique(); - Node* result = nullptr; - bool is_unswitched_loop = new_init == nullptr && new_stride == nullptr; - assert(new_init != nullptr || is_unswitched_loop, "new_init must be set when new_stride is non-null"); - // Look for the opaque node to replace with the new value - // and clone everything in between. We keep the Opaque4 node - // so the duplicated predicates are eliminated once loop - // opts are over: they are here only to keep the IR graph - // consistent. - do { - Node* n = to_clone.node(); - uint i = to_clone.index(); - Node* m = n->in(i); - if (is_part_of_template_assertion_predicate_bool(m)) { - to_clone.push(m, 1); - continue; - } - if (m->is_Opaque1()) { - if (n->_idx < current) { - n = n->clone(); - register_new_node(n, control); - } - int op = m->Opcode(); - if (op == Op_OpaqueLoopInit) { - if (is_unswitched_loop && m->_idx < current && new_init == nullptr) { - new_init = m->clone(); - register_new_node(new_init, control); - } - n->set_req(i, new_init); - } else { - assert(op == Op_OpaqueLoopStride, "unexpected opaque node"); - if (is_unswitched_loop && m->_idx < current && new_stride == nullptr) { - new_stride = m->clone(); - register_new_node(new_stride, control); - } - if (new_stride != nullptr) { - n->set_req(i, new_stride); - } - } - to_clone.set_node(n); - } - while (true) { - Node* cur = to_clone.node(); - uint j = to_clone.index(); - if (j+1 < cur->req()) { - to_clone.set_index(j+1); - break; - } - to_clone.pop(); - if (to_clone.size() == 0) { - result = cur; - break; - } - Node* next = to_clone.node(); - j = to_clone.index(); - if (next->in(j) != cur) { - assert(cur->_idx >= current || next->in(j)->Opcode() == Op_Opaque1, "new node or Opaque1 being replaced"); - if (next->_idx < current) { - next = next->clone(); - register_new_node(next, control); - to_clone.set_node(next); - } - next->set_req(j, cur); - } - } - } while (result == nullptr); - assert(result->_idx >= current, "new node expected"); - assert(!is_unswitched_loop || new_init != nullptr, "new_init must always be found and cloned"); - return result; -} - // Clone an Assertion Predicate for the main loop. new_init and new_stride are set as new inputs. Since the predicates // cannot fail at runtime, Halt nodes are inserted instead of uncommon traps. Node* PhaseIdealLoop::clone_assertion_predicate_and_initialize(Node* iff, Node* new_init, Node* new_stride, Node* predicate, Node* uncommon_proj, Node* control, IdealLoopTree* outer_loop, Node* input_proj) { - Node* result = create_bool_from_template_assertion_predicate(iff, new_init, new_stride, control); + TemplateAssertionPredicateExpression template_assertion_predicate_expression(iff->in(1)->as_Opaque4()); + Opaque4Node* new_opaque4_node; + if (new_stride == nullptr) { + // Only set a new OpaqueLoopInitNode node and clone the existing OpaqueLoopStrideNode without modification. + // This is done when creating a new Template Assertion Predicate for the main loop which requires a new init node. + assert(new_init->is_OpaqueLoopInit(), "only for creating new Template Assertion Predicates"); + new_opaque4_node = template_assertion_predicate_expression.clone_and_replace_init(new_init, control, this); + } else { + new_opaque4_node = template_assertion_predicate_expression.clone_and_replace_init_and_stride(new_init, new_stride, + control, this); + } Node* proj = predicate->clone(); Node* other_proj = uncommon_proj->clone(); Node* new_iff = iff->clone(); - new_iff->set_req(1, result); + new_iff->set_req(1, new_opaque4_node); proj->set_req(0, new_iff); other_proj->set_req(0, new_iff); Node* frame = new ParmNode(C->start(), TypeFunc::FramePtr); diff --git a/src/hotspot/share/opto/loopnode.hpp b/src/hotspot/share/opto/loopnode.hpp index dbd7d2fdeb9..e4654f6538c 100644 --- a/src/hotspot/share/opto/loopnode.hpp +++ b/src/hotspot/share/opto/loopnode.hpp @@ -950,8 +950,6 @@ class PhaseIdealLoop : public PhaseTransform { Node* input_proj); static void count_opaque_loop_nodes(Node* n, uint& init, uint& stride); static bool subgraph_has_opaque(Node* n); - Node* create_bool_from_template_assertion_predicate(Node* template_assertion_predicate, Node* new_init, Node* new_stride, - Node* control); static bool assertion_predicate_has_loop_opaque_node(IfNode* iff); static void get_assertion_predicates(Node* predicate, Unique_Node_List& list, bool get_opaque = false); void update_main_loop_assertion_predicates(Node* ctrl, CountedLoopNode* loop_head, Node* init, int stride_con); diff --git a/src/hotspot/share/opto/memnode.cpp b/src/hotspot/share/opto/memnode.cpp index e0a364d5056..fa57801d327 100644 --- a/src/hotspot/share/opto/memnode.cpp +++ b/src/hotspot/share/opto/memnode.cpp @@ -227,7 +227,7 @@ Node *MemNode::optimize_memory_chain(Node *mchain, const TypePtr *t_adr, Node *l t->is_oopptr()->cast_to_exactness(true) ->is_oopptr()->cast_to_ptr_type(t_oop->ptr()) ->is_oopptr()->cast_to_instance_id(t_oop->instance_id()); - if (t_oop->is_aryptr()) { + if (t_oop->isa_aryptr()) { mem_t = mem_t->is_aryptr() ->cast_to_stable(t_oop->is_aryptr()->is_stable()) ->cast_to_size(t_oop->is_aryptr()->size()) @@ -944,6 +944,7 @@ Node* LoadNode::make(PhaseGVN& gvn, Node* ctl, Node* mem, Node* adr, const TypeP case T_DOUBLE: load = new LoadDNode (ctl, mem, adr, adr_type, rt, mo, control_dependency, require_atomic_access); break; case T_ADDRESS: load = new LoadPNode (ctl, mem, adr, adr_type, rt->is_ptr(), mo, control_dependency); break; case T_OBJECT: + case T_NARROWOOP: #ifdef _LP64 if (adr->bottom_type()->is_ptr_to_narrowoop()) { load = new LoadNNode(ctl, mem, adr, adr_type, rt->make_narrowoop(), mo, control_dependency); @@ -1548,14 +1549,19 @@ static bool stable_phi(PhiNode* phi, PhaseGVN *phase) { // Phi *base*. This method is essentially a copy of the validations performed // by 'split_through_phi'. The first use of this method was in EA code as part // of simplification of allocation merges. +// Some differences from original method (split_through_phi): +// - If base->is_CastPP(): base = base->in(1) bool LoadNode::can_split_through_phi_base(PhaseGVN* phase) { Node* mem = in(Memory); Node* address = in(Address); intptr_t ignore = 0; Node* base = AddPNode::Ideal_base_and_offset(address, phase, ignore); - bool base_is_phi = (base != nullptr) && base->is_Phi(); - if (req() > 3 || !base_is_phi) { + if (base->is_CastPP()) { + base = base->in(1); + } + + if (req() > 3 || base == nullptr || !base->is_Phi()) { return false; } diff --git a/src/hotspot/share/opto/node.hpp b/src/hotspot/share/opto/node.hpp index 1e068a725de..14cf1436671 100644 --- a/src/hotspot/share/opto/node.hpp +++ b/src/hotspot/share/opto/node.hpp @@ -61,6 +61,7 @@ class CastDDNode; class CastVVNode; class CastIINode; class CastLLNode; +class CastPPNode; class CatchNode; class CatchProjNode; class CheckCastPPNode; @@ -716,6 +717,7 @@ class Node { DEFINE_CLASS_ID(CastFF, ConstraintCast, 3) DEFINE_CLASS_ID(CastDD, ConstraintCast, 4) DEFINE_CLASS_ID(CastVV, ConstraintCast, 5) + DEFINE_CLASS_ID(CastPP, ConstraintCast, 6) DEFINE_CLASS_ID(CMove, Type, 3) DEFINE_CLASS_ID(SafePointScalarObject, Type, 4) DEFINE_CLASS_ID(DecodeNarrowPtr, Type, 5) @@ -896,6 +898,7 @@ class Node { DEFINE_CLASS_QUERY(CastII) DEFINE_CLASS_QUERY(CastLL) DEFINE_CLASS_QUERY(ConI) + DEFINE_CLASS_QUERY(CastPP) DEFINE_CLASS_QUERY(ConstraintCast) DEFINE_CLASS_QUERY(ClearArray) DEFINE_CLASS_QUERY(CMove) diff --git a/src/hotspot/share/opto/predicates.cpp b/src/hotspot/share/opto/predicates.cpp index 905254ae382..997a05dc1f2 100644 --- a/src/hotspot/share/opto/predicates.cpp +++ b/src/hotspot/share/opto/predicates.cpp @@ -170,6 +170,49 @@ class CloneStrategy : public TransformStrategyForOpaqueLoopNodes { } }; +// This strategy replaces the OpaqueLoopInitNode with the provided init node and clones the OpaqueLoopStrideNode. +class ReplaceInitAndCloneStrideStrategy : public TransformStrategyForOpaqueLoopNodes { + Node* const _new_init; + Node* const _new_ctrl; + PhaseIdealLoop* const _phase; + + public: + ReplaceInitAndCloneStrideStrategy(Node* new_init, Node* new_ctrl, PhaseIdealLoop* phase) + : _new_init(new_init), + _new_ctrl(new_ctrl), + _phase(phase) {} + NONCOPYABLE(ReplaceInitAndCloneStrideStrategy); + + Node* transform_opaque_init(OpaqueLoopInitNode* opaque_init) const override { + return _new_init; + } + + Node* transform_opaque_stride(OpaqueLoopStrideNode* opaque_stride) const override { + return _phase->clone_and_register(opaque_stride, _new_ctrl)->as_OpaqueLoopStride(); + } +}; + +// This strategy replaces the OpaqueLoopInit and OpaqueLoopStride nodes with the provided init and stride nodes, +// respectively. +class ReplaceInitAndStrideStrategy : public TransformStrategyForOpaqueLoopNodes { + Node* const _new_init; + Node* const _new_stride; + + public: + ReplaceInitAndStrideStrategy(Node* new_init, Node* new_stride) + : _new_init(new_init), + _new_stride(new_stride) {} + NONCOPYABLE(ReplaceInitAndStrideStrategy); + + Node* transform_opaque_init(OpaqueLoopInitNode* opaque_init) const override { + return _new_init; + } + + Node* transform_opaque_stride(OpaqueLoopStrideNode* opaque_stride) const override { + return _new_stride; + } +}; + // Creates an identical clone of this Template Assertion Predicate Expression (i.e.cloning all nodes from the Opaque4Node // to and including the OpaqueLoop* nodes). The cloned nodes are rewired to reflect the same graph structure as found for // this Template Assertion Predicate Expression. The cloned nodes get 'new_ctrl' as ctrl. There is no other update done @@ -179,6 +222,22 @@ Opaque4Node* TemplateAssertionPredicateExpression::clone(Node* new_ctrl, PhaseId return clone(clone_init_and_stride_strategy, new_ctrl, phase); } +// Same as clone() but instead of cloning the OpaqueLoopInitNode, we replace it with the provided 'new_init' node. +Opaque4Node* TemplateAssertionPredicateExpression::clone_and_replace_init(Node* new_init, Node* new_ctrl, + PhaseIdealLoop* phase) { + ReplaceInitAndCloneStrideStrategy replace_init_and_clone_stride_strategy(new_init, new_ctrl, phase); + return clone(replace_init_and_clone_stride_strategy, new_ctrl, phase); +} + +// Same as clone() but instead of cloning the OpaqueLoopInit and OpaqueLoopStride node, we replace them with the provided +// 'new_init' and 'new_stride' nodes, respectively. +Opaque4Node* TemplateAssertionPredicateExpression::clone_and_replace_init_and_stride(Node* new_init, Node* new_stride, + Node* new_ctrl, + PhaseIdealLoop* phase) { + ReplaceInitAndStrideStrategy replace_init_and_stride_strategy(new_init, new_stride); + return clone(replace_init_and_stride_strategy, new_ctrl, phase); +} + // Class to collect data nodes from a source to target nodes by following the inputs of the source node recursively. // The class takes a node filter to decide which input nodes to follow and a target node predicate to start backtracking // from. All nodes found on all paths from source->target(s) are returned in a Unique_Node_List (without duplicates). diff --git a/src/hotspot/share/opto/predicates.hpp b/src/hotspot/share/opto/predicates.hpp index 37c6510c65f..a794e31ac3b 100644 --- a/src/hotspot/share/opto/predicates.hpp +++ b/src/hotspot/share/opto/predicates.hpp @@ -307,6 +307,8 @@ class TemplateAssertionPredicateExpression : public StackObj { } Opaque4Node* clone(Node* new_ctrl, PhaseIdealLoop* phase); + Opaque4Node* clone_and_replace_init(Node* new_init, Node* new_ctrl,PhaseIdealLoop* phase); + Opaque4Node* clone_and_replace_init_and_stride(Node* new_init, Node* new_stride, Node* new_ctrl, PhaseIdealLoop* phase); }; // This class represents a Predicate Block (i.e. either a Loop Predicate Block, a Profiled Loop Predicate Block, diff --git a/src/hotspot/share/opto/runtime.cpp b/src/hotspot/share/opto/runtime.cpp index 7caaca8846c..605c95316e2 100644 --- a/src/hotspot/share/opto/runtime.cpp +++ b/src/hotspot/share/opto/runtime.cpp @@ -26,7 +26,6 @@ #include "classfile/vmClasses.hpp" #include "classfile/vmSymbols.hpp" #include "code/codeCache.hpp" -#include "code/compiledMethod.inline.hpp" #include "code/compiledIC.hpp" #include "code/nmethod.hpp" #include "code/pcDesc.hpp" @@ -84,7 +83,7 @@ // To force FullGCALot inside a runtime function, add the following two lines // // Universe::release_fullgc_alot_dummy(); -// MarkSweep::invoke(0, "Debugging"); +// Universe::heap()->collect(); // // At command line specify the parameters: -XX:+FullGCALot -XX:FullGCALotStart=100000000 @@ -1851,9 +1850,8 @@ static void trace_exception(outputStream* st, oop exception_oop, address excepti exception_oop->print_value_on(&tempst); tempst.print(" in "); CodeBlob* blob = CodeCache::find_blob(exception_pc); - if (blob->is_compiled()) { - CompiledMethod* cm = blob->as_compiled_method_or_null(); - cm->method()->print_value_on(&tempst); + if (blob->is_nmethod()) { + blob->as_nmethod()->method()->print_value_on(&tempst); } else if (blob->is_runtime_stub()) { tempst.print(""); } else { diff --git a/src/hotspot/share/opto/subnode.cpp b/src/hotspot/share/opto/subnode.cpp index 5ecd7b4251f..7eb7922c5fb 100644 --- a/src/hotspot/share/opto/subnode.cpp +++ b/src/hotspot/share/opto/subnode.cpp @@ -643,6 +643,14 @@ CmpNode *CmpNode::make(Node *in1, Node *in2, BasicType bt, bool unsigned_comp) { return new CmpULNode(in1, in2); } return new CmpLNode(in1, in2); + case T_OBJECT: + case T_ARRAY: + case T_ADDRESS: + case T_METADATA: + return new CmpPNode(in1, in2); + case T_NARROWOOP: + case T_NARROWKLASS: + return new CmpNNode(in1, in2); default: fatal("Not implemented for %s", type2name(bt)); } diff --git a/src/hotspot/share/opto/superword.cpp b/src/hotspot/share/opto/superword.cpp index c242e5a4ef7..4c4cdd074a1 100644 --- a/src/hotspot/share/opto/superword.cpp +++ b/src/hotspot/share/opto/superword.cpp @@ -3106,14 +3106,37 @@ VStatus VLoopBody::construct() { } else if (!post_visited.test(bb_idx(n))) { // cross or back arc const int old_length = stack.length(); + + // If a Load depends on the same memory state as a Store, we must make sure that + // the Load is ordered before the Store. + // + // mem + // | + // +--+--+ + // | | + // | Load (n) + // | + // Store (mem_use) + // + if (n->is_Load()) { + Node* mem = n->in(MemNode::Memory); + for (DUIterator_Fast imax, i = mem->fast_outs(imax); i < imax; i++) { + Node* mem_use = mem->fast_out(i); + if (mem_use->is_Store() && _vloop.in_bb(mem_use) && !visited.test(bb_idx(mem_use))) { + stack.push(mem_use); // Ordering edge: Load (n) -> Store (mem_use) + } + } + } + for (DUIterator_Fast imax, i = n->fast_outs(imax); i < imax; i++) { Node* use = n->fast_out(i); if (_vloop.in_bb(use) && !visited.test(bb_idx(use)) && // Don't go around backedge (!use->is_Phi() || n == _vloop.cl())) { - stack.push(use); + stack.push(use); // Ordering edge: n -> use } } + if (stack.length() == old_length) { // There were no additional uses, post visit node now stack.pop(); // Remove node from stack diff --git a/src/hotspot/share/opto/type.cpp b/src/hotspot/share/opto/type.cpp index 1bbfc588ce5..7fecf0b4d35 100644 --- a/src/hotspot/share/opto/type.cpp +++ b/src/hotspot/share/opto/type.cpp @@ -6344,7 +6344,8 @@ const Type *TypeAryKlassPtr::xmeet( const Type *t ) const { // For instances when a subclass meets a superclass we fall // below the centerline when the superclass is exact. We need to // do the same here. - if (tp->klass()->equals(ciEnv::current()->Object_klass()) && this_interfaces->intersection_with(tp_interfaces)->eq(tp_interfaces) && !tp->klass_is_exact()) { + if (tp->klass()->equals(ciEnv::current()->Object_klass()) && this_interfaces->contains(tp_interfaces) && + !tp->klass_is_exact()) { return TypeAryKlassPtr::make(ptr, _elem, _klass, offset); } else { // cannot subclass, so the meet has to fall badly below the centerline @@ -6362,7 +6363,8 @@ const Type *TypeAryKlassPtr::xmeet( const Type *t ) const { // For instances when a subclass meets a superclass we fall // below the centerline when the superclass is exact. We need // to do the same here. - if (tp->klass()->equals(ciEnv::current()->Object_klass()) && this_interfaces->intersection_with(tp_interfaces)->eq(tp_interfaces) && !tp->klass_is_exact()) { + if (tp->klass()->equals(ciEnv::current()->Object_klass()) && this_interfaces->contains(tp_interfaces) && + !tp->klass_is_exact()) { // that is, my array type is a subtype of 'tp' klass return make(ptr, _elem, _klass, offset); } @@ -6396,7 +6398,8 @@ template bool TypePtr::is_java_subtype_of_helper_for_array( } if (this_one->is_instance_type(other)) { - return other->klass() == ciEnv::current()->Object_klass() && other->_interfaces->intersection_with(this_one->_interfaces)->eq(other->_interfaces) && other_exact; + return other->klass() == ciEnv::current()->Object_klass() && this_one->_interfaces->contains(other->_interfaces) && + other_exact; } assert(this_one->is_array_type(other), ""); @@ -6462,7 +6465,8 @@ template bool TypePtr::maybe_java_subtype_of_helper_for_arr return true; } if (this_one->is_instance_type(other)) { - return other->klass()->equals(ciEnv::current()->Object_klass()) && other->_interfaces->intersection_with(this_one->_interfaces)->eq(other->_interfaces); + return other->klass()->equals(ciEnv::current()->Object_klass()) && + this_one->_interfaces->contains(other->_interfaces); } int dummy; diff --git a/src/hotspot/share/opto/vectorization.cpp b/src/hotspot/share/opto/vectorization.cpp index 0ad87256b27..7197b3a58a5 100644 --- a/src/hotspot/share/opto/vectorization.cpp +++ b/src/hotspot/share/opto/vectorization.cpp @@ -292,23 +292,40 @@ void VLoopDependencyGraph::add_node(MemNode* n, GrowableArray& memory_pred_ _dependency_nodes.at_put_grow(_body.bb_idx(n), dn, nullptr); } +int VLoopDependencyGraph::find_max_pred_depth(const Node* n) const { + int max_pred_depth = 0; + if (!n->is_Phi()) { // ignore backedge + for (PredsIterator it(*this, n); !it.done(); it.next()) { + Node* pred = it.current(); + if (_vloop.in_bb(pred)) { + max_pred_depth = MAX2(max_pred_depth, depth(pred)); + } + } + } + return max_pred_depth; +} + // We iterate over the body, which is already ordered by the dependencies, i.e. pred comes // before use. With a single pass, we can compute the depth of every node, since we can // assume that the depth of all preds is already computed when we compute the depth of use. void VLoopDependencyGraph::compute_depth() { for (int i = 0; i < _body.body().length(); i++) { Node* n = _body.body().at(i); - int max_pred_depth = 0; - if (n->is_Phi()) { - for (PredsIterator it(*this, n); !it.done(); it.next()) { - Node* pred = it.current(); - if (_vloop.in_bb(pred)) { - max_pred_depth = MAX2(max_pred_depth, depth(pred)); - } - } + set_depth(n, find_max_pred_depth(n) + 1); + } + +#ifdef ASSERT + for (int i = 0; i < _body.body().length(); i++) { + Node* n = _body.body().at(i); + int max_pred_depth = find_max_pred_depth(n); + if (depth(n) != max_pred_depth + 1) { + print(); + tty->print_cr("Incorrect depth: %d vs %d", depth(n), max_pred_depth + 1); + n->dump(); } - set_depth(n, max_pred_depth + 1); + assert(depth(n) == max_pred_depth + 1, "must have correct depth"); } +#endif } #ifndef PRODUCT diff --git a/src/hotspot/share/opto/vectorization.hpp b/src/hotspot/share/opto/vectorization.hpp index 9dc029efb6b..6840b01bb93 100644 --- a/src/hotspot/share/opto/vectorization.hpp +++ b/src/hotspot/share/opto/vectorization.hpp @@ -553,6 +553,7 @@ class VLoopDependencyGraph : public StackObj { void add_node(MemNode* n, GrowableArray& memory_pred_edges); int depth(const Node* n) const { return _depths.at(_body.bb_idx(n)); } void set_depth(const Node* n, int d) { _depths.at_put(_body.bb_idx(n), d); } + int find_max_pred_depth(const Node* n) const; void compute_depth(); NOT_PRODUCT( void print() const; ) diff --git a/src/hotspot/share/prims/forte.cpp b/src/hotspot/share/prims/forte.cpp index 53dbc3caee0..b5973d4ad02 100644 --- a/src/hotspot/share/prims/forte.cpp +++ b/src/hotspot/share/prims/forte.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -80,7 +80,7 @@ class vframeStreamForte : public vframeStreamCommon { }; -static bool is_decipherable_compiled_frame(JavaThread* thread, frame* fr, CompiledMethod* nm); +static bool is_decipherable_compiled_frame(JavaThread* thread, frame* fr, nmethod* nm); static bool is_decipherable_interpreted_frame(JavaThread* thread, frame* fr, Method** method_p, @@ -150,7 +150,7 @@ void vframeStreamForte::forte_next() { // Determine if 'fr' is a decipherable compiled frame. We are already // assured that fr is for a java compiled method. -static bool is_decipherable_compiled_frame(JavaThread* thread, frame* fr, CompiledMethod* nm) { +static bool is_decipherable_compiled_frame(JavaThread* thread, frame* fr, nmethod* nm) { assert(nm->is_java_method(), "invariant"); if (thread->has_last_Java_frame() && thread->last_Java_pc() == fr->pc()) { @@ -413,9 +413,9 @@ static bool find_initial_Java_frame(JavaThread* thread, return false; } - if (candidate.cb()->is_compiled()) { + if (candidate.cb()->is_nmethod()) { - CompiledMethod* nm = candidate.cb()->as_compiled_method(); + nmethod* nm = candidate.cb()->as_nmethod(); *method_p = nm->method(); // If the frame is not decipherable, then the value of -1 diff --git a/src/hotspot/share/prims/jvmtiCodeBlobEvents.cpp b/src/hotspot/share/prims/jvmtiCodeBlobEvents.cpp index df7e6de6c33..a32bba9225a 100644 --- a/src/hotspot/share/prims/jvmtiCodeBlobEvents.cpp +++ b/src/hotspot/share/prims/jvmtiCodeBlobEvents.cpp @@ -234,7 +234,7 @@ jvmtiError JvmtiCodeBlobEvents::generate_compiled_method_load_events(JvmtiEnv* e // Save events to the queue for posting outside the CodeCache_lock. MutexLocker mu(java_thread, CodeCache_lock, Mutex::_no_safepoint_check_flag); // Iterate over non-profiled and profiled nmethods - NMethodIterator iter(NMethodIterator::only_not_unloading); + NMethodIterator iter(NMethodIterator::not_unloading); while(iter.next()) { nmethod* current = iter.method(); current->post_compiled_method_load_event(state); diff --git a/src/hotspot/share/prims/jvmtiEnv.cpp b/src/hotspot/share/prims/jvmtiEnv.cpp index 43f372b3a28..14030c1f8d3 100644 --- a/src/hotspot/share/prims/jvmtiEnv.cpp +++ b/src/hotspot/share/prims/jvmtiEnv.cpp @@ -1678,39 +1678,22 @@ JvmtiEnv::GetAllStackTraces(jint max_frame_count, jvmtiStackInfo** stack_info_pt jvmtiError JvmtiEnv::GetThreadListStackTraces(jint thread_count, const jthread* thread_list, jint max_frame_count, jvmtiStackInfo** stack_info_ptr) { jvmtiError err = JVMTI_ERROR_NONE; - JvmtiVTMSTransitionDisabler disabler; if (thread_count == 1) { - // Use direct handshake if we need to get only one stack trace. JavaThread *current_thread = JavaThread::current(); - ThreadsListHandle tlh(current_thread); jthread thread = thread_list[0]; - JavaThread *java_thread; - oop thread_obj = nullptr; - err = get_threadOop_and_JavaThread(tlh.list(), thread, &java_thread, &thread_obj); - if (err != JVMTI_ERROR_NONE) { - return err; - } - - if (java_lang_VirtualThread::is_instance(thread_obj) && java_thread == nullptr) { - // Target virtual thread is unmounted. - ResourceMark rm(current_thread); - MultipleStackTracesCollector collector(this, max_frame_count); - collector.fill_frames(thread, java_thread, thread_obj); - collector.allocate_and_fill_stacks(/* thread_count */ 1); - *stack_info_ptr = collector.stack_info(); - return collector.result(); - } GetSingleStackTraceClosure op(this, current_thread, thread, max_frame_count); - Handshake::execute(&op, &tlh, java_thread); + JvmtiHandshake::execute(&op, thread); err = op.result(); if (err == JVMTI_ERROR_NONE) { *stack_info_ptr = op.stack_info(); } } else { + JvmtiVTMSTransitionDisabler disabler; + // JVMTI get stack traces at safepoint. VM_GetThreadListStackTraces op(this, thread_count, thread_list, max_frame_count); VMThread::execute(&op); @@ -1748,6 +1731,7 @@ JvmtiEnv::PopFrame(jthread thread) { JavaThread* java_thread = nullptr; oop thread_obj = nullptr; jvmtiError err = get_threadOop_and_JavaThread(tlh.list(), thread, &java_thread, &thread_obj); + Handle thread_handle(current_thread, thread_obj); if (err != JVMTI_ERROR_NONE) { return err; @@ -1774,11 +1758,7 @@ JvmtiEnv::PopFrame(jthread thread) { MutexLocker mu(JvmtiThreadState_lock); UpdateForPopTopFrameClosure op(state); - if (self) { - op.doit(java_thread, self); - } else { - Handshake::execute(&op, java_thread); - } + JvmtiHandshake::execute(&op, &tlh, java_thread, thread_handle); return op.result(); } /* end PopFrame */ diff --git a/src/hotspot/share/prims/jvmtiEnvBase.cpp b/src/hotspot/share/prims/jvmtiEnvBase.cpp index cf7f1743f8d..9b9197aa888 100644 --- a/src/hotspot/share/prims/jvmtiEnvBase.cpp +++ b/src/hotspot/share/prims/jvmtiEnvBase.cpp @@ -2053,17 +2053,30 @@ VM_GetThreadListStackTraces::doit() { } void -GetSingleStackTraceClosure::do_thread(Thread *target) { - JavaThread *jt = JavaThread::cast(target); +GetSingleStackTraceClosure::doit() { + JavaThread *jt = _target_jt; oop thread_oop = JNIHandles::resolve_external_guard(_jthread); - if (!jt->is_exiting() && thread_oop != nullptr) { + if ((jt == nullptr || !jt->is_exiting()) && thread_oop != nullptr) { ResourceMark rm; _collector.fill_frames(_jthread, jt, thread_oop); _collector.allocate_and_fill_stacks(1); + set_result(_collector.result()); } } +void +GetSingleStackTraceClosure::do_thread(Thread *target) { + assert(_target_jt == JavaThread::cast(target), "sanity check"); + doit(); +} + +void +GetSingleStackTraceClosure::do_vthread(Handle target_h) { + assert(_target_jt == nullptr || _target_jt->vthread() == target_h(), "sanity check"); + doit(); +} + void VM_GetAllStackTraces::doit() { assert(SafepointSynchronize::is_at_safepoint(), "must be at safepoint"); @@ -2166,6 +2179,7 @@ JvmtiEnvBase::force_early_return(jthread thread, jvalue value, TosState tos) { if (err != JVMTI_ERROR_NONE) { return err; } + Handle thread_handle(current_thread, thread_obj); bool self = java_thread == current_thread; err = check_non_suspended_or_opaque_frame(java_thread, thread_obj, self); @@ -2186,17 +2200,14 @@ JvmtiEnvBase::force_early_return(jthread thread, jvalue value, TosState tos) { return JVMTI_ERROR_OUT_OF_MEMORY; } + MutexLocker mu(JvmtiThreadState_lock); SetForceEarlyReturn op(state, value, tos); - if (self) { - op.doit(java_thread, self); - } else { - Handshake::execute(&op, java_thread); - } + JvmtiHandshake::execute(&op, &tlh, java_thread, thread_handle); return op.result(); } void -SetForceEarlyReturn::doit(Thread *target, bool self) { +SetForceEarlyReturn::doit(Thread *target) { JavaThread* java_thread = JavaThread::cast(target); Thread* current_thread = Thread::current(); HandleMark hm(current_thread); @@ -2331,7 +2342,7 @@ JvmtiModuleClosure::get_all_modules(JvmtiEnv* env, jint* module_count_ptr, jobje } void -UpdateForPopTopFrameClosure::doit(Thread *target, bool self) { +UpdateForPopTopFrameClosure::doit(Thread *target) { Thread* current_thread = Thread::current(); HandleMark hm(current_thread); JavaThread* java_thread = JavaThread::cast(target); diff --git a/src/hotspot/share/prims/jvmtiEnvBase.hpp b/src/hotspot/share/prims/jvmtiEnvBase.hpp index 637b0e70796..57fa059b2d8 100644 --- a/src/hotspot/share/prims/jvmtiEnvBase.hpp +++ b/src/hotspot/share/prims/jvmtiEnvBase.hpp @@ -456,16 +456,6 @@ class JvmtiEnvIterator : public StackObj { JvmtiEnv* next(JvmtiEnvBase* env) { return env->next_environment(); } }; -class JvmtiHandshakeClosure : public HandshakeClosure { - protected: - jvmtiError _result; - public: - JvmtiHandshakeClosure(const char* name) - : HandshakeClosure(name), - _result(JVMTI_ERROR_THREAD_NOT_ALIVE) {} - jvmtiError result() { return _result; } -}; - // Used in combination with the JvmtiHandshake class. // It is intended to support both platform and virtual threads. class JvmtiUnitedHandshakeClosure : public HandshakeClosure { @@ -499,36 +489,46 @@ class JvmtiHandshake : public Handshake { static void execute(JvmtiUnitedHandshakeClosure* hs_cl, jthread target); }; -class SetForceEarlyReturn : public JvmtiHandshakeClosure { +class SetForceEarlyReturn : public JvmtiUnitedHandshakeClosure { private: JvmtiThreadState* _state; jvalue _value; TosState _tos; public: SetForceEarlyReturn(JvmtiThreadState* state, jvalue value, TosState tos) - : JvmtiHandshakeClosure("SetForceEarlyReturn"), + : JvmtiUnitedHandshakeClosure("SetForceEarlyReturn"), _state(state), _value(value), _tos(tos) {} + void doit(Thread *target); void do_thread(Thread *target) { - doit(target, false /* self */); + doit(target); + } + void do_vthread(Handle target_h) { + assert(_target_jt != nullptr, "sanity check"); + assert(_target_jt->vthread() == target_h(), "sanity check"); + doit(_target_jt); // mounted virtual thread } - void doit(Thread *target, bool self); }; // HandshakeClosure to update for pop top frame. -class UpdateForPopTopFrameClosure : public JvmtiHandshakeClosure { +class UpdateForPopTopFrameClosure : public JvmtiUnitedHandshakeClosure { private: JvmtiThreadState* _state; public: UpdateForPopTopFrameClosure(JvmtiThreadState* state) - : JvmtiHandshakeClosure("UpdateForPopTopFrame"), + : JvmtiUnitedHandshakeClosure("UpdateForPopTopFrame"), _state(state) {} + void doit(Thread *target); void do_thread(Thread *target) { - doit(target, false /* self */); + doit(target); + } + void do_vthread(Handle target_h) { + assert(_target_jt != nullptr, "sanity check"); + assert(_target_jt->vthread() == target_h(), "sanity check"); + doit(_target_jt); // mounted virtual thread } - void doit(Thread *target, bool self); }; // HandshakeClosure to set frame pop. @@ -724,7 +724,7 @@ class VM_GetThreadListStackTraces : public VM_Operation { }; // HandshakeClosure to get single stack trace. -class GetSingleStackTraceClosure : public HandshakeClosure { +class GetSingleStackTraceClosure : public JvmtiUnitedHandshakeClosure { private: JavaThread *_calling_thread; jthread _jthread; @@ -733,14 +733,16 @@ class GetSingleStackTraceClosure : public HandshakeClosure { public: GetSingleStackTraceClosure(JvmtiEnv *env, JavaThread *calling_thread, jthread thread, jint max_frame_count) - : HandshakeClosure("GetSingleStackTrace"), + : JvmtiUnitedHandshakeClosure("GetSingleStackTrace"), _calling_thread(calling_thread), _jthread(thread), _collector(env, max_frame_count) { } void do_thread(Thread *target); + void do_vthread(Handle target_h); + void doit(); jvmtiStackInfo *stack_info() { return _collector.stack_info(); } - jvmtiError result() { return _collector.result(); } + jvmtiError result() { return _result; } }; // HandshakeClosure to count stack frames. diff --git a/src/hotspot/share/prims/jvmtiImpl.cpp b/src/hotspot/share/prims/jvmtiImpl.cpp index 21122539af8..7b9821fe28a 100644 --- a/src/hotspot/share/prims/jvmtiImpl.cpp +++ b/src/hotspot/share/prims/jvmtiImpl.cpp @@ -1014,17 +1014,17 @@ void JvmtiDeferredEvent::run_nmethod_entry_barriers() { // Keep the nmethod for compiled_method_load from being unloaded. -void JvmtiDeferredEvent::oops_do(OopClosure* f, CodeBlobClosure* cf) { +void JvmtiDeferredEvent::oops_do(OopClosure* f, NMethodClosure* cf) { if (cf != nullptr && _type == TYPE_COMPILED_METHOD_LOAD) { - cf->do_code_blob(_event_data.compiled_method_load); + cf->do_nmethod(_event_data.compiled_method_load); } } // The GC calls this and marks the nmethods here on the stack so that // they cannot be unloaded while in the queue. -void JvmtiDeferredEvent::nmethods_do(CodeBlobClosure* cf) { +void JvmtiDeferredEvent::nmethods_do(NMethodClosure* cf) { if (cf != nullptr && _type == TYPE_COMPILED_METHOD_LOAD) { - cf->do_code_blob(_event_data.compiled_method_load); + cf->do_nmethod(_event_data.compiled_method_load); } } @@ -1092,13 +1092,13 @@ void JvmtiDeferredEventQueue::run_nmethod_entry_barriers() { } -void JvmtiDeferredEventQueue::oops_do(OopClosure* f, CodeBlobClosure* cf) { +void JvmtiDeferredEventQueue::oops_do(OopClosure* f, NMethodClosure* cf) { for(QueueNode* node = _queue_head; node != nullptr; node = node->next()) { node->event().oops_do(f, cf); } } -void JvmtiDeferredEventQueue::nmethods_do(CodeBlobClosure* cf) { +void JvmtiDeferredEventQueue::nmethods_do(NMethodClosure* cf) { for(QueueNode* node = _queue_head; node != nullptr; node = node->next()) { node->event().nmethods_do(cf); } diff --git a/src/hotspot/share/prims/jvmtiImpl.hpp b/src/hotspot/share/prims/jvmtiImpl.hpp index c93abe5eedf..5977e000621 100644 --- a/src/hotspot/share/prims/jvmtiImpl.hpp +++ b/src/hotspot/share/prims/jvmtiImpl.hpp @@ -499,9 +499,9 @@ class JvmtiDeferredEvent { void post_compiled_method_load_event(JvmtiEnv* env) NOT_JVMTI_RETURN; void run_nmethod_entry_barriers() NOT_JVMTI_RETURN; // GC support to keep nmethods from unloading while in the queue. - void nmethods_do(CodeBlobClosure* cf) NOT_JVMTI_RETURN; + void nmethods_do(NMethodClosure* cf) NOT_JVMTI_RETURN; // GC support to keep nmethod from being unloaded while in the queue. - void oops_do(OopClosure* f, CodeBlobClosure* cf) NOT_JVMTI_RETURN; + void oops_do(OopClosure* f, NMethodClosure* cf) NOT_JVMTI_RETURN; }; /** @@ -542,9 +542,9 @@ class JvmtiDeferredEventQueue : public CHeapObj { void run_nmethod_entry_barriers(); // GC support to keep nmethods from unloading while in the queue. - void nmethods_do(CodeBlobClosure* cf) NOT_JVMTI_RETURN; + void nmethods_do(NMethodClosure* cf) NOT_JVMTI_RETURN; // GC support to keep nmethod from being unloaded while in the queue. - void oops_do(OopClosure* f, CodeBlobClosure* cf) NOT_JVMTI_RETURN; + void oops_do(OopClosure* f, NMethodClosure* cf) NOT_JVMTI_RETURN; }; // Utility macro that checks for null pointers: diff --git a/src/hotspot/share/prims/jvmtiRedefineClasses.cpp b/src/hotspot/share/prims/jvmtiRedefineClasses.cpp index bcfb361c89f..4e0a429ffb2 100644 --- a/src/hotspot/share/prims/jvmtiRedefineClasses.cpp +++ b/src/hotspot/share/prims/jvmtiRedefineClasses.cpp @@ -4350,7 +4350,8 @@ void VM_RedefineClasses::redefine_single_class(Thread* current, jclass the_jclas the_class->vtable().initialize_vtable(); the_class->itable().initialize_itable(); - // Leave arrays of jmethodIDs and itable index cache unchanged + // Update jmethodID cache if present. + the_class->update_methods_jmethod_cache(); // Copy the "source debug extension" attribute from new class version the_class->set_source_debug_extension( diff --git a/src/hotspot/share/prims/jvmtiThreadState.cpp b/src/hotspot/share/prims/jvmtiThreadState.cpp index c5ba2c030d0..1e866236c98 100644 --- a/src/hotspot/share/prims/jvmtiThreadState.cpp +++ b/src/hotspot/share/prims/jvmtiThreadState.cpp @@ -984,7 +984,7 @@ void JvmtiThreadState::process_pending_step_for_earlyret() { } } -void JvmtiThreadState::oops_do(OopClosure* f, CodeBlobClosure* cf) { +void JvmtiThreadState::oops_do(OopClosure* f, NMethodClosure* cf) { f->do_oop((oop*) &_earlyret_oop); // Keep nmethods from unloading on the event queue @@ -993,7 +993,7 @@ void JvmtiThreadState::oops_do(OopClosure* f, CodeBlobClosure* cf) { } } -void JvmtiThreadState::nmethods_do(CodeBlobClosure* cf) { +void JvmtiThreadState::nmethods_do(NMethodClosure* cf) { // Keep nmethods from unloading on the event queue if (_jvmti_event_queue != nullptr) { _jvmti_event_queue->nmethods_do(cf); diff --git a/src/hotspot/share/prims/jvmtiThreadState.hpp b/src/hotspot/share/prims/jvmtiThreadState.hpp index 4bba0691e40..8d49f8af96c 100644 --- a/src/hotspot/share/prims/jvmtiThreadState.hpp +++ b/src/hotspot/share/prims/jvmtiThreadState.hpp @@ -525,8 +525,8 @@ class JvmtiThreadState : public CHeapObj { static ByteSize earlyret_oop_offset() { return byte_offset_of(JvmtiThreadState, _earlyret_oop); } static ByteSize earlyret_value_offset() { return byte_offset_of(JvmtiThreadState, _earlyret_value); } - void oops_do(OopClosure* f, CodeBlobClosure* cf) NOT_JVMTI_RETURN; // GC support - void nmethods_do(CodeBlobClosure* cf) NOT_JVMTI_RETURN; + void oops_do(OopClosure* f, NMethodClosure* cf) NOT_JVMTI_RETURN; // GC support + void nmethods_do(NMethodClosure* cf) NOT_JVMTI_RETURN; public: void set_should_post_on_exceptions(bool val); diff --git a/src/hotspot/share/prims/methodHandles.cpp b/src/hotspot/share/prims/methodHandles.cpp index 3ffe4853b8c..fd10f0723bf 100644 --- a/src/hotspot/share/prims/methodHandles.cpp +++ b/src/hotspot/share/prims/methodHandles.cpp @@ -1052,7 +1052,7 @@ JVM_ENTRY(jint, MHN_getNamedCon(JNIEnv *env, jobject igcls, jint which, jobjectA assert(which >= 0 && which < con_value_count, ""); int con = con_values[which]; objArrayHandle box(THREAD, (objArrayOop) JNIHandles::resolve(box_jh)); - if (box.not_null() && box->klass() == Universe::objectArrayKlassObj() && box->length() > 0) { + if (box.not_null() && box->klass() == Universe::objectArrayKlass() && box->length() > 0) { const char* str = &con_names[0]; for (int i = 0; i < which; i++) str += strlen(str) + 1; // skip name and null @@ -1255,7 +1255,7 @@ JVM_ENTRY(void, MHN_copyOutBootstrapArguments(JNIEnv* env, jobject igcls, InstanceKlass* caller = InstanceKlass::cast(caller_k); typeArrayOop index_info_oop = (typeArrayOop) JNIHandles::resolve(index_info_jh); if (index_info_oop == nullptr || - index_info_oop->klass() != Universe::intArrayKlassObj() || + index_info_oop->klass() != Universe::intArrayKlass() || typeArrayOop(index_info_oop)->length() < 2) { THROW_MSG(vmSymbols::java_lang_InternalError(), "bad index info (0)"); } diff --git a/src/hotspot/share/prims/vectorSupport.cpp b/src/hotspot/share/prims/vectorSupport.cpp index 4f2e78739ec..e0517c91e95 100644 --- a/src/hotspot/share/prims/vectorSupport.cpp +++ b/src/hotspot/share/prims/vectorSupport.cpp @@ -138,7 +138,7 @@ Handle VectorSupport::allocate_vector_payload_helper(InstanceKlass* ik, frame* f int elem_size = type2aelembytes(elem_bt); // On-heap vector values are represented as primitive arrays. - TypeArrayKlass* tak = TypeArrayKlass::cast(Universe::typeArrayKlassObj(elem_bt)); + TypeArrayKlass* tak = Universe::typeArrayKlass(elem_bt); typeArrayOop arr = tak->allocate(num_elem, CHECK_NH); // safepoint diff --git a/src/hotspot/share/prims/whitebox.cpp b/src/hotspot/share/prims/whitebox.cpp index d7de84ba20b..9ad77658072 100644 --- a/src/hotspot/share/prims/whitebox.cpp +++ b/src/hotspot/share/prims/whitebox.cpp @@ -768,9 +768,9 @@ class VM_WhiteBoxDeoptimizeFrames : public VM_WhiteBoxOperation { if (f->can_be_deoptimized() && !f->is_deoptimized_frame()) { Deoptimization::deoptimize(t, *f); if (_make_not_entrant) { - CompiledMethod* cm = CodeCache::find_compiled(f->pc()); - assert(cm != nullptr, "sanity check"); - cm->make_not_entrant(); + nmethod* nm = CodeCache::find_nmethod(f->pc()); + assert(nm != nullptr, "did not find nmethod"); + nm->make_not_entrant(); } ++_result; } @@ -820,7 +820,7 @@ WB_ENTRY(jint, WB_DeoptimizeMethod(JNIEnv* env, jobject o, jobject method, jbool if (is_osr) { result += mh->method_holder()->mark_osr_nmethods(&deopt_scope, mh()); } else { - MutexLocker ml(CompiledMethod_lock, Mutex::_no_safepoint_check_flag); + MutexLocker ml(NMethodState_lock, Mutex::_no_safepoint_check_flag); if (mh->code() != nullptr) { deopt_scope.mark(mh->code()); ++result; @@ -839,7 +839,7 @@ WB_ENTRY(jboolean, WB_IsMethodCompiled(JNIEnv* env, jobject o, jobject method, j CHECK_JNI_EXCEPTION_(env, JNI_FALSE); MutexLocker mu(Compile_lock); methodHandle mh(THREAD, Method::checked_resolve_jmethod_id(jmid)); - CompiledMethod* code = is_osr ? mh->lookup_osr_nmethod_for(InvocationEntryBci, CompLevel_none, false) : mh->code(); + nmethod* code = is_osr ? mh->lookup_osr_nmethod_for(InvocationEntryBci, CompLevel_none, false) : mh->code(); if (code == nullptr) { return JNI_FALSE; } @@ -938,7 +938,7 @@ WB_ENTRY(jint, WB_GetMethodCompilationLevel(JNIEnv* env, jobject o, jobject meth jmethodID jmid = reflected_method_to_jmid(thread, env, method); CHECK_JNI_EXCEPTION_(env, CompLevel_none); methodHandle mh(THREAD, Method::checked_resolve_jmethod_id(jmid)); - CompiledMethod* code = is_osr ? mh->lookup_osr_nmethod_for(InvocationEntryBci, CompLevel_none, false) : mh->code(); + nmethod* code = is_osr ? mh->lookup_osr_nmethod_for(InvocationEntryBci, CompLevel_none, false) : mh->code(); return (code != nullptr ? code->comp_level() : CompLevel_none); WB_END @@ -1023,7 +1023,7 @@ WB_ENTRY(jint, WB_GetMethodEntryBci(JNIEnv* env, jobject o, jobject method)) jmethodID jmid = reflected_method_to_jmid(thread, env, method); CHECK_JNI_EXCEPTION_(env, InvocationEntryBci); methodHandle mh(THREAD, Method::checked_resolve_jmethod_id(jmid)); - CompiledMethod* code = mh->lookup_osr_nmethod_for(InvocationEntryBci, CompLevel_none, false); + nmethod* code = mh->lookup_osr_nmethod_for(InvocationEntryBci, CompLevel_none, false); return (code != nullptr && code->is_osr_method() ? code->osr_entry_bci() : InvocationEntryBci); WB_END @@ -1097,8 +1097,8 @@ bool WhiteBox::compile_method(Method* method, int comp_level, int bci, JavaThrea } // Check code again because compilation may be finished before Compile_lock is acquired. if (bci == InvocationEntryBci) { - CompiledMethod* code = mh->code(); - if (code != nullptr && code->as_nmethod_or_null() != nullptr) { + nmethod* code = mh->code(); + if (code != nullptr) { return true; } } else if (mh->lookup_osr_nmethod_for(bci, comp_level, false) != nullptr) { @@ -1556,7 +1556,7 @@ WB_ENTRY(jobjectArray, WB_GetNMethod(JNIEnv* env, jobject o, jobject method, jbo jmethodID jmid = reflected_method_to_jmid(thread, env, method); CHECK_JNI_EXCEPTION_(env, nullptr); methodHandle mh(THREAD, Method::checked_resolve_jmethod_id(jmid)); - CompiledMethod* code = is_osr ? mh->lookup_osr_nmethod_for(InvocationEntryBci, CompLevel_none, false) : mh->code(); + nmethod* code = is_osr ? mh->lookup_osr_nmethod_for(InvocationEntryBci, CompLevel_none, false) : mh->code(); jobjectArray result = nullptr; if (code == nullptr) { return result; @@ -1608,7 +1608,7 @@ CodeBlob* WhiteBox::allocate_code_blob(int size, CodeBlobType blob_type) { MutexLocker mu(CodeCache_lock, Mutex::_no_safepoint_check_flag); blob = (BufferBlob*) CodeCache::allocate(full_size, blob_type); if (blob != nullptr) { - ::new (blob) BufferBlob("WB::DummyBlob", full_size); + ::new (blob) BufferBlob("WB::DummyBlob", CodeBlobKind::Buffer, full_size); } } // Track memory usage statistic after releasing CodeCache_lock diff --git a/src/hotspot/share/runtime/arguments.cpp b/src/hotspot/share/runtime/arguments.cpp index c8021de5ff0..b9939c6239a 100644 --- a/src/hotspot/share/runtime/arguments.cpp +++ b/src/hotspot/share/runtime/arguments.cpp @@ -537,6 +537,7 @@ static SpecialFlag const special_jvm_flags[] = { { "ParallelOldDeadWoodLimiterMean", JDK_Version::undefined(), JDK_Version::jdk(23), JDK_Version::jdk(24) }, { "ParallelOldDeadWoodLimiterStdDev", JDK_Version::undefined(), JDK_Version::jdk(23), JDK_Version::jdk(24) }, + { "UseNeon", JDK_Version::undefined(), JDK_Version::jdk(23), JDK_Version::jdk(24) }, #ifdef ASSERT { "DummyObsoleteTestFlag", JDK_Version::undefined(), JDK_Version::jdk(18), JDK_Version::undefined() }, #endif diff --git a/src/hotspot/share/runtime/basicLock.cpp b/src/hotspot/share/runtime/basicLock.cpp index b6cb4b075be..704bea85576 100644 --- a/src/hotspot/share/runtime/basicLock.cpp +++ b/src/hotspot/share/runtime/basicLock.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 @@ -40,10 +40,10 @@ void BasicLock::print_on(outputStream* st, oop owner) const { void BasicLock::move_to(oop obj, BasicLock* dest) { // Check to see if we need to inflate the lock. This is only needed // if an object is locked using "this" lightweight monitor. In that - // case, the displaced_header() is unlocked/is_neutral, because the + // case, the displaced_header() is unlocked/neutral, because the // displaced_header() contains the header for the originally unlocked // object. However the lock could have already been inflated. But it - // does not matter, this inflation will just a no-op. For other cases, + // does not matter, this inflation will just be a no-op. For other cases, // the displaced header will be either 0x0 or 0x3, which are location // independent, therefore the BasicLock is free to move. // @@ -63,7 +63,7 @@ void BasicLock::move_to(oop obj, BasicLock* dest) { // one stack location to another. This avoids inflation. Obviously, // we need to ensure that both locations refer to the current thread's stack. // There are some subtle concurrency issues, however, and since the benefit is - // is small (given the support for inflated fast-path locking in the fast_lock, etc) + // small (given the support for inflated fast-path locking in the fast_lock, etc) // we'll leave that optimization for another time. if (LockingMode == LM_LEGACY) { diff --git a/src/hotspot/share/runtime/basicLock.hpp b/src/hotspot/share/runtime/basicLock.hpp index 3338d466d1d..c348fa7f9a2 100644 --- a/src/hotspot/share/runtime/basicLock.hpp +++ b/src/hotspot/share/runtime/basicLock.hpp @@ -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 @@ -34,6 +34,8 @@ class BasicLock { friend class VMStructs; friend class JVMCIVMStructs; private: + // This is either the actual displaced header from a locked object, or + // a sentinel zero value indicating a recursive stack-lock. volatile markWord _displaced_header; public: markWord displaced_header() const { @@ -46,7 +48,7 @@ class BasicLock { void print_on(outputStream* st, oop owner) const; - // move a basic lock (used during deoptimization + // move a basic lock (used during deoptimization) void move_to(oop obj, BasicLock* dest); static int displaced_header_offset_in_bytes() { return (int)offset_of(BasicLock, _displaced_header); } diff --git a/src/hotspot/share/runtime/continuation.cpp b/src/hotspot/share/runtime/continuation.cpp index 03c0af1a572..cd55b4a9cff 100644 --- a/src/hotspot/share/runtime/continuation.cpp +++ b/src/hotspot/share/runtime/continuation.cpp @@ -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 @@ -105,10 +105,10 @@ bool Continuation::is_return_barrier_entry(const address pc) { } bool Continuation::is_continuation_enterSpecial(const frame& f) { - if (f.cb() == nullptr || !f.cb()->is_compiled()) { + if (f.cb() == nullptr || !f.cb()->is_nmethod()) { return false; } - Method* m = f.cb()->as_compiled_method()->method(); + Method* m = f.cb()->as_nmethod()->method(); return (m != nullptr && m->is_continuation_enter_intrinsic()); } diff --git a/src/hotspot/share/runtime/continuationEntry.cpp b/src/hotspot/share/runtime/continuationEntry.cpp index 42d4cb12486..31b062292f0 100644 --- a/src/hotspot/share/runtime/continuationEntry.cpp +++ b/src/hotspot/share/runtime/continuationEntry.cpp @@ -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 @@ -37,14 +37,14 @@ int ContinuationEntry::_return_pc_offset = 0; address ContinuationEntry::_return_pc = nullptr; -CompiledMethod* ContinuationEntry::_enter_special = nullptr; +nmethod* ContinuationEntry::_enter_special = nullptr; int ContinuationEntry::_interpreted_entry_offset = 0; -void ContinuationEntry::set_enter_code(CompiledMethod* cm, int interpreted_entry_offset) { +void ContinuationEntry::set_enter_code(nmethod* nm, int interpreted_entry_offset) { assert(_return_pc_offset != 0, ""); - _return_pc = cm->code_begin() + _return_pc_offset; + _return_pc = nm->code_begin() + _return_pc_offset; - _enter_special = cm; + _enter_special = nm; _interpreted_entry_offset = interpreted_entry_offset; assert(_enter_special->code_contains(compiled_entry()), "entry not in enterSpecial"); assert(_enter_special->code_contains(interpreted_entry()), "entry not in enterSpecial"); @@ -141,7 +141,7 @@ bool ContinuationEntry::assert_entry_frame_laid_out(JavaThread* thread) { if (pc != StubRoutines::cont_returnBarrier()) { CodeBlob* cb = pc != nullptr ? CodeCache::find_blob(pc) : nullptr; assert(cb != nullptr, "sp: " INTPTR_FORMAT " pc: " INTPTR_FORMAT, p2i(sp), p2i(pc)); - assert(cb->as_compiled_method()->method()->is_continuation_enter_intrinsic(), ""); + assert(cb->as_nmethod()->method()->is_continuation_enter_intrinsic(), ""); } return true; diff --git a/src/hotspot/share/runtime/continuationEntry.hpp b/src/hotspot/share/runtime/continuationEntry.hpp index d2d5a5ab366..5930b008d27 100644 --- a/src/hotspot/share/runtime/continuationEntry.hpp +++ b/src/hotspot/share/runtime/continuationEntry.hpp @@ -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 @@ -32,8 +32,8 @@ #include CPU_HEADER(continuationEntry) -class CompiledMethod; class JavaThread; +class nmethod; class OopMap; class RegisterMap; @@ -56,12 +56,12 @@ class ContinuationEntry { public: static int _return_pc_offset; // friend gen_continuation_enter - static void set_enter_code(CompiledMethod* cm, int interpreted_entry_offset); + static void set_enter_code(nmethod* nm, int interpreted_entry_offset); static bool is_interpreted_call(address call_address); private: static address _return_pc; - static CompiledMethod* _enter_special; + static nmethod* _enter_special; static int _interpreted_entry_offset; private: diff --git a/src/hotspot/share/runtime/continuationFreezeThaw.cpp b/src/hotspot/share/runtime/continuationFreezeThaw.cpp index ec6adf5cb67..d3375d1dfbb 100644 --- a/src/hotspot/share/runtime/continuationFreezeThaw.cpp +++ b/src/hotspot/share/runtime/continuationFreezeThaw.cpp @@ -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 @@ -26,7 +26,7 @@ #include "classfile/javaClasses.inline.hpp" #include "classfile/vmSymbols.hpp" #include "code/codeCache.inline.hpp" -#include "code/compiledMethod.inline.hpp" +#include "code/nmethod.inline.hpp" #include "code/vmreg.inline.hpp" #include "compiler/oopMap.inline.hpp" #include "gc/shared/continuationGCSupport.inline.hpp" @@ -1070,8 +1070,8 @@ void FreezeBase::patch(const frame& f, frame& hf, const frame& caller, bool is_b if (hf.is_compiled_frame()) { if (f.is_deoptimized_frame()) { // TODO DEOPT: long term solution: unroll on freeze and patch pc log_develop_trace(continuations)("Freezing deoptimized frame"); - assert(f.cb()->as_compiled_method()->is_deopt_pc(f.raw_pc()), ""); - assert(f.cb()->as_compiled_method()->is_deopt_pc(ContinuationHelper::Frame::real_pc(f)), ""); + assert(f.cb()->as_nmethod()->is_deopt_pc(f.raw_pc()), ""); + assert(f.cb()->as_nmethod()->is_deopt_pc(ContinuationHelper::Frame::real_pc(f)), ""); } } #endif @@ -1470,7 +1470,7 @@ void FreezeBase::throw_stack_overflow_on_humongous_chunk() { #if INCLUDE_JVMTI static int num_java_frames(ContinuationWrapper& cont) { - ResourceMark rm; // used for scope traversal in num_java_frames(CompiledMethod*, address) + ResourceMark rm; // used for scope traversal in num_java_frames(nmethod*, address) int count = 0; for (stackChunkOop chunk = cont.tail(); chunk != nullptr; chunk = chunk->parent()) { count += chunk->num_java_frames(); @@ -2290,7 +2290,7 @@ void ThawBase::recurse_thaw_compiled_frame(const frame& hf, frame& caller, int n if (hf.is_deoptimized_frame()) { maybe_set_fastpath(f.sp()); } else if (_thread->is_interp_only_mode() - || (_cont.is_preempted() && f.cb()->as_compiled_method()->is_marked_for_deoptimization())) { + || (_cont.is_preempted() && f.cb()->as_nmethod()->is_marked_for_deoptimization())) { // The caller of the safepoint stub when the continuation is preempted is not at a call instruction, and so // cannot rely on nmethod patching for deopt. assert(_thread->is_interp_only_mode() || stub_caller, "expected a stub-caller"); @@ -2309,7 +2309,7 @@ void ThawBase::recurse_thaw_compiled_frame(const frame& hf, frame& caller, int n _cont.tail()->fix_thawed_frame(caller, SmallRegisterMap::instance); } else if (_cont.tail()->has_bitmap() && added_argsize > 0) { address start = (address)(heap_frame_top + ContinuationHelper::CompiledFrame::size(hf) + frame::metadata_words_at_top); - int stack_args_slots = f.cb()->as_compiled_method()->method()->num_stack_arg_slots(false /* rounded */); + int stack_args_slots = f.cb()->as_nmethod()->method()->num_stack_arg_slots(false /* rounded */); int argsize_in_bytes = stack_args_slots * VMRegImpl::stack_slot_size; clear_bitmap_bits(start, start + argsize_in_bytes); } @@ -2404,7 +2404,7 @@ void ThawBase::finish_thaw(frame& f) { } void ThawBase::push_return_frame(frame& f) { // see generate_cont_thaw - assert(!f.is_compiled_frame() || f.is_deoptimized_frame() == f.cb()->as_compiled_method()->is_deopt_pc(f.raw_pc()), ""); + assert(!f.is_compiled_frame() || f.is_deoptimized_frame() == f.cb()->as_nmethod()->is_deopt_pc(f.raw_pc()), ""); assert(!f.is_compiled_frame() || f.is_deoptimized_frame() == (f.pc() != f.raw_pc()), ""); LogTarget(Trace, continuations) lt; @@ -2491,10 +2491,10 @@ static void do_deopt_after_thaw(JavaThread* thread) { fst.register_map()->set_include_argument_oops(false); ContinuationHelper::update_register_map_with_callee(*fst.current(), fst.register_map()); for (; !fst.is_done(); fst.next()) { - if (fst.current()->cb()->is_compiled()) { - CompiledMethod* cm = fst.current()->cb()->as_compiled_method(); - if (!cm->method()->is_continuation_native_intrinsic()) { - cm->make_deoptimized(); + if (fst.current()->cb()->is_nmethod()) { + nmethod* nm = fst.current()->cb()->as_nmethod(); + if (!nm->method()->is_continuation_native_intrinsic()) { + nm->make_deoptimized(); } } } @@ -2534,13 +2534,13 @@ static bool do_verify_after_thaw(JavaThread* thread, stackChunkOop chunk, output ResourceMark rm; ThawVerifyOopsClosure cl(st); - CodeBlobToOopClosure cf(&cl, false); + NMethodToOopClosure cf(&cl, false); StackFrameStream fst(thread, true, false); fst.register_map()->set_include_argument_oops(false); ContinuationHelper::update_register_map_with_callee(*fst.current(), fst.register_map()); for (; !fst.is_done() && !Continuation::is_continuation_enterSpecial(*fst.current()); fst.next()) { - if (fst.current()->cb()->is_compiled() && fst.current()->cb()->as_compiled_method()->is_marked_for_deoptimization()) { + if (fst.current()->cb()->is_nmethod() && fst.current()->cb()->as_nmethod()->is_marked_for_deoptimization()) { st->print_cr(">>> do_verify_after_thaw deopt"); fst.current()->deoptimize(nullptr); fst.current()->print_on(st); diff --git a/src/hotspot/share/runtime/continuationHelper.inline.hpp b/src/hotspot/share/runtime/continuationHelper.inline.hpp index 402703f1b19..d6b18a75815 100644 --- a/src/hotspot/share/runtime/continuationHelper.inline.hpp +++ b/src/hotspot/share/runtime/continuationHelper.inline.hpp @@ -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 @@ -57,7 +57,7 @@ inline bool ContinuationHelper::Frame::is_stub(CodeBlob* cb) { } inline Method* ContinuationHelper::Frame::frame_method(const frame& f) { - return f.is_interpreted_frame() ? f.interpreter_frame_method() : f.cb()->as_compiled_method()->method(); + return f.is_interpreted_frame() ? f.interpreter_frame_method() : f.cb()->as_nmethod()->method(); } inline address ContinuationHelper::Frame::return_pc(const frame& f) { @@ -79,8 +79,8 @@ inline intptr_t* ContinuationHelper::Frame::frame_top(const frame &f) { inline bool ContinuationHelper::Frame::is_deopt_return(address pc, const frame& sender) { if (sender.is_interpreted_frame()) return false; - CompiledMethod* cm = sender.cb()->as_compiled_method(); - return cm->is_deopt_pc(pc); + nmethod* nm = sender.cb()->as_nmethod(); + return nm->is_deopt_pc(pc); } #endif @@ -162,16 +162,16 @@ bool ContinuationHelper::CompiledFrame::is_owning_locks(JavaThread* thread, Regi assert(!f.is_interpreted_frame(), ""); assert(CompiledFrame::is_instance(f), ""); - CompiledMethod* cm = f.cb()->as_compiled_method(); - assert(!cm->is_compiled() || !cm->as_compiled_method()->is_native_method(), ""); // See compiledVFrame::compiledVFrame(...) in vframe_hp.cpp + nmethod* nm = f.cb()->as_nmethod(); + assert(!nm->is_native_method(), ""); // See compiledVFrame::compiledVFrame(...) in vframe_hp.cpp - if (!cm->has_monitors()) { + if (!nm->has_monitors()) { return false; } frame::update_map_with_saved_link(map, Frame::callee_link_address(f)); // the monitor object could be stored in the link register ResourceMark rm; - for (ScopeDesc* scope = cm->scope_desc_at(f.pc()); scope != nullptr; scope = scope->sender()) { + for (ScopeDesc* scope = nm->scope_desc_at(f.pc()); scope != nullptr; scope = scope->sender()) { GrowableArray* mons = scope->monitors(); if (mons == nullptr || mons->is_empty()) { continue; @@ -186,7 +186,7 @@ bool ContinuationHelper::CompiledFrame::is_owning_locks(JavaThread* thread, Regi StackValue* owner_sv = StackValue::create_stack_value(&f, map, ov); // it is an oop oop owner = owner_sv->get_obj()(); if (owner != nullptr) { - //assert(cm->has_monitors(), ""); + //assert(nm->has_monitors(), ""); return true; } } diff --git a/src/hotspot/share/runtime/deoptimization.cpp b/src/hotspot/share/runtime/deoptimization.cpp index e8f443ed1e0..1bdc597e4ce 100644 --- a/src/hotspot/share/runtime/deoptimization.cpp +++ b/src/hotspot/share/runtime/deoptimization.cpp @@ -108,7 +108,7 @@ bool DeoptimizationScope::_committing_in_progress = false; DeoptimizationScope::DeoptimizationScope() : _required_gen(0) { DEBUG_ONLY(_deopted = false;) - MutexLocker ml(CompiledMethod_lock, Mutex::_no_safepoint_check_flag); + MutexLocker ml(NMethodState_lock, Mutex::_no_safepoint_check_flag); // If there is nothing to deopt _required_gen is the same as comitted. _required_gen = DeoptimizationScope::_committed_deopt_gen; } @@ -117,34 +117,34 @@ DeoptimizationScope::~DeoptimizationScope() { assert(_deopted, "Deopt not executed"); } -void DeoptimizationScope::mark(CompiledMethod* cm, bool inc_recompile_counts) { - ConditionalMutexLocker ml(CompiledMethod_lock, !CompiledMethod_lock->owned_by_self(), Mutex::_no_safepoint_check_flag); +void DeoptimizationScope::mark(nmethod* nm, bool inc_recompile_counts) { + ConditionalMutexLocker ml(NMethodState_lock, !NMethodState_lock->owned_by_self(), Mutex::_no_safepoint_check_flag); // If it's already marked but we still need it to be deopted. - if (cm->is_marked_for_deoptimization()) { - dependent(cm); + if (nm->is_marked_for_deoptimization()) { + dependent(nm); return; } - CompiledMethod::DeoptimizationStatus status = - inc_recompile_counts ? CompiledMethod::deoptimize : CompiledMethod::deoptimize_noupdate; - Atomic::store(&cm->_deoptimization_status, status); + nmethod::DeoptimizationStatus status = + inc_recompile_counts ? nmethod::deoptimize : nmethod::deoptimize_noupdate; + Atomic::store(&nm->_deoptimization_status, status); // Make sure active is not committed assert(DeoptimizationScope::_committed_deopt_gen < DeoptimizationScope::_active_deopt_gen, "Must be"); - assert(cm->_deoptimization_generation == 0, "Is already marked"); + assert(nm->_deoptimization_generation == 0, "Is already marked"); - cm->_deoptimization_generation = DeoptimizationScope::_active_deopt_gen; + nm->_deoptimization_generation = DeoptimizationScope::_active_deopt_gen; _required_gen = DeoptimizationScope::_active_deopt_gen; } -void DeoptimizationScope::dependent(CompiledMethod* cm) { - ConditionalMutexLocker ml(CompiledMethod_lock, !CompiledMethod_lock->owned_by_self(), Mutex::_no_safepoint_check_flag); +void DeoptimizationScope::dependent(nmethod* nm) { + ConditionalMutexLocker ml(NMethodState_lock, !NMethodState_lock->owned_by_self(), Mutex::_no_safepoint_check_flag); // A method marked by someone else may have a _required_gen lower than what we marked with. // Therefore only store it if it's higher than _required_gen. - if (_required_gen < cm->_deoptimization_generation) { - _required_gen = cm->_deoptimization_generation; + if (_required_gen < nm->_deoptimization_generation) { + _required_gen = nm->_deoptimization_generation; } } @@ -170,7 +170,7 @@ void DeoptimizationScope::deoptimize_marked() { bool wait = false; while (true) { { - ConditionalMutexLocker ml(CompiledMethod_lock, !CompiledMethod_lock->owned_by_self(), Mutex::_no_safepoint_check_flag); + ConditionalMutexLocker ml(NMethodState_lock, !NMethodState_lock->owned_by_self(), Mutex::_no_safepoint_check_flag); // First we check if we or someone else already deopted the gen we want. if (DeoptimizationScope::_committed_deopt_gen >= _required_gen) { @@ -198,7 +198,7 @@ void DeoptimizationScope::deoptimize_marked() { Deoptimization::deoptimize_all_marked(); // May safepoint and an additional deopt may have occurred. DEBUG_ONLY(_deopted = true;) { - ConditionalMutexLocker ml(CompiledMethod_lock, !CompiledMethod_lock->owned_by_self(), Mutex::_no_safepoint_check_flag); + ConditionalMutexLocker ml(NMethodState_lock, !NMethodState_lock->owned_by_self(), Mutex::_no_safepoint_check_flag); // Make sure that committed doesn't go backwards. // Should only happen if we did a deopt during a safepoint above. @@ -301,27 +301,27 @@ static void print_objects(JavaThread* deoptee_thread, for (int i = 0; i < objects->length(); i++) { ObjectValue* sv = (ObjectValue*) objects->at(i); - Klass* k = java_lang_Class::as_Klass(sv->klass()->as_ConstantOopReadValue()->value()()); Handle obj = sv->value(); - st.print(" object <" INTPTR_FORMAT "> of type ", p2i(sv->value()())); - k->print_value_on(&st); - assert(obj.not_null() || realloc_failures, "reallocation was missed"); if (obj.is_null()) { - st.print(" allocation failed"); - } else { - st.print(" allocated (" SIZE_FORMAT " bytes)", obj->size() * HeapWordSize); + st.print_cr(" nullptr"); + continue; } - st.cr(); - if (Verbose && !obj.is_null()) { + Klass* k = java_lang_Class::as_Klass(sv->klass()->as_ConstantOopReadValue()->value()()); + + st.print(" object <" INTPTR_FORMAT "> of type ", p2i(sv->value()())); + k->print_value_on(&st); + st.print_cr(" allocated (" SIZE_FORMAT " bytes)", obj->size() * HeapWordSize); + + if (Verbose && k != nullptr) { k->oop_print_on(obj(), &st); } } tty->print_raw(st.freeze()); } -static bool rematerialize_objects(JavaThread* thread, int exec_mode, CompiledMethod* compiled_method, +static bool rematerialize_objects(JavaThread* thread, int exec_mode, nmethod* compiled_method, frame& deoptee, RegisterMap& map, GrowableArray* chunk, bool& deoptimized_objects) { bool realloc_failures = false; @@ -439,7 +439,7 @@ bool Deoptimization::deoptimize_objects_internal(JavaThread* thread, GrowableArr bool& realloc_failures) { frame deoptee = chunk->at(0)->fr(); JavaThread* deoptee_thread = chunk->at(0)->thread(); - CompiledMethod* cm = deoptee.cb()->as_compiled_method_or_null(); + nmethod* nm = deoptee.cb()->as_nmethod_or_null(); RegisterMap map(chunk->at(0)->register_map()); bool deoptimized_objects = false; @@ -448,7 +448,7 @@ bool Deoptimization::deoptimize_objects_internal(JavaThread* thread, GrowableArr // Reallocate the non-escaping objects and restore their fields. if (jvmci_enabled COMPILER2_PRESENT(|| (DoEscapeAnalysis && EliminateAllocations) || EliminateAutoBox || EnableVectorAggressiveReboxing)) { - realloc_failures = rematerialize_objects(thread, Unpack_none, cm, deoptee, map, chunk, deoptimized_objects); + realloc_failures = rematerialize_objects(thread, Unpack_none, nm, deoptee, map, chunk, deoptimized_objects); } // MonitorInfo structures used in eliminate_locks are not GC safe. @@ -492,8 +492,8 @@ Deoptimization::UnrollBlock* Deoptimization::fetch_unroll_info_helper(JavaThread frame deoptee = stub_frame.sender(&map); // Set the deoptee nmethod assert(current->deopt_compiled_method() == nullptr, "Pending deopt!"); - CompiledMethod* cm = deoptee.cb()->as_compiled_method_or_null(); - current->set_deopt_compiled_method(cm); + nmethod* nm = deoptee.cb()->as_nmethod_or_null(); + current->set_deopt_compiled_method(nm); if (VerifyStack) { current->validate_frame_layout(); @@ -522,7 +522,7 @@ Deoptimization::UnrollBlock* Deoptimization::fetch_unroll_info_helper(JavaThread if (jvmci_enabled COMPILER2_PRESENT( || (DoEscapeAnalysis && EliminateAllocations) || EliminateAutoBox || EnableVectorAggressiveReboxing )) { bool unused; - realloc_failures = rematerialize_objects(current, exec_mode, cm, deoptee, map, chunk, unused); + realloc_failures = rematerialize_objects(current, exec_mode, nm, deoptee, map, chunk, unused); } #endif // COMPILER2_OR_JVMCI @@ -1220,8 +1220,8 @@ bool Deoptimization::realloc_objects(JavaThread* thread, frame* fr, RegisterMap* bool cache_init_error = false; if (k->is_instance_klass()) { #if INCLUDE_JVMCI - CompiledMethod* cm = fr->cb()->as_compiled_method_or_null(); - if (cm->is_compiled_by_jvmci() && sv->is_auto_box()) { + nmethod* nm = fr->cb()->as_nmethod_or_null(); + if (nm->is_compiled_by_jvmci() && sv->is_auto_box()) { AutoBoxObjectValue* abv = (AutoBoxObjectValue*) sv; obj = get_cached_box(abv, fr, reg_map, cache_init_error, THREAD); if (obj != nullptr) { @@ -1747,14 +1747,14 @@ void Deoptimization::deoptimize_single_frame(JavaThread* thread, frame fr, Deopt gather_statistics(reason, Action_none, Bytecodes::_illegal); if (LogCompilation && xtty != nullptr) { - CompiledMethod* cm = fr.cb()->as_compiled_method_or_null(); - assert(cm != nullptr, "only compiled methods can deopt"); + nmethod* nm = fr.cb()->as_nmethod_or_null(); + assert(nm != nullptr, "only compiled methods can deopt"); ttyLocker ttyl; xtty->begin_head("deoptimized thread='" UINTX_FORMAT "' reason='%s' pc='" INTPTR_FORMAT "'",(uintx)thread->osthread()->thread_id(), trap_reason_name(reason), p2i(fr.pc())); - cm->log_identity(xtty); + nm->log_identity(xtty); xtty->end_head(); - for (ScopeDesc* sd = cm->scope_desc_at(fr.pc()); ; sd = sd->sender()) { + for (ScopeDesc* sd = nm->scope_desc_at(fr.pc()); ; sd = sd->sender()) { xtty->begin_elem("jvms bci='%d'", sd->bci()); xtty->method(sd->method()); xtty->end_elem(); @@ -1782,9 +1782,9 @@ void Deoptimization::deoptimize(JavaThread* thread, frame fr, DeoptReason reason } #if INCLUDE_JVMCI -address Deoptimization::deoptimize_for_missing_exception_handler(CompiledMethod* cm) { +address Deoptimization::deoptimize_for_missing_exception_handler(nmethod* nm) { // there is no exception handler for this pc => deoptimize - cm->make_not_entrant(); + nm->make_not_entrant(); // Use Deoptimization::deoptimize for all of its side-effects: // gathering traps statistics, logging... @@ -1797,7 +1797,7 @@ address Deoptimization::deoptimize_for_missing_exception_handler(CompiledMethod* RegisterMap::WalkContinuation::skip); frame runtime_frame = thread->last_frame(); frame caller_frame = runtime_frame.sender(®_map); - assert(caller_frame.cb()->as_compiled_method_or_null() == cm, "expect top frame compiled method"); + assert(caller_frame.cb()->as_nmethod_or_null() == nm, "expect top frame compiled method"); vframe* vf = vframe::new_vframe(&caller_frame, ®_map, thread); compiledVFrame* cvf = compiledVFrame::cast(vf); ScopeDesc* imm_scope = cvf->scope(); @@ -1815,7 +1815,7 @@ address Deoptimization::deoptimize_for_missing_exception_handler(CompiledMethod* Deoptimization::deoptimize(thread, caller_frame, Deoptimization::Reason_not_compiled_exception_handler); - MethodData* trap_mdo = get_method_data(thread, methodHandle(thread, cm->method()), true); + MethodData* trap_mdo = get_method_data(thread, methodHandle(thread, nm->method()), true); if (trap_mdo != nullptr) { trap_mdo->inc_trap_count(Deoptimization::Reason_not_compiled_exception_handler); } @@ -1950,7 +1950,7 @@ static void register_serializers() { JfrSerializer::register_serializer(TYPE_DEOPTIMIZATIONACTION, true, new DeoptActionSerializer()); } -static void post_deoptimization_event(CompiledMethod* nm, +static void post_deoptimization_event(nmethod* nm, const Method* method, int trap_bci, int instruction, @@ -1979,7 +1979,7 @@ static void post_deoptimization_event(CompiledMethod* nm, #endif // INCLUDE_JFR -static void log_deopt(CompiledMethod* nm, Method* tm, intptr_t pc, frame& fr, int trap_bci, +static void log_deopt(nmethod* nm, Method* tm, intptr_t pc, frame& fr, int trap_bci, const char* reason_name, const char* reason_action) { LogTarget(Debug, deoptimization) lt; if (lt.is_enabled()) { @@ -2041,7 +2041,7 @@ JRT_ENTRY(void, Deoptimization::uncommon_trap_inner(JavaThread* current, jint tr vframe* vf = vframe::new_vframe(&fr, ®_map, current); compiledVFrame* cvf = compiledVFrame::cast(vf); - CompiledMethod* nm = cvf->code(); + nmethod* nm = cvf->code(); ScopeDesc* trap_scope = cvf->scope(); @@ -2058,7 +2058,7 @@ JRT_ENTRY(void, Deoptimization::uncommon_trap_inner(JavaThread* current, jint tr #if INCLUDE_JVMCI jlong speculation = current->pending_failed_speculation(); if (nm->is_compiled_by_jvmci()) { - nm->as_nmethod()->update_speculation(current); + nm->update_speculation(current); } else { assert(speculation == 0, "There should not be a speculation for methods compiled by non-JVMCI compilers"); } @@ -2178,8 +2178,8 @@ JRT_ENTRY(void, Deoptimization::uncommon_trap_inner(JavaThread* current, jint tr trap_scope->bci(), p2i(fr.pc()), fr.pc() - nm->code_begin() JVMCI_ONLY(COMMA debug_id)); st.print(" compiler=%s compile_id=%d", nm->compiler_name(), nm->compile_id()); #if INCLUDE_JVMCI - if (nm->is_nmethod()) { - const char* installed_code_name = nm->as_nmethod()->jvmci_name(); + if (nm->is_compiled_by_jvmci()) { + const char* installed_code_name = nm->jvmci_name(); if (installed_code_name != nullptr) { st.print(" (JVMCI: installed code name=%s) ", installed_code_name); } @@ -2433,7 +2433,7 @@ JRT_ENTRY(void, Deoptimization::uncommon_trap_inner(JavaThread* current, jint tr // Assume that in new recompiled code the statistic could be different, // for example, due to different inlining. if ((reason != Reason_rtm_state_change) && (trap_mdo != nullptr) && - UseRTMDeopt && (nm->as_nmethod()->rtm_state() != ProfileRTM)) { + UseRTMDeopt && (nm->rtm_state() != ProfileRTM)) { trap_mdo->atomic_set_rtm_state(ProfileRTM); } #endif diff --git a/src/hotspot/share/runtime/deoptimization.hpp b/src/hotspot/share/runtime/deoptimization.hpp index e74047811c2..61e85d19fd7 100644 --- a/src/hotspot/share/runtime/deoptimization.hpp +++ b/src/hotspot/share/runtime/deoptimization.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 @@ -57,9 +57,9 @@ class DeoptimizationScope { DeoptimizationScope(); ~DeoptimizationScope(); // Mark a method, if already marked as dependent. - void mark(CompiledMethod* cm, bool inc_recompile_counts = true); + void mark(nmethod* nm, bool inc_recompile_counts = true); // Record this as a dependent method. - void dependent(CompiledMethod* cm); + void dependent(nmethod* nm); // Execute the deoptimization. // Make the nmethods not entrant, stackwalks and patch return pcs and sets post call nops. @@ -184,7 +184,7 @@ class Deoptimization : AllStatic { static void deoptimize(JavaThread* thread, frame fr, DeoptReason reason = Reason_constraint); #if INCLUDE_JVMCI - static address deoptimize_for_missing_exception_handler(CompiledMethod* cm); + static address deoptimize_for_missing_exception_handler(nmethod* nm); static oop get_cached_box(AutoBoxObjectValue* bv, frame* fr, RegisterMap* reg_map, bool& cache_init_error, TRAPS); #endif diff --git a/src/hotspot/share/runtime/frame.cpp b/src/hotspot/share/runtime/frame.cpp index 33abbd61694..b45c996e1f3 100644 --- a/src/hotspot/share/runtime/frame.cpp +++ b/src/hotspot/share/runtime/frame.cpp @@ -205,11 +205,12 @@ void RegisterMap::print() const { address frame::raw_pc() const { if (is_deoptimized_frame()) { - CompiledMethod* cm = cb()->as_compiled_method_or_null(); - if (cm->is_method_handle_return(pc())) - return cm->deopt_mh_handler_begin() - pc_return_offset; + nmethod* nm = cb()->as_nmethod_or_null(); + assert(nm != nullptr, "only nmethod is expected here"); + if (nm->is_method_handle_return(pc())) + return nm->deopt_mh_handler_begin() - pc_return_offset; else - return cm->deopt_handler_begin() - pc_return_offset; + return nm->deopt_handler_begin() - pc_return_offset; } else { return (pc() - pc_return_offset); } @@ -313,8 +314,8 @@ Method* frame::safe_interpreter_frame_method() const { bool frame::should_be_deoptimized() const { if (_deopt_state == is_deoptimized || !is_compiled_frame() ) return false; - assert(_cb != nullptr && _cb->is_compiled(), "must be an nmethod"); - CompiledMethod* nm = (CompiledMethod *)_cb; + assert(_cb != nullptr && _cb->is_nmethod(), "must be an nmethod"); + nmethod* nm = _cb->as_nmethod(); LogTarget(Debug, dependencies) lt; if (lt.is_enabled()) { LogStream ls(<); @@ -333,7 +334,7 @@ bool frame::should_be_deoptimized() const { bool frame::can_be_deoptimized() const { if (!is_compiled_frame()) return false; - CompiledMethod* nm = (CompiledMethod*)_cb; + nmethod* nm = _cb->as_nmethod(); if(!nm->can_be_deoptimized()) return false; @@ -346,18 +347,18 @@ void frame::deoptimize(JavaThread* thread) { || (thread->frame_anchor()->has_last_Java_frame() && thread->frame_anchor()->walkable()), "must be"); // Schedule deoptimization of an nmethod activation with this frame. - assert(_cb != nullptr && _cb->is_compiled(), "must be"); + assert(_cb != nullptr && _cb->is_nmethod(), "must be"); // If the call site is a MethodHandle call site use the MH deopt handler. - CompiledMethod* cm = (CompiledMethod*) _cb; - address deopt = cm->is_method_handle_return(pc()) ? - cm->deopt_mh_handler_begin() : - cm->deopt_handler_begin(); + nmethod* nm = _cb->as_nmethod(); + address deopt = nm->is_method_handle_return(pc()) ? + nm->deopt_mh_handler_begin() : + nm->deopt_handler_begin(); NativePostCallNop* inst = nativePostCallNop_at(pc()); // Save the original pc before we patch in the new one - cm->set_original_pc(this, pc()); + nm->set_original_pc(this, pc()); patch_pc(thread, deopt); assert(is_deoptimized_frame(), "must be"); @@ -674,15 +675,12 @@ void frame::print_on_error(outputStream* st, char* buf, int buflen, bool verbose } } else if (_cb->is_buffer_blob()) { st->print("v ~BufferBlob::%s " PTR_FORMAT, ((BufferBlob *)_cb)->name(), p2i(pc())); - } else if (_cb->is_compiled()) { - CompiledMethod* cm = (CompiledMethod*)_cb; - Method* m = cm->method(); + } else if (_cb->is_nmethod()) { + nmethod* nm = _cb->as_nmethod(); + Method* m = nm->method(); if (m != nullptr) { - if (cm->is_nmethod()) { - nmethod* nm = cm->as_nmethod(); - st->print("J %d%s", nm->compile_id(), (nm->is_osr_method() ? "%" : "")); - st->print(" %s", nm->compiler_name()); - } + st->print("J %d%s", nm->compile_id(), (nm->is_osr_method() ? "%" : "")); + st->print(" %s", nm->compiler_name()); m->name_and_sig_as_C_string(buf, buflen); st->print(" %s", buf); ModuleEntry* module = m->method_holder()->module(); @@ -697,12 +695,9 @@ void frame::print_on_error(outputStream* st, char* buf, int buflen, bool verbose st->print(" (%d bytes) @ " PTR_FORMAT " [" PTR_FORMAT "+" INTPTR_FORMAT "]", m->code_size(), p2i(_pc), p2i(_cb->code_begin()), _pc - _cb->code_begin()); #if INCLUDE_JVMCI - if (cm->is_nmethod()) { - nmethod* nm = cm->as_nmethod(); - const char* jvmciName = nm->jvmci_name(); - if (jvmciName != nullptr) { - st->print(" (%s)", jvmciName); - } + const char* jvmciName = nm->jvmci_name(); + if (jvmciName != nullptr) { + st->print(" (%s)", jvmciName); } #endif } else { @@ -967,7 +962,7 @@ void frame::oops_interpreted_arguments_do(Symbol* signature, bool has_receiver, finder.oops_do(); } -void frame::oops_code_blob_do(OopClosure* f, CodeBlobClosure* cf, DerivedOopClosure* df, DerivedPointerIterationMode derived_mode, const RegisterMap* reg_map) const { +void frame::oops_nmethod_do(OopClosure* f, NMethodClosure* cf, DerivedOopClosure* df, DerivedPointerIterationMode derived_mode, const RegisterMap* reg_map) const { assert(_cb != nullptr, "sanity check"); assert((oop_map() == nullptr) == (_cb->oop_maps() == nullptr), "frame and _cb must agree that oopmap is set or not"); if (oop_map() != nullptr) { @@ -988,8 +983,8 @@ void frame::oops_code_blob_do(OopClosure* f, CodeBlobClosure* cf, DerivedOopClos // prevent them from being collected. However, this visit should be // restricted to certain phases of the collection only. The // closure decides how it wants nmethods to be traced. - if (cf != nullptr) - cf->do_code_blob(_cb); + if (cf != nullptr && _cb->is_nmethod()) + cf->do_nmethod(_cb->as_nmethod()); } class CompiledArgumentOopFinder: public SignatureIterator { @@ -1136,7 +1131,7 @@ bool frame::is_deoptimized_frame() const { return false; } -void frame::oops_do_internal(OopClosure* f, CodeBlobClosure* cf, +void frame::oops_do_internal(OopClosure* f, NMethodClosure* cf, DerivedOopClosure* df, DerivedPointerIterationMode derived_mode, const RegisterMap* map, bool use_interpreter_oop_map_cache) const { #ifndef PRODUCT @@ -1153,15 +1148,15 @@ void frame::oops_do_internal(OopClosure* f, CodeBlobClosure* cf, } else if (is_upcall_stub_frame()) { _cb->as_upcall_stub()->oops_do(f, *this); } else if (CodeCache::contains(pc())) { - oops_code_blob_do(f, cf, df, derived_mode, map); + oops_nmethod_do(f, cf, df, derived_mode, map); } else { ShouldNotReachHere(); } } -void frame::nmethods_do(CodeBlobClosure* cf) const { +void frame::nmethod_do(NMethodClosure* cf) const { if (_cb != nullptr && _cb->is_nmethod()) { - cf->do_code_blob(_cb); + cf->do_nmethod(_cb->as_nmethod()); } } @@ -1403,22 +1398,22 @@ void frame::describe(FrameValues& values, int frame_no, const RegisterMap* reg_m } else if (is_entry_frame()) { // For now just label the frame values.describe(-1, info_address, err_msg("#%d entry frame", frame_no), 2); - } else if (cb()->is_compiled()) { + } else if (cb()->is_nmethod()) { // For now just label the frame - CompiledMethod* cm = cb()->as_compiled_method(); + nmethod* nm = cb()->as_nmethod(); values.describe(-1, info_address, FormatBuffer<1024>("#%d nmethod " INTPTR_FORMAT " for method J %s%s", frame_no, - p2i(cm), - cm->method()->name_and_sig_as_C_string(), + p2i(nm), + nm->method()->name_and_sig_as_C_string(), (_deopt_state == is_deoptimized) ? " (deoptimized)" : ((_deopt_state == unknown) ? " (state unknown)" : "")), 3); { // mark arguments (see nmethod::print_nmethod_labels) - Method* m = cm->method(); + Method* m = nm->method(); - int stack_slot_offset = cm->frame_size() * wordSize; // offset, in bytes, to caller sp + int stack_slot_offset = nm->frame_size() * wordSize; // offset, in bytes, to caller sp int sizeargs = m->size_of_parameters(); BasicType* sig_bt = NEW_RESOURCE_ARRAY(BasicType, sizeargs); @@ -1469,7 +1464,7 @@ void frame::describe(FrameValues& values, int frame_no, const RegisterMap* reg_m if (reg_map != nullptr && is_java_frame()) { int scope_no = 0; - for (ScopeDesc* scope = cm->scope_desc_at(pc()); scope != nullptr; scope = scope->sender(), scope_no++) { + for (ScopeDesc* scope = nm->scope_desc_at(pc()); scope != nullptr; scope = scope->sender(), scope_no++) { Method* m = scope->method(); int bci = scope->bci(); values.describe(-1, info_address, err_msg("- #%d scope %s @ %d", scope_no, m->name_and_sig_as_C_string(), bci), 2); @@ -1507,7 +1502,7 @@ void frame::describe(FrameValues& values, int frame_no, const RegisterMap* reg_m } } - if (cm->method()->is_continuation_enter_intrinsic()) { + if (nm->method()->is_continuation_enter_intrinsic()) { ContinuationEntry* ce = Continuation::get_continuation_entry_for_entry_frame(reg_map->thread(), *this); // (ContinuationEntry*)unextended_sp(); ce->describe(values, frame_no); } diff --git a/src/hotspot/share/runtime/frame.hpp b/src/hotspot/share/runtime/frame.hpp index 4d5777059e0..4113360724d 100644 --- a/src/hotspot/share/runtime/frame.hpp +++ b/src/hotspot/share/runtime/frame.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 @@ -40,7 +40,6 @@ typedef class BytecodeInterpreter* interpreterState; class CodeBlob; -class CompiledMethod; class FrameValues; class InterpreterOopMap; class JavaCallWrapper; @@ -122,6 +121,11 @@ class frame { // is deoptimization. It likely no one else should ever use it. address raw_pc() const; + // Return the original PC for the given PC if: + // (a) the given PC belongs to an nmethod and + // (b) it is a deopt PC + address get_deopt_original_pc() const; + void set_pc(address newpc); intptr_t* sp() const { assert_absolute(); return _sp; } @@ -451,17 +455,17 @@ class frame { void oops_interpreted_arguments_do(Symbol* signature, bool has_receiver, OopClosure* f) const; // Iteration of oops - void oops_do_internal(OopClosure* f, CodeBlobClosure* cf, + void oops_do_internal(OopClosure* f, NMethodClosure* cf, DerivedOopClosure* df, DerivedPointerIterationMode derived_mode, const RegisterMap* map, bool use_interpreter_oop_map_cache) const; void oops_entry_do(OopClosure* f, const RegisterMap* map) const; - void oops_code_blob_do(OopClosure* f, CodeBlobClosure* cf, - DerivedOopClosure* df, DerivedPointerIterationMode derived_mode, - const RegisterMap* map) const; + void oops_nmethod_do(OopClosure* f, NMethodClosure* cf, + DerivedOopClosure* df, DerivedPointerIterationMode derived_mode, + const RegisterMap* map) const; public: // Memory management - void oops_do(OopClosure* f, CodeBlobClosure* cf, const RegisterMap* map) { + void oops_do(OopClosure* f, NMethodClosure* cf, const RegisterMap* map) { #if COMPILER2_OR_JVMCI DerivedPointerIterationMode dpim = DerivedPointerTable::is_active() ? DerivedPointerIterationMode::_with_table : @@ -472,16 +476,16 @@ class frame { oops_do_internal(f, cf, nullptr, dpim, map, true); } - void oops_do(OopClosure* f, CodeBlobClosure* cf, DerivedOopClosure* df, const RegisterMap* map) { + void oops_do(OopClosure* f, NMethodClosure* cf, DerivedOopClosure* df, const RegisterMap* map) { oops_do_internal(f, cf, df, DerivedPointerIterationMode::_ignore, map, true); } - void oops_do(OopClosure* f, CodeBlobClosure* cf, const RegisterMap* map, + void oops_do(OopClosure* f, NMethodClosure* cf, const RegisterMap* map, DerivedPointerIterationMode derived_mode) const { oops_do_internal(f, cf, nullptr, derived_mode, map, true); } - void nmethods_do(CodeBlobClosure* cf) const; + void nmethod_do(NMethodClosure* cf) const; // RedefineClasses support for finding live interpreted methods on the stack void metadata_do(MetadataClosure* f) const; diff --git a/src/hotspot/share/runtime/frame.inline.hpp b/src/hotspot/share/runtime/frame.inline.hpp index da774fe1620..aa2de69a739 100644 --- a/src/hotspot/share/runtime/frame.inline.hpp +++ b/src/hotspot/share/runtime/frame.inline.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 @@ -28,7 +28,7 @@ #include "runtime/frame.hpp" #include "code/codeBlob.inline.hpp" -#include "code/compiledMethod.inline.hpp" +#include "code/nmethod.inline.hpp" #include "interpreter/interpreter.hpp" #include "oops/stackChunkOop.inline.hpp" #include "oops/method.hpp" @@ -64,13 +64,23 @@ inline bool frame::is_upcall_stub_frame() const { inline bool frame::is_compiled_frame() const { if (_cb != nullptr && - _cb->is_compiled() && - ((CompiledMethod*)_cb)->is_java_method()) { + _cb->is_nmethod() && + _cb->as_nmethod()->is_java_method()) { return true; } return false; } +inline address frame::get_deopt_original_pc() const { + if (_cb == nullptr) return nullptr; + + nmethod* nm = _cb->as_nmethod_or_null(); + if (nm != nullptr && nm->is_deopt_pc(_pc)) { + return nm->get_original_pc(this); + } + return nullptr; +} + template inline address frame::oopmapreg_to_location(VMReg reg, const RegisterMapT* reg_map) const { if (reg->is_reg()) { diff --git a/src/hotspot/share/runtime/javaThread.cpp b/src/hotspot/share/runtime/javaThread.cpp index 723aadedc29..8fe8e368f09 100644 --- a/src/hotspot/share/runtime/javaThread.cpp +++ b/src/hotspot/share/runtime/javaThread.cpp @@ -1290,8 +1290,8 @@ void JavaThread::deoptimize() { // Deoptimize only at particular bcis. DeoptimizeOnlyAt // consists of comma or carriage return separated numbers so // search for the current bci in that string. - address pc = fst.current()->pc(); - nmethod* nm = (nmethod*) fst.current()->cb(); + address pc = fst.current()->pc(); + nmethod* nm = fst.current()->cb()->as_nmethod(); ScopeDesc* sd = nm->scope_desc_at(pc); char buffer[8]; jio_snprintf(buffer, sizeof(buffer), "%d", sd->bci()); @@ -1333,6 +1333,7 @@ void JavaThread::make_zombies() { if (fst.current()->can_be_deoptimized()) { // it is a Java nmethod nmethod* nm = CodeCache::find_nmethod(fst.current()->pc()); + assert(nm != nullptr, "did not find nmethod"); nm->make_not_entrant(); } } @@ -1381,7 +1382,7 @@ void JavaThread::pop_jni_handle_block() { JNIHandleBlock::release_block(old_handles, this); } -void JavaThread::oops_do_no_frames(OopClosure* f, CodeBlobClosure* cf) { +void JavaThread::oops_do_no_frames(OopClosure* f, NMethodClosure* cf) { // Verify that the deferred card marks have been flushed. assert(deferred_card_mark().is_empty(), "Should be empty during GC"); @@ -1439,7 +1440,7 @@ void JavaThread::oops_do_no_frames(OopClosure* f, CodeBlobClosure* cf) { } } -void JavaThread::oops_do_frames(OopClosure* f, CodeBlobClosure* cf) { +void JavaThread::oops_do_frames(OopClosure* f, NMethodClosure* cf) { if (!has_last_Java_frame()) { return; } @@ -1458,14 +1459,14 @@ void JavaThread::verify_states_for_handshake() { } #endif -void JavaThread::nmethods_do(CodeBlobClosure* cf) { +void JavaThread::nmethods_do(NMethodClosure* cf) { DEBUG_ONLY(verify_frame_info();) MACOS_AARCH64_ONLY(ThreadWXEnable wx(WXWrite, Thread::current());) if (has_last_Java_frame()) { // Traverse the execution stack for (StackFrameStream fst(this, true /* update */, true /* process_frames */); !fst.is_done(); fst.next()) { - fst.current()->nmethods_do(cf); + fst.current()->nmethod_do(cf); } } diff --git a/src/hotspot/share/runtime/javaThread.hpp b/src/hotspot/share/runtime/javaThread.hpp index b16a879189e..80d52eda390 100644 --- a/src/hotspot/share/runtime/javaThread.hpp +++ b/src/hotspot/share/runtime/javaThread.hpp @@ -120,7 +120,7 @@ class JavaThread: public Thread { // Deopt support DeoptResourceMark* _deopt_mark; // Holds special ResourceMark for deoptimization - CompiledMethod* _deopt_nmethod; // CompiledMethod that is currently being deoptimized + nmethod* _deopt_nmethod; // nmethod that is currently being deoptimized vframeArray* _vframe_array_head; // Holds the heap of the active vframeArrays vframeArray* _vframe_array_last; // Holds last vFrameArray we popped // Holds updates by JVMTI agents for compiled frames that cannot be performed immediately. They @@ -686,8 +686,8 @@ class JavaThread: public Thread { void set_deopt_mark(DeoptResourceMark* value) { _deopt_mark = value; } DeoptResourceMark* deopt_mark(void) { return _deopt_mark; } - void set_deopt_compiled_method(CompiledMethod* nm) { _deopt_nmethod = nm; } - CompiledMethod* deopt_compiled_method() { return _deopt_nmethod; } + void set_deopt_compiled_method(nmethod* nm) { _deopt_nmethod = nm; } + nmethod* deopt_compiled_method() { return _deopt_nmethod; } Method* callee_target() const { return _callee_target; } void set_callee_target (Method* x) { _callee_target = x; } @@ -891,11 +891,11 @@ class JavaThread: public Thread { void frames_do(void f(frame*, const RegisterMap*)); // Memory operations - void oops_do_frames(OopClosure* f, CodeBlobClosure* cf); - void oops_do_no_frames(OopClosure* f, CodeBlobClosure* cf); + void oops_do_frames(OopClosure* f, NMethodClosure* cf); + void oops_do_no_frames(OopClosure* f, NMethodClosure* cf); // GC operations - virtual void nmethods_do(CodeBlobClosure* cf); + virtual void nmethods_do(NMethodClosure* cf); // RedefineClasses Support void metadata_do(MetadataClosure* f); diff --git a/src/hotspot/share/runtime/mutexLocker.cpp b/src/hotspot/share/runtime/mutexLocker.cpp index 1bf821fa5f6..d945037324e 100644 --- a/src/hotspot/share/runtime/mutexLocker.cpp +++ b/src/hotspot/share/runtime/mutexLocker.cpp @@ -37,7 +37,7 @@ // Mutexes used in the VM (see comment in mutexLocker.hpp): Mutex* Patching_lock = nullptr; -Mutex* CompiledMethod_lock = nullptr; +Mutex* NMethodState_lock = nullptr; Monitor* SystemDictionary_lock = nullptr; Mutex* InvokeMethodTypeTable_lock = nullptr; Monitor* InvokeMethodIntrinsicTable_lock = nullptr; @@ -327,7 +327,7 @@ void mutex_init() { MUTEX_DEFL(VtableStubs_lock , PaddedMutex , CompiledIC_lock); // Also holds DumpTimeTable_lock MUTEX_DEFL(CodeCache_lock , PaddedMonitor, VtableStubs_lock); MUTEX_DEFL(DirectivesStack_lock , PaddedMutex , CodeCache_lock); - MUTEX_DEFL(CompiledMethod_lock , PaddedMutex , CodeCache_lock); + MUTEX_DEFL(NMethodState_lock , PaddedMutex , CodeCache_lock); MUTEX_DEFL(Threads_lock , PaddedMonitor, CompileThread_lock, true); MUTEX_DEFL(Compile_lock , PaddedMutex , MethodCompileQueue_lock); diff --git a/src/hotspot/share/runtime/mutexLocker.hpp b/src/hotspot/share/runtime/mutexLocker.hpp index 7729189e18a..8b71a097812 100644 --- a/src/hotspot/share/runtime/mutexLocker.hpp +++ b/src/hotspot/share/runtime/mutexLocker.hpp @@ -32,7 +32,7 @@ // Mutexes used in the VM. extern Mutex* Patching_lock; // a lock used to guard code patching of compiled code -extern Mutex* CompiledMethod_lock; // a lock used to guard a compiled method and OSR queues +extern Mutex* NMethodState_lock; // a lock used to guard a compiled method state extern Monitor* SystemDictionary_lock; // a lock on the system dictionary extern Mutex* InvokeMethodTypeTable_lock; extern Monitor* InvokeMethodIntrinsicTable_lock; diff --git a/src/hotspot/share/runtime/os.cpp b/src/hotspot/share/runtime/os.cpp index 2d8d9a0d907..4e3bce88181 100644 --- a/src/hotspot/share/runtime/os.cpp +++ b/src/hotspot/share/runtime/os.cpp @@ -1256,7 +1256,7 @@ void os::print_location(outputStream* st, intptr_t x, bool verbose) { #ifdef _LP64 if (UseCompressedClassPointers && ((uintptr_t)addr &~ (uintptr_t)max_juint) == 0) { narrowKlass narrow_klass = (narrowKlass)(uintptr_t)addr; - Klass* k = CompressedKlassPointers::decode_raw(narrow_klass); + Klass* k = CompressedKlassPointers::decode_without_asserts(narrow_klass); if (Klass::is_valid(k)) { st->print_cr(UINT32_FORMAT " is a compressed pointer to class: " INTPTR_FORMAT, narrow_klass, p2i((HeapWord*)k)); diff --git a/src/hotspot/share/runtime/reflection.cpp b/src/hotspot/share/runtime/reflection.cpp index 0eaa5668250..bc8779158d3 100644 --- a/src/hotspot/share/runtime/reflection.cpp +++ b/src/hotspot/share/runtime/reflection.cpp @@ -328,7 +328,7 @@ static Klass* basic_type_mirror_to_arrayklass(oop basic_type_mirror, TRAPS) { THROW_0(vmSymbols::java_lang_IllegalArgumentException()); } else { - return Universe::typeArrayKlassObj(type); + return Universe::typeArrayKlass(type); } } diff --git a/src/hotspot/share/runtime/safepoint.cpp b/src/hotspot/share/runtime/safepoint.cpp index 74972b655a5..935c1beee40 100644 --- a/src/hotspot/share/runtime/safepoint.cpp +++ b/src/hotspot/share/runtime/safepoint.cpp @@ -844,8 +844,8 @@ void ThreadSafepointState::handle_polling_page_exception() { address real_return_addr = self->saved_exception_pc(); CodeBlob *cb = CodeCache::find_blob(real_return_addr); - assert(cb != nullptr && cb->is_compiled(), "return address should be in nmethod"); - CompiledMethod* nm = (CompiledMethod*)cb; + assert(cb != nullptr && cb->is_nmethod(), "return address should be in nmethod"); + nmethod* nm = cb->as_nmethod(); // Find frame of caller frame stub_fr = self->last_frame(); diff --git a/src/hotspot/share/runtime/serviceThread.cpp b/src/hotspot/share/runtime/serviceThread.cpp index ddc755a81f9..0118c5005ab 100644 --- a/src/hotspot/share/runtime/serviceThread.cpp +++ b/src/hotspot/share/runtime/serviceThread.cpp @@ -208,7 +208,7 @@ void ServiceThread::enqueue_deferred_event(JvmtiDeferredEvent* event) { Service_lock->notify_all(); } -void ServiceThread::oops_do_no_frames(OopClosure* f, CodeBlobClosure* cf) { +void ServiceThread::oops_do_no_frames(OopClosure* f, NMethodClosure* cf) { JavaThread::oops_do_no_frames(f, cf); // The ServiceThread "owns" the JVMTI Deferred events, scan them here // to keep them alive until they are processed. @@ -220,7 +220,7 @@ void ServiceThread::oops_do_no_frames(OopClosure* f, CodeBlobClosure* cf) { _jvmti_service_queue.oops_do(f, cf); } -void ServiceThread::nmethods_do(CodeBlobClosure* cf) { +void ServiceThread::nmethods_do(NMethodClosure* cf) { JavaThread::nmethods_do(cf); if (cf != nullptr) { if (_jvmti_event != nullptr) { diff --git a/src/hotspot/share/runtime/serviceThread.hpp b/src/hotspot/share/runtime/serviceThread.hpp index 10f443121c6..b3f76e08a4f 100644 --- a/src/hotspot/share/runtime/serviceThread.hpp +++ b/src/hotspot/share/runtime/serviceThread.hpp @@ -54,8 +54,8 @@ class ServiceThread : public JavaThread { static void enqueue_deferred_event(JvmtiDeferredEvent* event); // GC support - void oops_do_no_frames(OopClosure* f, CodeBlobClosure* cf); - void nmethods_do(CodeBlobClosure* cf); + void oops_do_no_frames(OopClosure* f, NMethodClosure* cf); + void nmethods_do(NMethodClosure* cf); }; #endif // SHARE_RUNTIME_SERVICETHREAD_HPP diff --git a/src/hotspot/share/runtime/sharedRuntime.cpp b/src/hotspot/share/runtime/sharedRuntime.cpp index ebd30f05451..a4ee1a31734 100644 --- a/src/hotspot/share/runtime/sharedRuntime.cpp +++ b/src/hotspot/share/runtime/sharedRuntime.cpp @@ -29,7 +29,7 @@ #include "classfile/vmSymbols.hpp" #include "code/codeCache.hpp" #include "code/compiledIC.hpp" -#include "code/compiledMethod.inline.hpp" +#include "code/nmethod.inline.hpp" #include "code/scopeDesc.hpp" #include "code/vtableStubs.hpp" #include "compiler/abstractCompiler.hpp" @@ -485,7 +485,7 @@ address SharedRuntime::raw_exception_handler_for_return_address(JavaThread* curr // The fastest case first CodeBlob* blob = CodeCache::find_blob(return_address); - CompiledMethod* nm = (blob != nullptr) ? blob->as_compiled_method_or_null() : nullptr; + nmethod* nm = (blob != nullptr) ? blob->as_nmethod_or_null() : nullptr; if (nm != nullptr) { // Set flag if return address is a method handle call site. current->set_is_method_handle_return(nm->is_method_handle_return(return_address)); @@ -558,10 +558,10 @@ address SharedRuntime::get_poll_stub(address pc) { CodeBlob *cb = CodeCache::find_blob(pc); // Should be an nmethod - guarantee(cb != nullptr && cb->is_compiled(), "safepoint polling: pc must refer to an nmethod"); + guarantee(cb != nullptr && cb->is_nmethod(), "safepoint polling: pc must refer to an nmethod"); // Look up the relocation information - assert(((CompiledMethod*)cb)->is_at_poll_or_poll_return(pc), + assert(cb->as_nmethod()->is_at_poll_or_poll_return(pc), "safepoint polling: type must be poll at pc " INTPTR_FORMAT, p2i(pc)); #ifdef ASSERT @@ -572,8 +572,8 @@ address SharedRuntime::get_poll_stub(address pc) { } #endif - bool at_poll_return = ((CompiledMethod*)cb)->is_at_poll_return(pc); - bool has_wide_vectors = ((CompiledMethod*)cb)->has_wide_vectors(); + bool at_poll_return = cb->as_nmethod()->is_at_poll_return(pc); + bool has_wide_vectors = cb->as_nmethod()->has_wide_vectors(); if (at_poll_return) { assert(SharedRuntime::polling_page_return_handler_blob() != nullptr, "polling page return stub not created yet"); @@ -683,26 +683,25 @@ JRT_END // ret_pc points into caller; we are returning caller's exception handler // for given exception // Note that the implementation of this method assumes it's only called when an exception has actually occured -address SharedRuntime::compute_compiled_exc_handler(CompiledMethod* cm, address ret_pc, Handle& exception, +address SharedRuntime::compute_compiled_exc_handler(nmethod* nm, address ret_pc, Handle& exception, bool force_unwind, bool top_frame_only, bool& recursive_exception_occurred) { - assert(cm != nullptr, "must exist"); + assert(nm != nullptr, "must exist"); ResourceMark rm; #if INCLUDE_JVMCI - if (cm->is_compiled_by_jvmci()) { + if (nm->is_compiled_by_jvmci()) { // lookup exception handler for this pc - int catch_pco = pointer_delta_as_int(ret_pc, cm->code_begin()); - ExceptionHandlerTable table(cm); + int catch_pco = pointer_delta_as_int(ret_pc, nm->code_begin()); + ExceptionHandlerTable table(nm); HandlerTableEntry *t = table.entry_for(catch_pco, -1, 0); if (t != nullptr) { - return cm->code_begin() + t->pco(); + return nm->code_begin() + t->pco(); } else { - return Deoptimization::deoptimize_for_missing_exception_handler(cm); + return Deoptimization::deoptimize_for_missing_exception_handler(nm); } } #endif // INCLUDE_JVMCI - nmethod* nm = cm->as_nmethod(); ScopeDesc* sd = nm->scope_desc_at(ret_pc); // determine handler bci, if any EXCEPTION_MARK; @@ -913,7 +912,7 @@ address SharedRuntime::continuation_for_implicit_exception(JavaThread* current, // 2. Inline-cache check in nmethod, or // 3. Implicit null exception in nmethod - if (!cb->is_compiled()) { + if (!cb->is_nmethod()) { bool is_in_blob = cb->is_adapter_blob() || cb->is_method_handles_adapter_blob(); if (!is_in_blob) { // Allow normal crash reporting to handle this @@ -925,8 +924,8 @@ address SharedRuntime::continuation_for_implicit_exception(JavaThread* current, } // Otherwise, it's a compiled method. Consult its exception handlers. - CompiledMethod* cm = (CompiledMethod*)cb; - if (cm->inlinecache_check_contains(pc)) { + nmethod* nm = cb->as_nmethod(); + if (nm->inlinecache_check_contains(pc)) { // exception happened inside inline-cache check code // => the nmethod is not yet active (i.e., the frame // is not set up yet) => use return address pushed by @@ -935,7 +934,7 @@ address SharedRuntime::continuation_for_implicit_exception(JavaThread* current, return StubRoutines::throw_NullPointerException_at_call_entry(); } - if (cm->method()->is_method_handle_intrinsic()) { + if (nm->method()->is_method_handle_intrinsic()) { // exception happened inside MH dispatch code, similar to a vtable stub Events::log_exception(current, "NullPointerException in MH adapter " INTPTR_FORMAT, p2i(pc)); return StubRoutines::throw_NullPointerException_at_call_entry(); @@ -944,7 +943,7 @@ address SharedRuntime::continuation_for_implicit_exception(JavaThread* current, #ifndef PRODUCT _implicit_null_throws++; #endif - target_pc = cm->continuation_for_implicit_null_exception(pc); + target_pc = nm->continuation_for_implicit_null_exception(pc); // If there's an unexpected fault, target_pc might be null, // in which case we want to fall through into the normal // error handling code. @@ -955,12 +954,12 @@ address SharedRuntime::continuation_for_implicit_exception(JavaThread* current, case IMPLICIT_DIVIDE_BY_ZERO: { - CompiledMethod* cm = CodeCache::find_compiled(pc); - guarantee(cm != nullptr, "must have containing compiled method for implicit division-by-zero exceptions"); + nmethod* nm = CodeCache::find_nmethod(pc); + guarantee(nm != nullptr, "must have containing compiled method for implicit division-by-zero exceptions"); #ifndef PRODUCT _implicit_div0_throws++; #endif - target_pc = cm->continuation_for_implicit_div0_exception(pc); + target_pc = nm->continuation_for_implicit_div0_exception(pc); // If there's an unexpected fault, target_pc might be null, // in which case we want to fall through into the normal // error handling code. @@ -1109,7 +1108,7 @@ Handle SharedRuntime::find_callee_info(Bytecodes::Code& bc, CallInfo& callinfo, } Method* SharedRuntime::extract_attached_method(vframeStream& vfst) { - CompiledMethod* caller = vfst.nm(); + nmethod* caller = vfst.nm(); address pc = vfst.frame_pc(); { // Get call instruction under lock because another thread may be busy patching it. @@ -1295,8 +1294,8 @@ methodHandle SharedRuntime::resolve_helper(bool is_virtual, bool is_optimized, T frame caller_frame = current->last_frame().sender(&cbl_map); CodeBlob* caller_cb = caller_frame.cb(); - guarantee(caller_cb != nullptr && caller_cb->is_compiled(), "must be called from compiled method"); - CompiledMethod* caller_nm = caller_cb->as_compiled_method(); + guarantee(caller_cb != nullptr && caller_cb->is_nmethod(), "must be called from compiled method"); + nmethod* caller_nm = caller_cb->as_nmethod(); // determine call info & receiver // note: a) receiver is null for static calls @@ -1506,8 +1505,8 @@ JRT_BLOCK_ENTRY(address, SharedRuntime::resolve_static_call_C(JavaThread* curren frame stub_frame = current->last_frame(); assert(stub_frame.is_runtime_frame(), "must be a runtimeStub"); frame caller = stub_frame.sender(®_map); - enter_special = caller.cb() != nullptr && caller.cb()->is_compiled() - && caller.cb()->as_compiled_method()->method()->is_continuation_enter_intrinsic(); + enter_special = caller.cb() != nullptr && caller.cb()->is_nmethod() + && caller.cb()->as_nmethod()->method()->is_continuation_enter_intrinsic(); } JRT_BLOCK_END @@ -1603,7 +1602,7 @@ methodHandle SharedRuntime::handle_ic_miss_helper(TRAPS) { RegisterMap::WalkContinuation::skip); frame caller_frame = current->last_frame().sender(®_map); CodeBlob* cb = caller_frame.cb(); - CompiledMethod* caller_nm = cb->as_compiled_method(); + nmethod* caller_nm = cb->as_nmethod(); CompiledICLocker ml(caller_nm); CompiledIC* inline_cache = CompiledIC_before(caller_nm, caller_frame.pc()); @@ -1634,11 +1633,12 @@ methodHandle SharedRuntime::reresolve_call_site(TRAPS) { // so no update to the caller is needed. if ((caller.is_compiled_frame() && !caller.is_deoptimized_frame()) || - (caller.is_native_frame() && ((CompiledMethod*)caller.cb())->method()->is_continuation_enter_intrinsic())) { + (caller.is_native_frame() && caller.cb()->as_nmethod()->method()->is_continuation_enter_intrinsic())) { address pc = caller.pc(); - CompiledMethod* caller_nm = CodeCache::find_compiled(pc); + nmethod* caller_nm = CodeCache::find_nmethod(pc); + assert(caller_nm != nullptr, "did not find caller nmethod"); // Default call_addr is the location of the "basic" call. // Determine the address of the call we a reresolving. With @@ -1766,7 +1766,7 @@ JRT_LEAF(void, SharedRuntime::fixup_callers_callsite(Method* method, address cal // Result from nmethod::is_unloading is not stable across safepoints. NoSafepointVerifier nsv; - CompiledMethod* callee = method->code(); + nmethod* callee = method->code(); if (callee == nullptr) { return; } @@ -1775,12 +1775,12 @@ JRT_LEAF(void, SharedRuntime::fixup_callers_callsite(Method* method, address cal MACOS_AARCH64_ONLY(ThreadWXEnable __wx(WXWrite, JavaThread::current())); CodeBlob* cb = CodeCache::find_blob(caller_pc); - if (cb == nullptr || !cb->is_compiled() || !callee->is_in_use() || callee->is_unloading()) { + if (cb == nullptr || !cb->is_nmethod() || !callee->is_in_use() || callee->is_unloading()) { return; } - // The check above makes sure this is a nmethod. - CompiledMethod* caller = cb->as_compiled_method(); + // The check above makes sure this is an nmethod. + nmethod* caller = cb->as_nmethod(); // Get the return PC for the passed caller PC. address return_pc = caller_pc + frame::pc_return_offset; @@ -2781,7 +2781,7 @@ void AdapterHandlerLibrary::create_native_wrapper(const methodHandle& method) { if (nm != nullptr) { { - MutexLocker pl(CompiledMethod_lock, Mutex::_no_safepoint_check_flag); + MutexLocker pl(NMethodState_lock, Mutex::_no_safepoint_check_flag); if (nm->make_in_use()) { method->set_code(method, nm); } @@ -3043,7 +3043,7 @@ JRT_END frame SharedRuntime::look_for_reserved_stack_annotated_method(JavaThread* current, frame fr) { ResourceMark rm(current); frame activation; - CompiledMethod* nm = nullptr; + nmethod* nm = nullptr; int count = 1; assert(fr.is_java_frame(), "Must start on Java frame"); @@ -3066,8 +3066,8 @@ frame SharedRuntime::look_for_reserved_stack_annotated_method(JavaThread* curren } } else { CodeBlob* cb = fr.cb(); - if (cb != nullptr && cb->is_compiled()) { - nm = cb->as_compiled_method(); + if (cb != nullptr && cb->is_nmethod()) { + nm = cb->as_nmethod(); method = nm->method(); // scope_desc_near() must be used, instead of scope_desc_at() because on // SPARC, the pcDesc can be on the delay slot after the call instruction. diff --git a/src/hotspot/share/runtime/sharedRuntime.hpp b/src/hotspot/share/runtime/sharedRuntime.hpp index 9d259616bd9..c8a10006764 100644 --- a/src/hotspot/share/runtime/sharedRuntime.hpp +++ b/src/hotspot/share/runtime/sharedRuntime.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 @@ -181,7 +181,7 @@ class SharedRuntime: AllStatic { static address exception_handler_for_return_address(JavaThread* current, address return_address); // exception handling and implicit exceptions - static address compute_compiled_exc_handler(CompiledMethod* nm, address ret_pc, Handle& exception, + static address compute_compiled_exc_handler(nmethod* nm, address ret_pc, Handle& exception, bool force_unwind, bool top_frame_only, bool& recursive_exception_occurred); enum ImplicitExceptionKind { IMPLICIT_NULL, @@ -328,7 +328,7 @@ class SharedRuntime: AllStatic { // deopt blob static void generate_deopt_blob(void); - static bool handle_ic_miss_helper_internal(Handle receiver, CompiledMethod* caller_nm, const frame& caller_frame, + static bool handle_ic_miss_helper_internal(Handle receiver, nmethod* caller_nm, const frame& caller_frame, methodHandle callee_method, Bytecodes::Code bc, CallInfo& call_info, bool& needs_ic_stub_refill, TRAPS); diff --git a/src/hotspot/share/runtime/stackChunkFrameStream.inline.hpp b/src/hotspot/share/runtime/stackChunkFrameStream.inline.hpp index 0a279c57385..8ead76211b7 100644 --- a/src/hotspot/share/runtime/stackChunkFrameStream.inline.hpp +++ b/src/hotspot/share/runtime/stackChunkFrameStream.inline.hpp @@ -1,4 +1,5 @@ -/* Copyright (c) 2019, 2022, Oracle and/or its affiliates. All rights reserved. +/* + * Copyright (c) 2019, 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 @@ -110,7 +111,7 @@ inline bool StackChunkFrameStream::is_stub() const { template inline bool StackChunkFrameStream::is_compiled() const { - return cb() != nullptr && _cb->is_compiled(); + return cb() != nullptr && _cb->is_nmethod(); } template <> @@ -188,9 +189,9 @@ inline int StackChunkFrameStream::stack_argsize() const { return 0; } assert(cb() != nullptr, ""); - assert(cb()->is_compiled(), ""); - assert(cb()->as_compiled_method()->method() != nullptr, ""); - return (cb()->as_compiled_method()->method()->num_stack_arg_slots() * VMRegImpl::stack_slot_size) >> LogBytesPerWord; + assert(cb()->is_nmethod(), ""); + assert(cb()->as_nmethod()->method() != nullptr, ""); + return (cb()->as_nmethod()->method()->num_stack_arg_slots() * VMRegImpl::stack_slot_size) >> LogBytesPerWord; } template @@ -265,7 +266,7 @@ inline void StackChunkFrameStream::get_oopmap() const { template inline void StackChunkFrameStream::get_oopmap(address pc, int oopmap_slot) const { assert(cb() != nullptr, ""); - assert(!is_compiled() || !cb()->as_compiled_method()->is_deopt_pc(pc), ""); + assert(!is_compiled() || !cb()->as_nmethod()->is_deopt_pc(pc), ""); if (oopmap_slot >= 0) { assert(oopmap_slot >= 0, ""); assert(cb()->oop_map_for_slot(oopmap_slot, pc) != nullptr, ""); @@ -317,13 +318,13 @@ inline address StackChunkFrameStream::orig_pc() const { if (is_interpreted() || is_stub()) { return pc1; } - CompiledMethod* cm = cb()->as_compiled_method(); - if (cm->is_deopt_pc(pc1)) { - pc1 = *(address*)((address)unextended_sp() + cm->orig_pc_offset()); + nmethod* nm = cb()->as_nmethod(); + if (nm->is_deopt_pc(pc1)) { + pc1 = *(address*)((address)unextended_sp() + nm->orig_pc_offset()); } assert(pc1 != nullptr, ""); - assert(!cm->is_deopt_pc(pc1), ""); + assert(!nm->is_deopt_pc(pc1), ""); assert(_cb == CodeCache::find_blob_fast(pc1), ""); return pc1; @@ -344,7 +345,7 @@ void StackChunkFrameStream::handle_deopted() const { address pc1 = pc(); int oopmap_slot = CodeCache::find_oopmap_slot_fast(pc1); if (oopmap_slot < 0) { // UNLIKELY; we could have marked frames for deoptimization in thaw_chunk - if (cb()->as_compiled_method()->is_deopt_pc(pc1)) { + if (cb()->as_nmethod()->is_deopt_pc(pc1)) { pc1 = orig_pc(); oopmap_slot = CodeCache::find_oopmap_slot_fast(pc1); } diff --git a/src/hotspot/share/runtime/stackValue.cpp b/src/hotspot/share/runtime/stackValue.cpp index b08c527dd01..c0b511ed537 100644 --- a/src/hotspot/share/runtime/stackValue.cpp +++ b/src/hotspot/share/runtime/stackValue.cpp @@ -248,8 +248,9 @@ StackValue* StackValue::create_stack_value(ScopeValue* sv, address value_addr, c return new StackValue(value.p); #endif } else if (sv->is_object()) { // Scalar replaced object in compiled frame - Handle ov = ((ObjectValue *)sv)->value(); - return new StackValue(ov, (ov.is_null()) ? 1 : 0); + ObjectValue* ov = (ObjectValue *)sv; + Handle hdl = ov->value(); + return new StackValue(hdl, hdl.is_null() && ov->is_scalar_replaced() ? 1 : 0); } else if (sv->is_marker()) { // Should never need to directly construct a marker. ShouldNotReachHere(); diff --git a/src/hotspot/share/runtime/synchronizer.cpp b/src/hotspot/share/runtime/synchronizer.cpp index 2dbafc62766..356be7cba43 100644 --- a/src/hotspot/share/runtime/synchronizer.cpp +++ b/src/hotspot/share/runtime/synchronizer.cpp @@ -602,7 +602,7 @@ bool ObjectSynchronizer::enter_fast_impl(Handle obj, BasicLock* lock, JavaThread } markWord mark = obj()->mark_acquire(); - while (mark.is_neutral()) { + while (mark.is_unlocked()) { // Retry until a lock state change has been observed. cas_set_mark() may collide with non lock bits modifications. // Try to swing into 'fast-locked' state. assert(!lock_stack.contains(obj()), "thread must not already hold the lock"); @@ -625,7 +625,7 @@ bool ObjectSynchronizer::enter_fast_impl(Handle obj, BasicLock* lock, JavaThread return false; } else if (LockingMode == LM_LEGACY) { markWord mark = obj->mark(); - if (mark.is_neutral()) { + if (mark.is_unlocked()) { // Anticipate successful CAS -- the ST of the displaced mark must // be visible <= the ST performed by the CAS. lock->set_displaced_header(mark); @@ -696,7 +696,7 @@ void ObjectSynchronizer::exit(oop object, BasicLock* lock, JavaThread* current) // Only do diagnostics if we are not racing an inflation. Simply // exiting a recursive enter of a Java Monitor that is being // inflated is safe; see the has_monitor() comment below. - assert(!mark.is_neutral(), "invariant"); + assert(!mark.is_unlocked(), "invariant"); assert(!mark.has_locker() || current->is_lock_owned((address)mark.locker()), "invariant"); if (mark.has_monitor()) { @@ -1009,7 +1009,7 @@ intptr_t ObjectSynchronizer::FastHashCode(Thread* current, oop obj) { assert(LockingMode == LM_MONITOR, "+VerifyHeavyMonitors requires LockingMode == 0 (LM_MONITOR)"); guarantee((obj->mark().value() & markWord::lock_mask_in_place) != markWord::locked_value, "must not be lightweight/stack-locked"); } - if (mark.is_neutral() || (LockingMode == LM_LIGHTWEIGHT && mark.is_fast_locked())) { + if (mark.is_unlocked() || (LockingMode == LM_LIGHTWEIGHT && mark.is_fast_locked())) { hash = mark.hash(); if (hash != 0) { // if it has a hash, just return it return hash; @@ -1139,7 +1139,7 @@ bool ObjectSynchronizer::current_thread_holds_lock(JavaThread* current, return monitor->is_entered(current) != 0; } // Unlocked case, header in place - assert(mark.is_neutral(), "sanity check"); + assert(mark.is_unlocked(), "sanity check"); return false; } @@ -1172,7 +1172,7 @@ JavaThread* ObjectSynchronizer::get_lock_owner(ThreadsList * t_list, Handle h_ob // Unlocked case, header in place // Cannot have assertion since this object may have been // locked by another thread when reaching here. - // assert(mark.is_neutral(), "sanity check"); + // assert(mark.is_unlocked(), "sanity check"); return nullptr; } @@ -1423,7 +1423,7 @@ ObjectMonitor* ObjectSynchronizer::inflate_impl(JavaThread* inflating_thread, oo // * stack-locked - Coerce it to inflated from stack-locked. // * INFLATING - Busy wait for conversion from stack-locked to // inflated. - // * neutral - Aggressively inflate the object. + // * unlocked - Aggressively inflate the object. // CASE: inflated if (mark.has_monitor()) { @@ -1601,7 +1601,7 @@ ObjectMonitor* ObjectSynchronizer::inflate_impl(JavaThread* inflating_thread, oo return m; } - // CASE: neutral + // CASE: unlocked // TODO-FIXME: for entry we currently inflate and then try to CAS _owner. // If we know we're inflating for entry it's better to inflate by swinging a // pre-locked ObjectMonitor pointer into the object header. A successful @@ -1610,9 +1610,7 @@ ObjectMonitor* ObjectSynchronizer::inflate_impl(JavaThread* inflating_thread, oo // to inflate and then CAS() again to try to swing _owner from null to current. // An inflateTry() method that we could call from enter() would be useful. - // Catch if the object's header is not neutral (not locked and - // not marked is what we care about here). - assert(mark.is_neutral(), "invariant: header=" INTPTR_FORMAT, mark.value()); + assert(mark.is_unlocked(), "invariant: header=" INTPTR_FORMAT, mark.value()); ObjectMonitor* m = new ObjectMonitor(object); // prepare m for installation - set monitor to initial state m->set_header(mark); @@ -1635,7 +1633,7 @@ ObjectMonitor* ObjectSynchronizer::inflate_impl(JavaThread* inflating_thread, oo OM_PERFDATA_OP(Inflations, inc()); if (log_is_enabled(Trace, monitorinflation)) { ResourceMark rm; - lsh.print_cr("inflate(neutral): object=" INTPTR_FORMAT ", mark=" + lsh.print_cr("inflate(unlocked): object=" INTPTR_FORMAT ", mark=" INTPTR_FORMAT ", type='%s'", p2i(object), object->mark().value(), object->klass()->external_name()); } diff --git a/src/hotspot/share/runtime/thread.cpp b/src/hotspot/share/runtime/thread.cpp index 7401629bf94..396f349a885 100644 --- a/src/hotspot/share/runtime/thread.cpp +++ b/src/hotspot/share/runtime/thread.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. * Copyright (c) 2021, Azul Systems, Inc. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -399,7 +399,7 @@ bool Thread::claim_par_threads_do(uintx claim_token) { return false; } -void Thread::oops_do_no_frames(OopClosure* f, CodeBlobClosure* cf) { +void Thread::oops_do_no_frames(OopClosure* f, NMethodClosure* cf) { // Do oop for ThreadShadow f->do_oop((oop*)&_pending_exception); handle_area()->oops_do(f); @@ -429,7 +429,7 @@ class RememberProcessedThread: public StackObj { } }; -void Thread::oops_do(OopClosure* f, CodeBlobClosure* cf) { +void Thread::oops_do(OopClosure* f, NMethodClosure* cf) { // Record JavaThread to GC thread RememberProcessedThread rpt(this); oops_do_no_frames(f, cf); @@ -491,9 +491,11 @@ void Thread::print_on_error(outputStream* st, char* buf, int buflen) const { if (os_thr != nullptr) { st->fill_to(67); if (os_thr->get_state() != ZOMBIE) { + // Use raw field members for stack base/size as this could be + // called before a thread has run enough to initialize them. st->print(" [id=%d, stack(" PTR_FORMAT "," PTR_FORMAT ") (" PROPERFMT ")]", - osthread()->thread_id(), p2i(stack_end()), p2i(stack_base()), - PROPERFMTARGS(stack_size())); + osthread()->thread_id(), p2i(_stack_base - _stack_size), p2i(_stack_base), + PROPERFMTARGS(_stack_size)); } else { st->print(" terminated"); } diff --git a/src/hotspot/share/runtime/thread.hpp b/src/hotspot/share/runtime/thread.hpp index 32f7b7fa8ec..a3d6e091d28 100644 --- a/src/hotspot/share/runtime/thread.hpp +++ b/src/hotspot/share/runtime/thread.hpp @@ -48,7 +48,9 @@ class HandleArea; class HandleMark; class ICRefillVerifier; class JvmtiRawMonitor; +class NMethodClosure; class Metadata; +class OopClosure; class OSThread; class ParkEvent; class ResourceArea; @@ -58,8 +60,6 @@ class ThreadsList; class ThreadsSMRSupport; class VMErrorCallback; -class OopClosure; -class CodeBlobClosure; DEBUG_ONLY(class ResourceMark;) @@ -443,10 +443,10 @@ class Thread: public ThreadShadow { // GC support // Apply "f->do_oop" to all root oops in "this". // Used by JavaThread::oops_do. - // Apply "cf->do_code_blob" (if !nullptr) to all code blobs active in frames - virtual void oops_do_no_frames(OopClosure* f, CodeBlobClosure* cf); - virtual void oops_do_frames(OopClosure* f, CodeBlobClosure* cf) {} - void oops_do(OopClosure* f, CodeBlobClosure* cf); + // Apply "cf->do_nmethod" (if !nullptr) to all nmethods active in frames + virtual void oops_do_no_frames(OopClosure* f, NMethodClosure* cf); + virtual void oops_do_frames(OopClosure* f, NMethodClosure* cf) {} + void oops_do(OopClosure* f, NMethodClosure* cf); // Handles the parallel case for claim_threads_do. private: diff --git a/src/hotspot/share/runtime/threads.cpp b/src/hotspot/share/runtime/threads.cpp index a8650a97a39..2a16baf8648 100644 --- a/src/hotspot/share/runtime/threads.cpp +++ b/src/hotspot/share/runtime/threads.cpp @@ -1049,7 +1049,7 @@ void Threads::add(JavaThread* p, bool force_daemon) { ObjectSynchronizer::inc_in_use_list_ceiling(); // Possible GC point. - Events::log(p, "Thread added: " INTPTR_FORMAT, p2i(p)); + Events::log(Thread::current(), "Thread added: " INTPTR_FORMAT, p2i(p)); // Make new thread known to active EscapeBarrier EscapeBarrier::thread_added(p); @@ -1115,7 +1115,7 @@ void Threads::remove(JavaThread* p, bool is_daemon) { ObjectSynchronizer::dec_in_use_list_ceiling(); // Since Events::log uses a lock, we grab it outside the Threads_lock - Events::log(p, "Thread exited: " INTPTR_FORMAT, p2i(p)); + Events::log(Thread::current(), "Thread exited: " INTPTR_FORMAT, p2i(p)); } // Operations on the Threads list for GC. These are not explicitly locked, @@ -1125,7 +1125,7 @@ void Threads::remove(JavaThread* p, bool is_daemon) { // uses the Threads_lock to guarantee this property. It also makes sure that // all threads gets blocked when exiting or starting). -void Threads::oops_do(OopClosure* f, CodeBlobClosure* cf) { +void Threads::oops_do(OopClosure* f, NMethodClosure* cf) { ALL_JAVA_THREADS(p) { p->oops_do(f, cf); } @@ -1182,15 +1182,15 @@ void Threads::assert_all_threads_claimed() { class ParallelOopsDoThreadClosure : public ThreadClosure { private: OopClosure* _f; - CodeBlobClosure* _cf; + NMethodClosure* _cf; public: - ParallelOopsDoThreadClosure(OopClosure* f, CodeBlobClosure* cf) : _f(f), _cf(cf) {} + ParallelOopsDoThreadClosure(OopClosure* f, NMethodClosure* cf) : _f(f), _cf(cf) {} void do_thread(Thread* t) { t->oops_do(_f, _cf); } }; -void Threads::possibly_parallel_oops_do(bool is_par, OopClosure* f, CodeBlobClosure* cf) { +void Threads::possibly_parallel_oops_do(bool is_par, OopClosure* f, NMethodClosure* cf) { ParallelOopsDoThreadClosure tc(f, cf); possibly_parallel_threads_do(is_par, &tc); } @@ -1370,10 +1370,7 @@ void Threads::print_on(outputStream* st, bool print_stacks, } PrintOnClosure cl(st); - cl.do_thread(VMThread::vm_thread()); - Universe::heap()->gc_threads_do(&cl); - cl.do_thread(WatcherThread::watcher_thread()); - cl.do_thread(AsyncLogWriter::instance()); + non_java_threads_do(&cl); // SapMachine 2019-11-07: Vitals const Thread* vitals_sampler_thread = sapmachine_vitals::samplerthread(); diff --git a/src/hotspot/share/runtime/threads.hpp b/src/hotspot/share/runtime/threads.hpp index 97cfeea07ad..6c4573827d9 100644 --- a/src/hotspot/share/runtime/threads.hpp +++ b/src/hotspot/share/runtime/threads.hpp @@ -33,15 +33,13 @@ class JavaThread; class Metadata; +class MetadataClosure; +class OopClosure; class Thread; class ThreadClosure; class ThreadsList; class outputStream; -class CodeBlobClosure; -class MetadataClosure; -class OopClosure; - // The active thread queue. It also keeps track of the current used // thread priorities. class Threads: AllStatic { @@ -106,9 +104,9 @@ class Threads: AllStatic { // Apply "f->do_oop" to all root oops in all threads. // This version may only be called by sequential code. - static void oops_do(OopClosure* f, CodeBlobClosure* cf); + static void oops_do(OopClosure* f, NMethodClosure* cf); // This version may be called by sequential or parallel code. - static void possibly_parallel_oops_do(bool is_par, OopClosure* f, CodeBlobClosure* cf); + static void possibly_parallel_oops_do(bool is_par, OopClosure* f, NMethodClosure* cf); // RedefineClasses support static void metadata_do(MetadataClosure* f); diff --git a/src/hotspot/share/runtime/vframe.cpp b/src/hotspot/share/runtime/vframe.cpp index 9644962ade2..ccb90c427b0 100644 --- a/src/hotspot/share/runtime/vframe.cpp +++ b/src/hotspot/share/runtime/vframe.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 @@ -71,8 +71,8 @@ vframe* vframe::new_vframe(const frame* f, const RegisterMap* reg_map, JavaThrea // Compiled frame CodeBlob* cb = f->cb(); if (cb != nullptr) { - if (cb->is_compiled()) { - CompiledMethod* nm = (CompiledMethod*)cb; + if (cb->is_nmethod()) { + nmethod* nm = cb->as_nmethod(); return new compiledVFrame(f, reg_map, thread, nm); } diff --git a/src/hotspot/share/runtime/vframe.hpp b/src/hotspot/share/runtime/vframe.hpp index 2f2ab48ac43..427fea2f78e 100644 --- a/src/hotspot/share/runtime/vframe.hpp +++ b/src/hotspot/share/runtime/vframe.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 @@ -292,10 +292,10 @@ class vframeStreamCommon : StackObj { inline int decode_offset() const; inline oop continuation() const; - CodeBlob* cb() const { return _frame.cb(); } - CompiledMethod* nm() const { - assert( cb() != nullptr && cb()->is_compiled(), "usage"); - return (CompiledMethod*) cb(); + CodeBlob* cb() const { return _frame.cb(); } + nmethod* nm() const { + assert(cb() != nullptr, "usage"); + return cb()->as_nmethod(); } const RegisterMap* reg_map() { return &_reg_map; } diff --git a/src/hotspot/share/runtime/vframe.inline.hpp b/src/hotspot/share/runtime/vframe.inline.hpp index 97ab8e4e2db..4630e695ce9 100644 --- a/src/hotspot/share/runtime/vframe.inline.hpp +++ b/src/hotspot/share/runtime/vframe.inline.hpp @@ -206,7 +206,7 @@ inline bool vframeStreamCommon::fill_from_frame() { // Compiled frame - if (cb() != nullptr && cb()->is_compiled()) { + if (cb() != nullptr && cb()->is_nmethod()) { assert(nm()->method() != nullptr, "must be"); if (nm()->is_native_method()) { // Do not rely on scopeDesc since the pc might be imprecise due to the _last_native_pc trick. diff --git a/src/hotspot/share/runtime/vframe_hp.cpp b/src/hotspot/share/runtime/vframe_hp.cpp index b508b091047..28b62c60fd9 100644 --- a/src/hotspot/share/runtime/vframe_hp.cpp +++ b/src/hotspot/share/runtime/vframe_hp.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 @@ -242,7 +242,7 @@ BasicLock* compiledVFrame::resolve_monitor_lock(Location location) const { GrowableArray* compiledVFrame::monitors() const { // Natives has no scope if (scope() == nullptr) { - CompiledMethod* nm = code(); + nmethod* nm = code(); Method* method = nm->method(); assert(method->is_native(), "Expect a native method"); if (!method->is_synchronized()) { @@ -299,13 +299,13 @@ GrowableArray* compiledVFrame::monitors() const { } -compiledVFrame::compiledVFrame(const frame* fr, const RegisterMap* reg_map, JavaThread* thread, CompiledMethod* nm) +compiledVFrame::compiledVFrame(const frame* fr, const RegisterMap* reg_map, JavaThread* thread, nmethod* nm) : javaVFrame(fr, reg_map, thread) { _scope = nullptr; _vframe_id = 0; // Compiled method (native stub or Java code) // native wrappers have no scope data, it is implied - if (!nm->is_compiled() || !nm->as_compiled_method()->is_native_method()) { + if (!nm->is_native_method()) { _scope = nm->scope_desc_at(_fr.pc()); } } @@ -333,15 +333,15 @@ bool compiledVFrame::is_top() const { } -CompiledMethod* compiledVFrame::code() const { - return CodeCache::find_compiled(_fr.pc()); +nmethod* compiledVFrame::code() const { + return CodeCache::find_nmethod(_fr.pc()); } Method* compiledVFrame::method() const { if (scope() == nullptr) { // native nmethods have no scope the method is implied - nmethod* nm = code()->as_nmethod(); + nmethod* nm = code(); assert(nm->is_native_method(), "must be native"); return nm->method(); } @@ -358,7 +358,7 @@ int compiledVFrame::bci() const { int compiledVFrame::raw_bci() const { if (scope() == nullptr) { // native nmethods have no scope the method/bci is implied - nmethod* nm = code()->as_nmethod(); + nmethod* nm = code(); assert(nm->is_native_method(), "must be native"); return 0; } @@ -368,7 +368,7 @@ int compiledVFrame::raw_bci() const { bool compiledVFrame::should_reexecute() const { if (scope() == nullptr) { // native nmethods have no scope the method/bci is implied - nmethod* nm = code()->as_nmethod(); + nmethod* nm = code(); assert(nm->is_native_method(), "must be native"); return false; } @@ -378,7 +378,7 @@ bool compiledVFrame::should_reexecute() const { bool compiledVFrame::has_ea_local_in_scope() const { if (scope() == nullptr) { // native nmethod, all objs escape - assert(code()->as_nmethod()->is_native_method(), "must be native"); + assert(code()->is_native_method(), "must be native"); return false; } return (scope()->objects() != nullptr) || scope()->has_ea_local_in_scope(); @@ -387,7 +387,7 @@ bool compiledVFrame::has_ea_local_in_scope() const { bool compiledVFrame::arg_escape() const { if (scope() == nullptr) { // native nmethod, all objs escape - assert(code()->as_nmethod()->is_native_method(), "must be native"); + assert(code()->is_native_method(), "must be native"); return false; } return scope()->arg_escape(); @@ -397,7 +397,7 @@ vframe* compiledVFrame::sender() const { const frame f = fr(); if (scope() == nullptr) { // native nmethods have no scope the method/bci is implied - nmethod* nm = code()->as_nmethod(); + nmethod* nm = code(); assert(nm->is_native_method(), "must be native"); return vframe::sender(); } else { diff --git a/src/hotspot/share/runtime/vframe_hp.hpp b/src/hotspot/share/runtime/vframe_hp.hpp index 23818e41544..f5bfdbe6dab 100644 --- a/src/hotspot/share/runtime/vframe_hp.hpp +++ b/src/hotspot/share/runtime/vframe_hp.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 @@ -65,7 +65,7 @@ class compiledVFrame: public javaVFrame { public: // Constructors - compiledVFrame(const frame* fr, const RegisterMap* reg_map, JavaThread* thread, CompiledMethod* nm); + compiledVFrame(const frame* fr, const RegisterMap* reg_map, JavaThread* thread, nmethod* nm); // Update a local in a compiled frame. Update happens when deopt occurs void update_local(BasicType type, int index, jvalue value); @@ -77,7 +77,7 @@ class compiledVFrame: public javaVFrame { void update_monitor(int index, MonitorInfo* value); // Returns the active nmethod - CompiledMethod* code() const; + nmethod* code() const; // Returns the scopeDesc ScopeDesc* scope() const { return _scope; } diff --git a/src/hotspot/share/runtime/vmOperation.hpp b/src/hotspot/share/runtime/vmOperation.hpp index b6625a1d946..ed136e90206 100644 --- a/src/hotspot/share/runtime/vmOperation.hpp +++ b/src/hotspot/share/runtime/vmOperation.hpp @@ -47,7 +47,6 @@ template(ZombieAll) \ template(Verify) \ template(HeapDumper) \ - template(HeapDumpMerge) \ template(CollectForMetadataAllocation) \ template(CollectForCodeCacheAllocation) \ template(GC_HeapInspection) \ diff --git a/src/hotspot/share/runtime/vmStructs.cpp b/src/hotspot/share/runtime/vmStructs.cpp index cc9d8afbaa4..3935a9dcca8 100644 --- a/src/hotspot/share/runtime/vmStructs.cpp +++ b/src/hotspot/share/runtime/vmStructs.cpp @@ -253,7 +253,6 @@ nonstatic_field(InstanceKlass, _jni_ids, JNIid*) \ nonstatic_field(InstanceKlass, _osr_nmethods_head, nmethod*) \ JVMTI_ONLY(nonstatic_field(InstanceKlass, _breakpoints, BreakpointInfo*)) \ - volatile_nonstatic_field(InstanceKlass, _methods_jmethod_ids, jmethodID*) \ volatile_nonstatic_field(InstanceKlass, _idnum_allocated_count, u2) \ nonstatic_field(InstanceKlass, _annotations, Annotations*) \ nonstatic_field(InstanceKlass, _method_ordering, Array*) \ @@ -307,7 +306,7 @@ nonstatic_field(Method, _access_flags, AccessFlags) \ nonstatic_field(Method, _vtable_index, int) \ nonstatic_field(Method, _intrinsic_id, u2) \ - volatile_nonstatic_field(Method, _code, CompiledMethod*) \ + volatile_nonstatic_field(Method, _code, nmethod*) \ nonstatic_field(Method, _i2i_entry, address) \ volatile_nonstatic_field(Method, _from_compiled_entry, address) \ volatile_nonstatic_field(Method, _from_interpreted_entry, address) \ @@ -549,45 +548,37 @@ /* CodeBlobs (NOTE: incomplete, but only a little) */ \ /***************************************************/ \ \ - nonstatic_field(CodeBlob, _name, const char*) \ - nonstatic_field(CodeBlob, _size, int) \ - nonstatic_field(CodeBlob, _header_size, int) \ - nonstatic_field(CodeBlob, _frame_complete_offset, int) \ - nonstatic_field(CodeBlob, _data_offset, int) \ - nonstatic_field(CodeBlob, _frame_size, int) \ - nonstatic_field(CodeBlob, _oop_maps, ImmutableOopMapSet*) \ - nonstatic_field(CodeBlob, _code_begin, address) \ - nonstatic_field(CodeBlob, _code_end, address) \ - nonstatic_field(CodeBlob, _content_begin, address) \ - nonstatic_field(CodeBlob, _data_end, address) \ + nonstatic_field(CodeBlob, _name, const char*) \ + nonstatic_field(CodeBlob, _size, int) \ + nonstatic_field(CodeBlob, _header_size, int) \ + nonstatic_field(CodeBlob, _relocation_size, int) \ + nonstatic_field(CodeBlob, _content_offset, int) \ + nonstatic_field(CodeBlob, _code_offset, int) \ + nonstatic_field(CodeBlob, _frame_complete_offset, int) \ + nonstatic_field(CodeBlob, _data_offset, int) \ + nonstatic_field(CodeBlob, _frame_size, int) \ + nonstatic_field(CodeBlob, _oop_maps, ImmutableOopMapSet*) \ + nonstatic_field(CodeBlob, _caller_must_gc_arguments, bool) \ \ nonstatic_field(DeoptimizationBlob, _unpack_offset, int) \ \ - nonstatic_field(RuntimeStub, _caller_must_gc_arguments, bool) \ - \ - /********************************************************/ \ - /* CompiledMethod (NOTE: incomplete, but only a little) */ \ - /********************************************************/ \ - \ - nonstatic_field(CompiledMethod, _method, Method*) \ - volatile_nonstatic_field(CompiledMethod, _exception_cache, ExceptionCache*) \ - nonstatic_field(CompiledMethod, _scopes_data_begin, address) \ - nonstatic_field(CompiledMethod, _deopt_handler_begin, address) \ - nonstatic_field(CompiledMethod, _deopt_mh_handler_begin, address) \ - \ /**************************************************/ \ /* NMethods (NOTE: incomplete, but only a little) */ \ /**************************************************/ \ \ + nonstatic_field(nmethod, _method, Method*) \ nonstatic_field(nmethod, _entry_bci, int) \ nonstatic_field(nmethod, _osr_link, nmethod*) \ nonstatic_field(nmethod, _state, volatile signed char) \ nonstatic_field(nmethod, _exception_offset, int) \ + nonstatic_field(nmethod, _deopt_handler_offset, int) \ + nonstatic_field(nmethod, _deopt_mh_handler_offset, int) \ nonstatic_field(nmethod, _orig_pc_offset, int) \ nonstatic_field(nmethod, _stub_offset, int) \ nonstatic_field(nmethod, _consts_offset, int) \ nonstatic_field(nmethod, _oops_offset, int) \ nonstatic_field(nmethod, _metadata_offset, int) \ + nonstatic_field(nmethod, _scopes_data_offset, int) \ nonstatic_field(nmethod, _scopes_pcs_offset, int) \ nonstatic_field(nmethod, _dependencies_offset, int) \ nonstatic_field(nmethod, _handler_table_offset, int) \ @@ -598,6 +589,7 @@ nonstatic_field(nmethod, _osr_entry_point, address) \ nonstatic_field(nmethod, _compile_id, int) \ nonstatic_field(nmethod, _comp_level, CompLevel) \ + volatile_nonstatic_field(nmethod, _exception_cache, ExceptionCache*) \ \ unchecked_c2_static_field(Deoptimization, _trap_reason_name, void*) \ \ @@ -1311,8 +1303,7 @@ declare_type(AdapterBlob, BufferBlob) \ declare_type(MethodHandlesAdapterBlob, BufferBlob) \ declare_type(VtableBlob, BufferBlob) \ - declare_type(CompiledMethod, CodeBlob) \ - declare_type(nmethod, CompiledMethod) \ + declare_type(nmethod, CodeBlob) \ declare_type(RuntimeStub, RuntimeBlob) \ declare_type(SingletonBlob, RuntimeBlob) \ declare_type(SafepointBlob, SingletonBlob) \ diff --git a/src/hotspot/share/services/heapDumper.cpp b/src/hotspot/share/services/heapDumper.cpp index 656d6e2f1ab..c28f1021540 100644 --- a/src/hotspot/share/services/heapDumper.cpp +++ b/src/hotspot/share/services/heapDumper.cpp @@ -2166,20 +2166,6 @@ void DumpMerger::do_merge() { merge_done(); } -// The VM operation wraps DumpMerger so that it could be performed by VM thread -class VM_HeapDumpMerge : public VM_Operation { -private: - DumpMerger* _merger; -public: - VM_HeapDumpMerge(DumpMerger* merger) : _merger(merger) {} - VMOp_Type type() const { return VMOp_HeapDumpMerge; } - // heap dump merge could happen outside safepoint - virtual bool evaluate_at_safepoint() const { return false; } - void doit() { - _merger->do_merge(); - } -}; - // The VM operation that performs the heap dump class VM_HeapDumper : public VM_GC_Operation, public WorkerTask, public UnmountedVThreadDumper { private: @@ -2659,17 +2645,10 @@ int HeapDumper::dump(const char* path, outputStream* out, int compression, bool // This is done by DumpMerger, which is performed outside safepoint DumpMerger merger(path, &writer, dumper.dump_seq()); - Thread* current_thread = Thread::current(); - if (current_thread->is_AttachListener_thread()) { - // perform heapdump file merge operation in the current thread prevents us - // from occupying the VM Thread, which in turn affects the occurrence of - // GC and other VM operations. - merger.do_merge(); - } else { - // otherwise, performs it by VM thread - VM_HeapDumpMerge op(&merger); - VMThread::execute(&op); - } + // Perform heapdump file merge operation in the current thread prevents us + // from occupying the VM Thread, which in turn affects the occurrence of + // GC and other VM operations. + merger.do_merge(); if (writer.error() != nullptr) { set_error(writer.error()); } diff --git a/src/hotspot/share/utilities/globalDefinitions_gcc.hpp b/src/hotspot/share/utilities/globalDefinitions_gcc.hpp index 7ea877062d8..06bb22687d8 100644 --- a/src/hotspot/share/utilities/globalDefinitions_gcc.hpp +++ b/src/hotspot/share/utilities/globalDefinitions_gcc.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2022, 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 @@ -32,9 +32,11 @@ // declarations and a few frequently used utility functions. #include +#include #include #include #include +#include #include #include #include @@ -49,7 +51,6 @@ #include #if defined(LINUX) || defined(_ALLBSD_SOURCE) -#include #include #ifndef __OpenBSD__ #include @@ -79,28 +80,6 @@ #define NULL_WORD NULL #endif -#if !defined(LINUX) && !defined(_ALLBSD_SOURCE) -// Compiler-specific primitive types -typedef unsigned short uint16_t; -#ifndef _UINT32_T -#define _UINT32_T -typedef unsigned int uint32_t; -#endif // _UINT32_T - -#if !defined(_SYS_INT_TYPES_H) -#ifndef _UINT64_T -#define _UINT64_T -typedef unsigned long long uint64_t; -#endif // _UINT64_T -// %%%% how to access definition of intptr_t portably in 5.5 onward? -typedef int intptr_t; -typedef unsigned int uintptr_t; -// If this gets an error, figure out a symbol XXX that implies the -// prior definition of intptr_t, and add "&& !defined(XXX)" above. -#endif // _SYS_INT_TYPES_H - -#endif // !LINUX && !_ALLBSD_SOURCE - // checking for nanness #if defined(__APPLE__) inline int g_isnan(double f) { return isnan(f); } diff --git a/src/java.base/share/classes/java/io/CharArrayWriter.java b/src/java.base/share/classes/java/io/CharArrayWriter.java index f084d6245a8..8f165986c87 100644 --- a/src/java.base/share/classes/java/io/CharArrayWriter.java +++ b/src/java.base/share/classes/java/io/CharArrayWriter.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2023, 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 @@ -150,7 +150,8 @@ public void writeTo(Writer out) throws IOException { * Appends the specified character sequence to this writer. * *

An invocation of this method of the form {@code out.append(csq)} - * behaves in exactly the same way as the invocation + * when {@code csq} is not {@code null}, behaves in exactly the same way + * as the invocation * * {@snippet lang=java : * out.write(csq.toString()) diff --git a/src/java.base/share/classes/java/io/PrintStream.java b/src/java.base/share/classes/java/io/PrintStream.java index 6807827b022..2a548660a98 100644 --- a/src/java.base/share/classes/java/io/PrintStream.java +++ b/src/java.base/share/classes/java/io/PrintStream.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2023, 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 @@ -1444,7 +1444,8 @@ private void implFormat(Locale l, String format, Object ... args) throws IOExcep * Appends the specified character sequence to this output stream. * *

An invocation of this method of the form {@code out.append(csq)} - * behaves in exactly the same way as the invocation + * when {@code csq} is not {@code null}, behaves in exactly the same way + * as the invocation * * {@snippet lang=java : * out.print(csq.toString()) @@ -1452,7 +1453,7 @@ private void implFormat(Locale l, String format, Object ... args) throws IOExcep * *

Depending on the specification of {@code toString} for the * character sequence {@code csq}, the entire sequence may not be - * appended. For instance, invoking then {@code toString} method of a + * appended. For instance, invoking the {@code toString} method of a * character buffer will return a subsequence whose content depends upon * the buffer's position and limit. * diff --git a/src/java.base/share/classes/java/io/PrintWriter.java b/src/java.base/share/classes/java/io/PrintWriter.java index cb7f611f147..2ed9315ba6a 100644 --- a/src/java.base/share/classes/java/io/PrintWriter.java +++ b/src/java.base/share/classes/java/io/PrintWriter.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 @@ -1287,7 +1287,8 @@ private void implFormat(Locale l, String format, Object ... args) { * Appends the specified character sequence to this writer. * *

An invocation of this method of the form {@code out.append(csq)} - * behaves in exactly the same way as the invocation + * when {@code csq} is not {@code null}, behaves in exactly the same way + * as the invocation * * {@snippet lang=java : * out.write(csq.toString()) diff --git a/src/java.base/share/classes/java/io/StringWriter.java b/src/java.base/share/classes/java/io/StringWriter.java index 9fdeb5550cb..ee58d741cc8 100644 --- a/src/java.base/share/classes/java/io/StringWriter.java +++ b/src/java.base/share/classes/java/io/StringWriter.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2023, 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 @@ -126,7 +126,8 @@ public void write(String str, int off, int len) { * Appends the specified character sequence to this writer. * *

An invocation of this method of the form {@code out.append(csq)} - * behaves in exactly the same way as the invocation + * when {@code csq} is not {@code null}, behaves in exactly the same way + * as the invocation * * {@snippet lang=java : * out.write(csq.toString()) diff --git a/src/java.base/share/classes/java/io/Writer.java b/src/java.base/share/classes/java/io/Writer.java index 4ec95d84a76..62fe6b053e5 100644 --- a/src/java.base/share/classes/java/io/Writer.java +++ b/src/java.base/share/classes/java/io/Writer.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2023, 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 @@ -338,7 +338,8 @@ private void implWrite(String str, int off, int len) throws IOException { * Appends the specified character sequence to this writer. * *

An invocation of this method of the form {@code out.append(csq)} - * behaves in exactly the same way as the invocation + * when {@code csq} is not {@code null}, behaves in exactly the same way + * as the invocation * * {@snippet lang=java : * out.write(csq.toString()) @@ -369,7 +370,6 @@ public Writer append(CharSequence csq) throws IOException { /** * Appends a subsequence of the specified character sequence to this writer. - * {@code Appendable}. * *

An invocation of this method of the form * {@code out.append(csq, start, end)} when {@code csq} diff --git a/src/java.base/share/classes/java/lang/String.java b/src/java.base/share/classes/java/lang/String.java index 4ec3e8b6a94..3b497cd1923 100644 --- a/src/java.base/share/classes/java/lang/String.java +++ b/src/java.base/share/classes/java/lang/String.java @@ -1335,7 +1335,13 @@ private static byte[] encodeUTF8_UTF16(byte[] val, boolean doReplace) { int dp = 0; int sp = 0; int sl = val.length >> 1; - byte[] dst = new byte[sl * 3]; + // UTF-8 encoded can be as much as 3 times the string length + // For very large estimate, (as in overflow of 32 bit int), precompute the exact size + long allocLen = (sl * 3 < 0) ? computeSizeUTF8_UTF16(val, doReplace) : sl * 3; + if (allocLen > (long)Integer.MAX_VALUE) { + throw new OutOfMemoryError("Required length exceeds implementation limit"); + } + byte[] dst = new byte[(int) allocLen]; while (sp < sl) { // ascii fast loop; char c = StringUTF16.getChar(val, sp); @@ -1385,6 +1391,47 @@ private static byte[] encodeUTF8_UTF16(byte[] val, boolean doReplace) { return Arrays.copyOf(dst, dp); } + /** + * {@return the exact size required to UTF_8 encode this UTF16 string} + * @param val UTF16 encoded byte array + * @param doReplace true to replace unmappable characters + */ + private static long computeSizeUTF8_UTF16(byte[] val, boolean doReplace) { + long dp = 0L; + int sp = 0; + int sl = val.length >> 1; + + while (sp < sl) { + char c = StringUTF16.getChar(val, sp++); + if (c < 0x80) { + dp++; + } else if (c < 0x800) { + dp += 2; + } else if (Character.isSurrogate(c)) { + int uc = -1; + char c2; + if (Character.isHighSurrogate(c) && sp < sl && + Character.isLowSurrogate(c2 = StringUTF16.getChar(val, sp))) { + uc = Character.toCodePoint(c, c2); + } + if (uc < 0) { + if (doReplace) { + dp++; + } else { + throwUnmappable(sp - 1); + } + } else { + dp += 4; + sp++; // 2 chars + } + } else { + // 3 bytes, 16 bits + dp += 3; + } + } + return dp; + } + /** * Constructs a new {@code String} by decoding the specified array of bytes * using the specified {@linkplain java.nio.charset.Charset charset}. The diff --git a/src/java.base/share/classes/java/lang/classfile/ClassFile.java b/src/java.base/share/classes/java/lang/classfile/ClassFile.java index c024094f777..27c2f18fe96 100644 --- a/src/java.base/share/classes/java/lang/classfile/ClassFile.java +++ b/src/java.base/share/classes/java/lang/classfile/ClassFile.java @@ -180,7 +180,7 @@ enum DeadCodeOption implements Option { /** * Option describing whether to filter unresolved labels. - * Default is {@code FAIL_ON_DEAD_LABELS} to throw IllegalStateException + * Default is {@code FAIL_ON_DEAD_LABELS} to throw IllegalArgumentException * when any {@link ExceptionCatch}, {@link LocalVariableInfo}, * {@link LocalVariableTypeInfo}, or {@link CharacterRangeInfo} * reference to unresolved {@link Label} during bytecode serialization. diff --git a/src/java.base/share/classes/java/lang/classfile/Opcode.java b/src/java.base/share/classes/java/lang/classfile/Opcode.java index 9c4a1a80625..6ce231d43d0 100644 --- a/src/java.base/share/classes/java/lang/classfile/Opcode.java +++ b/src/java.base/share/classes/java/lang/classfile/Opcode.java @@ -645,7 +645,7 @@ public enum Opcode { IFNULL(ClassFile.IFNULL, 3, Kind.BRANCH, TypeKind.ReferenceType), /** Branch if reference not null */ - IFNONNULL(ClassFile.IFNONNULL, 3, Kind.BRANCH, TypeKind.IntType), + IFNONNULL(ClassFile.IFNONNULL, 3, Kind.BRANCH, TypeKind.ReferenceType), /** Branch always (wide index) */ GOTO_W(ClassFile.GOTO_W, 5, Kind.BRANCH, TypeKind.VoidType), 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 39244e98cfc..de94c09d9b4 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 @@ -174,20 +174,26 @@ * for some statically enumerated options, as well as factories for more complex options, * including: *

    - *
  • {@link java.lang.classfile.ClassFile.StackMapsOption} - * -- generate stackmaps (default is {@code STACK_MAPS_WHEN_REQUIRED})
  • - *
  • {@link java.lang.classfile.ClassFile.DebugElementsOption} - * -- processing of debug information, such as local variable metadata (default is {@code PASS_DEBUG})
  • - *
  • {@link java.lang.classfile.ClassFile.LineNumbersOption} - * -- processing of line numbers (default is {@code PASS_LINE_NUMBERS})
  • + *
  • {@link java.lang.classfile.ClassFile.AttributeMapperOption#of(java.util.function.Function)} + * -- specify format of custom attributes
  • *
  • {@link java.lang.classfile.ClassFile.AttributesProcessingOption} * -- unrecognized or problematic original attributes (default is {@code PASS_ALL_ATTRIBUTES})
  • - *
  • {@link java.lang.classfile.ClassFile.ConstantPoolSharingOption}} - * -- share constant pool when transforming (default is {@code SHARED_POOL})
  • *
  • {@link java.lang.classfile.ClassFile.ClassHierarchyResolverOption#of(java.lang.classfile.ClassHierarchyResolver)} * -- specify a custom class hierarchy resolver used by stack map generation
  • - *
  • {@link java.lang.classfile.ClassFile.AttributeMapperOption#of(java.util.function.Function)} - * -- specify format of custom attributes
  • + *
  • {@link java.lang.classfile.ClassFile.ConstantPoolSharingOption}} + * -- share constant pool when transforming (default is {@code SHARED_POOL})
  • + *
  • {@link java.lang.classfile.ClassFile.DeadCodeOption}} + * -- patch out unreachable code (default is {@code PATCH_DEAD_CODE})
  • + *
  • {@link java.lang.classfile.ClassFile.DeadLabelsOption}} + * -- filter unresolved labels (default is {@code FAIL_ON_DEAD_LABELS})
  • + *
  • {@link java.lang.classfile.ClassFile.DebugElementsOption} + * -- processing of debug information, such as local variable metadata (default is {@code PASS_DEBUG})
  • + *
  • {@link java.lang.classfile.ClassFile.LineNumbersOption} + * -- processing of line numbers (default is {@code PASS_LINE_NUMBERS})
  • + *
  • {@link java.lang.classfile.ClassFile.ShortJumpsOption} + * -- automatically rewrite short jumps to long when necessary (default is {@code FIX_SHORT_JUMPS})
  • + *
  • {@link java.lang.classfile.ClassFile.StackMapsOption} + * -- generate stackmaps (default is {@code STACK_MAPS_WHEN_REQUIRED})
  • *
*

* Most options allow you to request that certain parts of the classfile be diff --git a/src/java.base/share/classes/java/net/ServerSocket.java b/src/java.base/share/classes/java/net/ServerSocket.java index 5c57dc15ca9..b3e570c858a 100644 --- a/src/java.base/share/classes/java/net/ServerSocket.java +++ b/src/java.base/share/classes/java/net/ServerSocket.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1995, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1995, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -140,9 +140,10 @@ public ServerSocket() throws IOException { * request to connect) is set to {@code 50}. If a connection * indication arrives when the queue is full, the connection is refused. *

- * If the application has specified a server socket implementation - * factory, that factory's {@code createSocketImpl} method is called to - * create the actual socket implementation. Otherwise a system-default + * If the application has specified a {@linkplain SocketImplFactory server + * socket implementation factory}, that factory's + * {@linkplain SocketImplFactory#createSocketImpl() createSocketImpl} method + * is called to create the actual socket implementation. Otherwise a system-default * socket implementation is created. *

* If there is a security manager, @@ -163,7 +164,6 @@ public ServerSocket() throws IOException { * the specified range of valid port values, which is between * 0 and 65535, inclusive. * - * @see java.net.SocketImpl * @see SecurityManager#checkListen */ public ServerSocket(int port) throws IOException { @@ -183,9 +183,10 @@ public ServerSocket(int port) throws IOException { * a connection indication arrives when the queue is full, the * connection is refused. *

- * If the application has specified a server socket implementation - * factory, that factory's {@code createSocketImpl} method is called to - * create the actual socket implementation. Otherwise a system-default + * If the application has specified a {@linkplain SocketImplFactory server + * socket implementation factory}, that factory's + * {@linkplain SocketImplFactory#createSocketImpl() createSocketImpl} method + * is called to create the actual socket implementation. Otherwise a system-default * socket implementation is created. *

* If there is a security manager, @@ -214,7 +215,6 @@ public ServerSocket(int port) throws IOException { * the specified range of valid port values, which is between * 0 and 65535, inclusive. * - * @see java.net.SocketImpl * @see SecurityManager#checkListen */ public ServerSocket(int port, int backlog) throws IOException { @@ -261,8 +261,6 @@ public ServerSocket(int port, int backlog) throws IOException { * the specified range of valid port values, which is between * 0 and 65535, inclusive. * - * @see SocketOptions - * @see SocketImpl * @see SecurityManager#checkListen * @since 1.1 */ @@ -801,7 +799,7 @@ public boolean isClosed() { * specified timeout, in milliseconds. With this option set to a positive * timeout value, a call to accept() for this ServerSocket * will block for only this amount of time. If the timeout expires, - * a java.net.SocketTimeoutException is raised, though the + * a {@link java.net.SocketTimeoutException} is raised, though the * ServerSocket is still valid. A timeout of zero is interpreted as an * infinite timeout. * The option must be enabled prior to entering the blocking @@ -843,7 +841,7 @@ public int getSoTimeout() throws IOException { } /** - * Enable/disable the {@link SocketOptions#SO_REUSEADDR SO_REUSEADDR} + * Enable/disable the {@link StandardSocketOptions#SO_REUSEADDR SO_REUSEADDR} * socket option. *

* When a TCP connection is closed the connection may remain @@ -855,22 +853,22 @@ public int getSoTimeout() throws IOException { * {@code SocketAddress} if there is a connection in the * timeout state involving the socket address or port. *

- * Enabling {@link SocketOptions#SO_REUSEADDR SO_REUSEADDR} prior to - * binding the socket using {@link #bind(SocketAddress)} allows the socket - * to be bound even though a previous connection is in a timeout state. + * Enabling {@code SO_REUSEADDR} prior to binding the socket using + * {@link #bind(SocketAddress)} allows the socket to be bound even + * though a previous connection is in a timeout state. *

* When a {@code ServerSocket} is created the initial setting - * of {@link SocketOptions#SO_REUSEADDR SO_REUSEADDR} is not defined. - * Applications can use {@link #getReuseAddress()} to determine the initial - * setting of {@link SocketOptions#SO_REUSEADDR SO_REUSEADDR}. + * of {@code SO_REUSEADDR} is not defined. Applications can use + * {@link #getReuseAddress()} to determine the initial + * setting of {@code SO_REUSEADDR}. *

- * The behaviour when {@link SocketOptions#SO_REUSEADDR SO_REUSEADDR} is - * enabled or disabled after a socket is bound (See {@link #isBound()}) + * The behaviour when {@code SO_REUSEADDR} is enabled or disabled + * after a socket is bound (See {@link #isBound()}) * is not defined. * * @param on whether to enable or disable the socket option * @throws SocketException if an error occurs enabling or - * disabling the {@link SocketOptions#SO_REUSEADDR SO_REUSEADDR} + * disabling the {@code SO_REUSEADDR} * socket option, or the socket is closed. * @since 1.4 * @see #getReuseAddress() @@ -885,10 +883,10 @@ public void setReuseAddress(boolean on) throws SocketException { } /** - * Tests if {@link SocketOptions#SO_REUSEADDR SO_REUSEADDR} is enabled. + * Tests if {@link StandardSocketOptions#SO_REUSEADDR SO_REUSEADDR} is enabled. * * @return a {@code boolean} indicating whether or not - * {@link SocketOptions#SO_REUSEADDR SO_REUSEADDR} is enabled. + * {@code SO_REUSEADDR} is enabled. * @throws SocketException if there is an error * in the underlying protocol, such as a TCP error. * @since 1.4 @@ -981,14 +979,14 @@ public static synchronized void setSocketFactory(SocketImplFactory fac) throws I /** * Sets a default proposed value for the - * {@link SocketOptions#SO_RCVBUF SO_RCVBUF} option for sockets + * {@link StandardSocketOptions#SO_RCVBUF SO_RCVBUF} option for sockets * accepted from this {@code ServerSocket}. The value actually set * in the accepted socket must be determined by calling * {@link Socket#getReceiveBufferSize()} after the socket * is returned by {@link #accept()}. *

- * The value of {@link SocketOptions#SO_RCVBUF SO_RCVBUF} is used both to - * set the size of the internal socket receive buffer, and to set the size + * The value of {@code SO_RCVBUF} is used both to set the size of + * the internal socket receive buffer, and to set the size * of the TCP receive window that is advertised to the remote peer. *

* It is possible to change the value subsequently, by calling @@ -1024,14 +1022,13 @@ public void setReceiveBufferSize(int size) throws SocketException { } /** - * Gets the value of the {@link SocketOptions#SO_RCVBUF SO_RCVBUF} option + * Gets the value of the {@link StandardSocketOptions#SO_RCVBUF SO_RCVBUF} option * for this {@code ServerSocket}, that is the proposed buffer size that * will be used for Sockets accepted from this {@code ServerSocket}. * *

Note, the value actually set in the accepted socket is determined by * calling {@link Socket#getReceiveBufferSize()}. - * @return the value of the {@link SocketOptions#SO_RCVBUF SO_RCVBUF} - * option for this {@code Socket}. + * @return the value of the {@code SO_RCVBUF} option for this {@code Socket}. * @throws SocketException if there is an error * in the underlying protocol, such as a TCP error. * @see #setReceiveBufferSize(int) diff --git a/src/java.base/share/classes/java/net/Socket.java b/src/java.base/share/classes/java/net/Socket.java index e291dc829fa..7d0b2acda99 100644 --- a/src/java.base/share/classes/java/net/Socket.java +++ b/src/java.base/share/classes/java/net/Socket.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1995, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1995, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -172,10 +172,11 @@ private Socket(Void unused, SocketImpl impl) { /** * Creates an unconnected Socket. *

- * If the application has specified a client socket implementation - * factory, that factory's {@code createSocketImpl} method is called to - * create the actual socket implementation. Otherwise a system-default - * socket implementation is created. + * If the application has specified a {@linkplain SocketImplFactory client + * socket implementation factory}, that factory's + * {@linkplain SocketImplFactory#createSocketImpl() createSocketImpl} + * method is called to create the actual socket implementation. Otherwise + * a system-default socket implementation is created. * * @since 1.1 */ @@ -295,10 +296,11 @@ private static Void checkPermission(SocketImpl impl) { * In other words, it is equivalent to specifying an address of the * loopback interface.

*

- * If the application has specified a client socket implementation - * factory, that factory's {@code createSocketImpl} method is called to - * create the actual socket implementation. Otherwise a system-default - * socket implementation is created. + * If the application has specified a {@linkplain SocketImplFactory client + * socket implementation factory}, that factory's + * {@linkplain SocketImplFactory#createSocketImpl() createSocketImpl} + * method is called to create the actual socket implementation. Otherwise + * a system-default socket implementation is created. *

* If there is a security manager, its * {@code checkConnect} method is called @@ -317,7 +319,6 @@ private static Void checkPermission(SocketImpl impl) { * @throws IllegalArgumentException if the port parameter is outside * the specified range of valid port values, which is between * 0 and 65535, inclusive. - * @see java.net.SocketImpl * @see SecurityManager#checkConnect */ @SuppressWarnings("this-escape") @@ -333,10 +334,11 @@ public Socket(String host, int port) * Creates a stream socket and connects it to the specified port * number at the specified IP address. *

- * If the application has specified a client socket implementation - * factory, that factory's {@code createSocketImpl} method is called to - * create the actual socket implementation. Otherwise a system-default - * socket implementation is created. + * If the application has specified a {@linkplain SocketImplFactory client + * socket implementation factory}, that factory's + * {@linkplain SocketImplFactory#createSocketImpl() createSocketImpl} + * method is called to create the actual socket implementation. Otherwise + * a system-default socket implementation is created. *

* If there is a security manager, its * {@code checkConnect} method is called @@ -352,7 +354,6 @@ public Socket(String host, int port) * the specified range of valid port values, which is between * 0 and 65535, inclusive. * @throws NullPointerException if {@code address} is null. - * @see java.net.SocketImpl * @see SecurityManager#checkConnect */ @SuppressWarnings("this-escape") @@ -461,10 +462,11 @@ public Socket(InetAddress address, int port, InetAddress localAddr, * stream socket. If the stream argument is {@code false}, it * creates a datagram socket. *

- * If the application has specified a client socket implementation - * factory, that factory's {@code createSocketImpl} method is called to - * create the actual socket implementation. Otherwise a system-default - * socket implementation is created. + * If the application has specified a {@linkplain SocketImplFactory client + * socket implementation factory}, that factory's + * {@linkplain SocketImplFactory#createSocketImpl() createSocketImpl} + * method is called to create the actual socket implementation. Otherwise + * a system-default socket implementation is created. *

* If there is a security manager, its * {@code checkConnect} method is called @@ -483,7 +485,6 @@ public Socket(InetAddress address, int port, InetAddress localAddr, * @throws IllegalArgumentException if the port parameter is outside * the specified range of valid port values, which is between * 0 and 65535, inclusive. - * @see java.net.SocketImpl * @see SecurityManager#checkConnect * @deprecated Use DatagramSocket instead for UDP transport. */ @@ -503,10 +504,11 @@ public Socket(String host, int port, boolean stream) throws IOException { * stream socket. If the stream argument is {@code false}, it * creates a datagram socket. *

- * If the application has specified a client socket implementation - * factory, that factory's {@code createSocketImpl} method is called to - * create the actual socket implementation. Otherwise a system-default - * socket implementation is created. + * If the application has specified a {@linkplain SocketImplFactory client + * socket implementation factory}, that factory's + * {@linkplain SocketImplFactory#createSocketImpl() createSocketImpl} + * method is called to create the actual socket implementation. Otherwise + * a system-default socket implementation is created. * *

If there is a security manager, its * {@code checkConnect} method is called @@ -526,7 +528,6 @@ public Socket(String host, int port, boolean stream) throws IOException { * the specified range of valid port values, which is between * 0 and 65535, inclusive. * @throws NullPointerException if {@code host} is null. - * @see java.net.SocketImpl * @see SecurityManager#checkConnect * @deprecated Use DatagramSocket instead for UDP transport. */ @@ -1244,10 +1245,10 @@ public void close() throws IOException { } /** - * Enable/disable {@link SocketOptions#TCP_NODELAY TCP_NODELAY} + * Enable/disable {@link StandardSocketOptions#TCP_NODELAY TCP_NODELAY} * (disable/enable Nagle's algorithm). * - * @param on {@code true} to enable TCP_NODELAY, + * @param on {@code true} to enable {@code TCP_NODELAY}, * {@code false} to disable. * * @throws SocketException if there is an error @@ -1264,10 +1265,10 @@ public void setTcpNoDelay(boolean on) throws SocketException { } /** - * Tests if {@link SocketOptions#TCP_NODELAY TCP_NODELAY} is enabled. + * Tests if {@link StandardSocketOptions#TCP_NODELAY TCP_NODELAY} is enabled. * * @return a {@code boolean} indicating whether or not - * {@link SocketOptions#TCP_NODELAY TCP_NODELAY} is enabled. + * {@code TCP_NODELAY} is enabled. * @throws SocketException if there is an error * in the underlying protocol, such as a TCP error. * @since 1.1 @@ -1280,7 +1281,7 @@ public boolean getTcpNoDelay() throws SocketException { } /** - * Enable/disable {@link SocketOptions#SO_LINGER SO_LINGER} with the + * Enable/disable {@link StandardSocketOptions#SO_LINGER SO_LINGER} with the * specified linger time in seconds. The maximum timeout value is platform * specific. * @@ -1310,13 +1311,13 @@ public void setSoLinger(boolean on, int linger) throws SocketException { } /** - * Returns setting for {@link SocketOptions#SO_LINGER SO_LINGER}. + * Returns setting for {@link StandardSocketOptions#SO_LINGER SO_LINGER}. * -1 returns implies that the * option is disabled. * * The setting only affects socket close. * - * @return the setting for {@link SocketOptions#SO_LINGER SO_LINGER}. + * @return the setting for {@code SO_LINGER}. * @throws SocketException if there is an error * in the underlying protocol, such as a TCP error. * @since 1.1 @@ -1364,8 +1365,7 @@ public void sendUrgentData(int data) throws IOException { * and there is no capability to distinguish between normal data and urgent * data unless provided by a higher level protocol. * - * @param on {@code true} to enable - * {@link SocketOptions#SO_OOBINLINE SO_OOBINLINE}, + * @param on {@code true} to enable {@code SO_OOBINLINE}, * {@code false} to disable. * * @throws SocketException if there is an error @@ -1385,7 +1385,7 @@ public void setOOBInline(boolean on) throws SocketException { * Tests if {@link SocketOptions#SO_OOBINLINE SO_OOBINLINE} is enabled. * * @return a {@code boolean} indicating whether or not - * {@link SocketOptions#SO_OOBINLINE SO_OOBINLINE} is enabled. + * {@code SO_OOBINLINE} is enabled. * * @throws SocketException if there is an error * in the underlying protocol, such as a TCP error. @@ -1427,7 +1427,7 @@ public void setSoTimeout(int timeout) throws SocketException { * Returns setting for {@link SocketOptions#SO_TIMEOUT SO_TIMEOUT}. * 0 returns implies that the option is disabled (i.e., timeout of infinity). * - * @return the setting for {@link SocketOptions#SO_TIMEOUT SO_TIMEOUT} + * @return the setting for {@code SO_TIMEOUT} * @throws SocketException if there is an error * in the underlying protocol, such as a TCP error. * @@ -1447,15 +1447,13 @@ public int getSoTimeout() throws SocketException { } /** - * Sets the {@link SocketOptions#SO_SNDBUF SO_SNDBUF} option to the + * Sets the {@link StandardSocketOptions#SO_SNDBUF SO_SNDBUF} option to the * specified value for this {@code Socket}. - * The {@link SocketOptions#SO_SNDBUF SO_SNDBUF} option is used by the - * platform's networking code as a hint for the size to set the underlying - * network I/O buffers. + * The {@code SO_SNDBUF} option is used by the platform's networking code + * as a hint for the size to set the underlying network I/O buffers. * - *

Because {@link SocketOptions#SO_SNDBUF SO_SNDBUF} is a hint, - * applications that want to verify what size the buffers were set to - * should call {@link #getSendBufferSize()}. + *

Because {@code SO_SNDBUF} is a hint, applications that want to verify + * what size the buffers were set to should call {@link #getSendBufferSize()}. * * @throws SocketException if there is an error * in the underlying protocol, such as a TCP error. @@ -1478,11 +1476,10 @@ public void setSendBufferSize(int size) throws SocketException { } /** - * Get value of the {@link SocketOptions#SO_SNDBUF SO_SNDBUF} option + * Get value of the {@link StandardSocketOptions#SO_SNDBUF SO_SNDBUF} option * for this {@code Socket}, that is the buffer size used by the platform * for output on this {@code Socket}. - * @return the value of the {@link SocketOptions#SO_SNDBUF SO_SNDBUF} - * option for this {@code Socket}. + * @return the value of the {@code SO_SNDBUF} option for this {@code Socket}. * * @throws SocketException if there is an error * in the underlying protocol, such as a TCP error. @@ -1502,22 +1499,20 @@ public int getSendBufferSize() throws SocketException { } /** - * Sets the {@link SocketOptions#SO_RCVBUF SO_RCVBUF} option to the + * Sets the {@link StandardSocketOptions#SO_RCVBUF SO_RCVBUF} option to the * specified value for this {@code Socket}. The - * {@link SocketOptions#SO_RCVBUF SO_RCVBUF} option is - * used by the platform's networking code as a hint for the size to set - * the underlying network I/O buffers. + * {@code SO_RCVBUF} option is used by the platform's networking code + * as a hint for the size to set the underlying network I/O buffers. * *

Increasing the receive buffer size can increase the performance of * network I/O for high-volume connection, while decreasing it can * help reduce the backlog of incoming data. * - *

Because {@link SocketOptions#SO_RCVBUF SO_RCVBUF} is a hint, - * applications that want to verify what size the buffers were set to - * should call {@link #getReceiveBufferSize()}. + *

Because {@code SO_RCVBUF} is a hint, applications that want to verify + * what size the buffers were set to should call {@link #getReceiveBufferSize()}. * - *

The value of {@link SocketOptions#SO_RCVBUF SO_RCVBUF} is also used - * to set the TCP receive window that is advertised to the remote peer. + *

The value of {@code SO_RCVBUF} is also used to set the TCP receive window + * that is advertised to the remote peer. * Generally, the window size can be modified at any time when a socket is * connected. However, if a receive window larger than 64K is required then * this must be requested before the socket is connected to the @@ -1550,12 +1545,11 @@ public void setReceiveBufferSize(int size) throws SocketException { } /** - * Gets the value of the {@link SocketOptions#SO_RCVBUF SO_RCVBUF} option + * Gets the value of the {@link StandardSocketOptions#SO_RCVBUF SO_RCVBUF} option * for this {@code Socket}, that is the buffer size used by the platform * for input on this {@code Socket}. * - * @return the value of the {@link SocketOptions#SO_RCVBUF SO_RCVBUF} - * option for this {@code Socket}. + * @return the value of the {@code SO_RCVBUF} option for this {@code Socket}. * @throws SocketException if there is an error * in the underlying protocol, such as a TCP error. * @see #setReceiveBufferSize(int) @@ -1573,7 +1567,7 @@ public int getReceiveBufferSize() throws SocketException { } /** - * Enable/disable {@link SocketOptions#SO_KEEPALIVE SO_KEEPALIVE}. + * Enable/disable {@link StandardSocketOptions#SO_KEEPALIVE SO_KEEPALIVE}. * * @param on whether or not to have socket keep alive turned on. * @throws SocketException if there is an error @@ -1588,10 +1582,10 @@ public void setKeepAlive(boolean on) throws SocketException { } /** - * Tests if {@link SocketOptions#SO_KEEPALIVE SO_KEEPALIVE} is enabled. + * Tests if {@link StandardSocketOptions#SO_KEEPALIVE SO_KEEPALIVE} is enabled. * * @return a {@code boolean} indicating whether or not - * {@link SocketOptions#SO_KEEPALIVE SO_KEEPALIVE} is enabled. + * {@code SO_KEEPALIVE} is enabled. * @throws SocketException if there is an error * in the underlying protocol, such as a TCP error. * @since 1.3 @@ -1647,7 +1641,7 @@ public boolean getKeepAlive() throws SocketException { * traffic class or type-of-service * @since 1.4 * @see #getTrafficClass - * @see SocketOptions#IP_TOS + * @see StandardSocketOptions#IP_TOS */ public void setTrafficClass(int tc) throws SocketException { if (tc < 0 || tc > 255) @@ -1671,14 +1665,14 @@ public void setTrafficClass(int tc) throws SocketException { * traffic class or type-of-service value. * @since 1.4 * @see #setTrafficClass(int) - * @see SocketOptions#IP_TOS + * @see StandardSocketOptions#IP_TOS */ public int getTrafficClass() throws SocketException { return ((Integer) (getImpl().getOption(SocketOptions.IP_TOS))).intValue(); } /** - * Enable/disable the {@link SocketOptions#SO_REUSEADDR SO_REUSEADDR} + * Enable/disable the {@link StandardSocketOptions#SO_REUSEADDR SO_REUSEADDR} * socket option. *

* When a TCP connection is closed the connection may remain @@ -1690,21 +1684,19 @@ public int getTrafficClass() throws SocketException { * {@code SocketAddress} if there is a connection in the * timeout state involving the socket address or port. *

- * Enabling {@link SocketOptions#SO_REUSEADDR SO_REUSEADDR} - * prior to binding the socket using {@link #bind(SocketAddress)} allows - * the socket to be bound even though a previous connection is in a timeout - * state. + * Enabling {@code SO_REUSEADDR} prior to binding the socket using + * {@link #bind(SocketAddress)} allows the socket to be bound even + * though a previous connection is in a timeout state. *

* When a {@code Socket} is created the initial setting - * of {@link SocketOptions#SO_REUSEADDR SO_REUSEADDR} is disabled. + * of {@code SO_REUSEADDR} is disabled. *

- * The behaviour when {@link SocketOptions#SO_REUSEADDR SO_REUSEADDR} is - * enabled or disabled after a socket is bound (See {@link #isBound()}) - * is not defined. + * The behaviour when {@code SO_REUSEADDR} is enabled or disabled after + * a socket is bound (See {@link #isBound()}) is not defined. * * @param on whether to enable or disable the socket option * @throws SocketException if an error occurs enabling or - * disabling the {@link SocketOptions#SO_REUSEADDR SO_REUSEADDR} + * disabling the {@code SO_REUSEADDR} * socket option, or the socket is closed. * @since 1.4 * @see #getReuseAddress() @@ -1719,10 +1711,10 @@ public void setReuseAddress(boolean on) throws SocketException { } /** - * Tests if {@link SocketOptions#SO_REUSEADDR SO_REUSEADDR} is enabled. + * Tests if {@link StandardSocketOptions#SO_REUSEADDR SO_REUSEADDR} is enabled. * * @return a {@code boolean} indicating whether or not - * {@link SocketOptions#SO_REUSEADDR SO_REUSEADDR} is enabled. + * {@code SO_REUSEADDR} is enabled. * @throws SocketException if there is an error * in the underlying protocol, such as a TCP error. * @since 1.4 diff --git a/src/java.base/share/classes/java/net/SocketOptions.java b/src/java.base/share/classes/java/net/SocketOptions.java index 7dac20ac55b..340530d8cef 100644 --- a/src/java.base/share/classes/java/net/SocketOptions.java +++ b/src/java.base/share/classes/java/net/SocketOptions.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2023, 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 @@ -29,15 +29,15 @@ /** * Interface of methods to get/set socket options. This interface is - * implemented by: SocketImpl and DatagramSocketImpl. - * Subclasses of these should override the methods - * of this interface in order to support their own options. + * implemented by {@link SocketImpl} and {@link DatagramSocketImpl}. + * Subclasses of these two classes should override the {@link #getOption(int)} and + * {@link #setOption(int, Object)} methods of this interface in order to support their own options. *

- * The methods and constants which specify options in this interface are - * for implementation only. If you're not subclassing SocketImpl or - * DatagramSocketImpl, you won't use these directly. There are - * type-safe methods to get/set each of these options in Socket, ServerSocket, - * DatagramSocket and MulticastSocket. + * The methods and constants defined in this interface are + * for implementation only. If you're not subclassing {@code SocketImpl} or + * {@code DatagramSocketImpl}, then you won't use these directly. There are + * type-safe methods to get/set each of these options in {@link Socket}, {@link ServerSocket}, + * {@link DatagramSocket} and {@link MulticastSocket}. * * @author David Brown * @since 1.1 @@ -47,54 +47,45 @@ public interface SocketOptions { /** - * Enable/disable the option specified by optID. If the option - * is to be enabled, and it takes an option-specific "value", this is - * passed in value. The actual type of value is option-specific, - * and it is an error to pass something that isn't of the expected type: - *

+     * Enable/disable the option specified by {@code optID}. If the option
+     * is to be enabled, and it takes an option-specific "value", this is passed in {@code value}.
+     * The actual type of {@code value} is option-specific, and it is an error to pass something
+     * that isn't of the expected type:
+     * {@snippet lang=java :
      * SocketImpl s;
      * ...
      * s.setOption(SO_LINGER, Integer.valueOf(10));
      *    // OK - set SO_LINGER w/ timeout of 10 sec.
      * s.setOption(SO_LINGER, Double.valueOf(10));
      *    // ERROR - expects java.lang.Integer
-     *
- * If the requested option is binary, it can be set using this method by - * a java.lang.Boolean: - *
+     *}
+     * If the requested option is binary, it can be set using this method by a {@link Boolean}:
+     * {@snippet lang=java :
      * s.setOption(TCP_NODELAY, Boolean.TRUE);
      *    // OK - enables TCP_NODELAY, a binary option
-     * 
- *
- * Any option can be disabled using this method with a Boolean.FALSE: - *
+     * }
+     * Any option can be disabled using this method with a {@link Boolean#FALSE}:
+     * {@snippet lang=java :
      * s.setOption(TCP_NODELAY, Boolean.FALSE);
      *    // OK - disables TCP_NODELAY
      * s.setOption(SO_LINGER, Boolean.FALSE);
      *    // OK - disables SO_LINGER
-     * 
- *
- * For an option that has a notion of on and off, and requires - * a non-boolean parameter, setting its value to anything other than - * Boolean.FALSE implicitly enables it. - *
- * Throws SocketException if the option is unrecognized, - * the socket is closed, or some low-level error occurred - *
+ * } + * For an option that has a notion of on and off, and requires a non-boolean parameter, setting + * its value to anything other than {@link Boolean#FALSE} implicitly enables it. + * * @param optID identifies the option * @param value the parameter of the socket option - * @throws SocketException if the option is unrecognized, - * the socket is closed, or some low-level error occurred + * @throws SocketException if the option is unrecognized, the socket is closed, or some + * low-level error occurred * @see #getOption(int) */ - public void - setOption(int optID, Object value) throws SocketException; + public void setOption(int optID, Object value) throws SocketException; /** - * Fetch the value of an option. - * Binary options will return java.lang.Boolean.TRUE - * if enabled, java.lang.Boolean.FALSE if disabled, e.g.: - *
+     * Fetch the value of an option. Binary options will return {@link Boolean#TRUE} if enabled,
+     * {@link Boolean#FALSE} if disabled, e.g.:
+     * {@snippet lang=java :
      * SocketImpl s;
      * ...
      * Boolean noDelay = (Boolean)(s.getOption(TCP_NODELAY));
@@ -102,115 +93,83 @@ public interface SocketOptions {
      *     // true if TCP_NODELAY is enabled...
      * ...
      * }
-     * 
+ * } *

- * For options that take a particular type as a parameter, - * getOption(int) will return the parameter's value, else - * it will return java.lang.Boolean.FALSE: - *

+     * For options that take a particular type as a parameter, this method will return the
+     * parameter's value, else it will return {@link Boolean#FALSE}:
+     * {@snippet lang=java :
      * Object o = s.getOption(SO_LINGER);
      * if (o instanceof Integer) {
      *     System.out.print("Linger time is " + ((Integer)o).intValue());
      * } else {
      *   // the true type of o is java.lang.Boolean.FALSE;
      * }
-     * 
+ * } * * @param optID an {@code int} identifying the option to fetch * @return the value of the option - * @throws SocketException if the socket is closed - * @throws SocketException if optID is unknown along the - * protocol stack (including the SocketImpl) + * @throws SocketException if the socket is closed or if {@code optID} is unknown along the + * protocol stack * @see #setOption(int, java.lang.Object) */ public Object getOption(int optID) throws SocketException; - /** - * The java-supported BSD-style options. - */ + // Java supported BSD-style options follow /** - * Disable Nagle's algorithm for this connection. Written data - * to the network is not buffered pending acknowledgement of - * previously written data. - *

- * Valid for TCP only: SocketImpl. + * See {@link StandardSocketOptions#TCP_NODELAY} for description of this socket option. * * @see Socket#setTcpNoDelay * @see Socket#getTcpNoDelay */ - @Native public static final int TCP_NODELAY = 0x0001; /** - * Fetch the local address binding of a socket (this option cannot - * be "set" only "gotten", since sockets are bound at creation time, - * and so the locally bound address cannot be changed). The default local - * address of a socket is INADDR_ANY, meaning any local address on a - * multi-homed host. A multi-homed host can use this option to accept + * Fetch the local address binding of a socket. This option cannot be set and can only be + * fetched. The default local address of a socket is + * {@link InetAddress#isAnyLocalAddress() INADDR_ANY}, meaning any local + * address on a multi-homed host. A multi-homed host can use this option to accept * connections to only one of its addresses (in the case of a - * ServerSocket or DatagramSocket), or to specify its return address - * to the peer (for a Socket or DatagramSocket). The parameter of - * this option is an InetAddress. - *

- * This option must be specified in the constructor. - *

- * Valid for: SocketImpl, DatagramSocketImpl + * {@link ServerSocket} or {@link DatagramSocket}), or to specify its return address + * to the peer (for a {@link Socket} or {@link DatagramSocket}). The type of this option's + * value is an {@link InetAddress}. * * @see Socket#getLocalAddress * @see DatagramSocket#getLocalAddress */ - @Native public static final int SO_BINDADDR = 0x000F; - /** Sets SO_REUSEADDR for a socket. This is used only for MulticastSockets - * in java, and it is set by default for MulticastSockets. - *

- * Valid for: DatagramSocketImpl + /** + * See {@link StandardSocketOptions#SO_REUSEADDR} for description of this socket option. */ - @Native public static final int SO_REUSEADDR = 0x04; - /** Sets SO_REUSEPORT for a socket. This option enables and disables - * the ability to have multiple sockets listen to the same address - * and port. - *

- * Valid for: SocketImpl, DatagramSocketImpl - * + /** + * See {@link StandardSocketOptions#SO_REUSEPORT} for description of this socket option. * @since 9 - * @see StandardSocketOptions#SO_REUSEPORT */ @Native public static final int SO_REUSEPORT = 0x0E; /** - * Sets SO_BROADCAST for a socket. This option enables and disables - * the ability of the process to send broadcast messages. It is supported - * for only datagram sockets and only on networks that support - * the concept of a broadcast message (e.g. Ethernet, token ring, etc.), - * and it is set by default for DatagramSockets. + * See {@link StandardSocketOptions#SO_BROADCAST} for description of this socket option. * @since 1.4 */ - @Native public static final int SO_BROADCAST = 0x0020; - /** Set which outgoing interface on which to send multicast packets. - * Useful on hosts with multiple network interfaces, where applications - * want to use other than the system default. Takes/returns an InetAddress. - *

- * Valid for Multicast: DatagramSocketImpl + /** + * See {@link StandardSocketOptions#IP_MULTICAST_IF} for description of this socket option. * * @see MulticastSocket#setInterface(InetAddress) * @see MulticastSocket#getInterface() */ - @Native public static final int IP_MULTICAST_IF = 0x10; - /** Same as above. This option is introduced so that the behaviour - * with IP_MULTICAST_IF will be kept the same as before, while - * this new option can support setting outgoing interfaces with either - * IPv4 and IPv6 addresses. + /** + * This option is used to both set and fetch the outgoing interface on which the multicast + * packets are sent. Useful on hosts with multiple network interfaces, where applications + * want to use other than the system default. This option supports setting outgoing interfaces + * with either IPv4 and IPv6 addresses. * - * NOTE: make sure there is no conflict with this * @see MulticastSocket#setNetworkInterface(NetworkInterface) * @see MulticastSocket#getNetworkInterface() * @since 1.4 @@ -218,53 +177,39 @@ public interface SocketOptions { @Native public static final int IP_MULTICAST_IF2 = 0x1f; /** - * This option enables or disables local loopback of multicast datagrams. - * This option is enabled by default for Multicast Sockets. + * See {@link StandardSocketOptions#IP_MULTICAST_LOOP} for description of this socket option. * @since 1.4 */ - @Native public static final int IP_MULTICAST_LOOP = 0x12; /** - * This option sets the type-of-service or traffic class field - * in the IP header for a TCP or UDP socket. + * See {@link StandardSocketOptions#IP_TOS} for description of this socket option. * @since 1.4 */ - @Native public static final int IP_TOS = 0x3; /** - * Specify a linger-on-close timeout. This option disables/enables - * immediate return from a close() of a TCP Socket. Enabling - * this option with a non-zero Integer timeout means that a - * close() will block pending the transmission and acknowledgement - * of all data written to the peer, at which point the socket is closed - * gracefully. Upon reaching the linger timeout, the socket is - * closed forcefully, with a TCP RST. Enabling the option with a - * timeout of zero does a forceful close immediately. If the specified - * timeout value exceeds 65,535 it will be reduced to 65,535. - *

- * Valid only for TCP: SocketImpl + * See {@link StandardSocketOptions#SO_LINGER} for description of this socket option. * * @see Socket#setSoLinger * @see Socket#getSoLinger */ @Native public static final int SO_LINGER = 0x0080; - /** Set a timeout on blocking Socket operations: - *

-     * ServerSocket.accept();
-     * SocketInputStream.read();
-     * DatagramSocket.receive();
-     * 
- * - *

The option must be set prior to entering a blocking - * operation to take effect. If the timeout expires and the - * operation would continue to block, - * java.io.InterruptedIOException is raised. The Socket is - * not closed in this case. + /** + * This option is used to both set and fetch a timeout value on blocking + * {@code Socket} operations: + *

    + *
  • {@linkplain ServerSocket#accept() ServerSocket.accept()}
  • + *
  • {@linkplain Socket#getInputStream() Socket InputStream.read()}
  • + *
  • {@linkplain DatagramSocket#receive(DatagramPacket) DatagramSocket.receive()}
  • + *
* - *

Valid for all sockets: SocketImpl, DatagramSocketImpl + *

+ * This option must be set prior to entering a blocking operation to take effect. If the + * timeout expires and the operation would continue to block, then + * {@link java.io.InterruptedIOException} is raised. The {@code Socket} is not closed + * in such cases. * * @see Socket#setSoTimeout * @see ServerSocket#setSoTimeout @@ -273,14 +218,7 @@ public interface SocketOptions { @Native public static final int SO_TIMEOUT = 0x1006; /** - * Set a hint the size of the underlying buffers used by the - * platform for outgoing network I/O. When used in set, this is a - * suggestion to the kernel from the application about the size of - * buffers to use for the data to be sent over the socket. When - * used in get, this must return the size of the buffer actually - * used by the platform when sending out data on this socket. - * - * Valid for all sockets: SocketImpl, DatagramSocketImpl + * See {@link StandardSocketOptions#SO_SNDBUF} for description of this socket option. * * @see Socket#setSendBufferSize * @see Socket#getSendBufferSize @@ -290,15 +228,7 @@ public interface SocketOptions { @Native public static final int SO_SNDBUF = 0x1001; /** - * Set a hint the size of the underlying buffers used by the - * platform for incoming network I/O. When used in set, this is a - * suggestion to the kernel from the application about the size of - * buffers to use for the data to be received over the - * socket. When used in get, this must return the size of the - * buffer actually used by the platform when receiving in data on - * this socket. - * - * Valid for all sockets: SocketImpl, DatagramSocketImpl + * See {@link StandardSocketOptions#SO_RCVBUF} for description of this socket option. * * @see Socket#setReceiveBufferSize * @see Socket#getReceiveBufferSize @@ -308,22 +238,7 @@ public interface SocketOptions { @Native public static final int SO_RCVBUF = 0x1002; /** - * When the keepalive option is set for a TCP socket and no data - * has been exchanged across the socket in either direction for - * 2 hours (NOTE: the actual value is implementation dependent), - * TCP automatically sends a keepalive probe to the peer. This probe is a - * TCP segment to which the peer must respond. - * One of three responses is expected: - * 1. The peer responds with the expected ACK. The application is not - * notified (since everything is OK). TCP will send another probe - * following another 2 hours of inactivity. - * 2. The peer responds with an RST, which tells the local TCP that - * the peer host has crashed and rebooted. The socket is closed. - * 3. There is no response from the peer. The socket is closed. - * - * The purpose of this option is to detect if the peer host crashes. - * - * Valid only for TCP socket: SocketImpl + * See {@link StandardSocketOptions#SO_KEEPALIVE} for description of this socket option. * * @see Socket#setKeepAlive * @see Socket#getKeepAlive @@ -331,10 +246,9 @@ public interface SocketOptions { @Native public static final int SO_KEEPALIVE = 0x0008; /** - * When the OOBINLINE option is set, any TCP urgent data received on - * the socket will be received through the socket input stream. - * When the option is disabled (which is the default) urgent data - * is silently discarded. + * When this option is set, any TCP urgent data received on the socket will be received + * through the socket input stream. When the option is disabled (which is the default) + * urgent data is silently discarded. * * @see Socket#setOOBInline * @see Socket#getOOBInline diff --git a/src/java.base/share/classes/java/security/cert/X509Extension.java b/src/java.base/share/classes/java/security/cert/X509Extension.java index e4e1670540f..141cd24a1bb 100644 --- a/src/java.base/share/classes/java/security/cert/X509Extension.java +++ b/src/java.base/share/classes/java/security/cert/X509Extension.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2022, 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 @@ -161,12 +161,12 @@ public interface X509Extension { * Extension Name * * + * 1.3.6.1.5.5.7.1.1 + * AuthorityInformationAccess * 2.5.29.14 * SubjectKeyIdentifier * 2.5.29.15 * KeyUsage - * 2.5.29.16 - * PrivateKeyUsage * 2.5.29.17 * SubjectAlternativeName * 2.5.29.18 @@ -175,12 +175,18 @@ public interface X509Extension { * BasicConstraints * 2.5.29.30 * NameConstraints + * 2.5.29.31 + * CRLDistributionPoints + * 2.5.29.32 + * CertificatePolicies * 2.5.29.33 * PolicyMappings * 2.5.29.35 * AuthorityKeyIdentifier * 2.5.29.36 * PolicyConstraints + * 2.5.29.37 + * ExtendedKeyUsage * * * diff --git a/src/java.base/share/classes/java/util/ImmutableCollections.java b/src/java.base/share/classes/java/util/ImmutableCollections.java index 525cdf15ecd..726c7bb923b 100644 --- a/src/java.base/share/classes/java/util/ImmutableCollections.java +++ b/src/java.base/share/classes/java/util/ImmutableCollections.java @@ -258,6 +258,8 @@ abstract static class AbstractImmutableList extends AbstractImmutableCollecti @Override public void add(int index, E element) { throw uoe(); } @Override public boolean addAll(int index, Collection c) { throw uoe(); } @Override public E remove(int index) { throw uoe(); } + @Override public E removeFirst() { throw uoe(); } + @Override public E removeLast() { throw uoe(); } @Override public void replaceAll(UnaryOperator operator) { throw uoe(); } @Override public E set(int index, E element) { throw uoe(); } @Override public void sort(Comparator c) { throw uoe(); } diff --git a/src/java.base/share/classes/java/util/concurrent/ForkJoinPool.java b/src/java.base/share/classes/java/util/concurrent/ForkJoinPool.java index 98e3cd2917b..f64ba4bf998 100644 --- a/src/java.base/share/classes/java/util/concurrent/ForkJoinPool.java +++ b/src/java.base/share/classes/java/util/concurrent/ForkJoinPool.java @@ -1140,12 +1140,7 @@ public final ForkJoinWorkerThread newThread(ForkJoinPool pool) { boolean isCommon = (pool.workerNamePrefix == null); @SuppressWarnings("removal") SecurityManager sm = System.getSecurityManager(); - if (sm == null) { - if (isCommon) - return new ForkJoinWorkerThread.InnocuousForkJoinWorkerThread(pool); - else - return new ForkJoinWorkerThread(null, pool, true, false); - } else if (isCommon) + if (sm != null && isCommon) return newCommonWithACC(pool); else return newRegularWithACC(pool); diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/AbstractInstruction.java b/src/java.base/share/classes/jdk/internal/classfile/impl/AbstractInstruction.java index 4b0f4f12399..1ee9e1136a5 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/AbstractInstruction.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/AbstractInstruction.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 @@ -860,7 +860,7 @@ public int slot() { @Override public int constant() { - return 0; + return constant; } @Override diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/ClassPrinterImpl.java b/src/java.base/share/classes/jdk/internal/classfile/impl/ClassPrinterImpl.java index c7617f07257..989589d0a01 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/ClassPrinterImpl.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/ClassPrinterImpl.java @@ -817,13 +817,15 @@ private static MapNode codeToTree(CodeAttribute com, Verbosity verbosity) { "owner", inv.owner().name().stringValue(), "method name", inv.name().stringValue(), "method type", inv.type().stringValue())); - case InvokeDynamicInstruction invd -> in.with(leafs( + case InvokeDynamicInstruction invd -> { + in.with(leafs( "name", invd.name().stringValue(), "descriptor", invd.type().stringValue(), - "kind", invd.bootstrapMethod().kind().name(), - "owner", invd.bootstrapMethod().owner().descriptorString(), - "method name", invd.bootstrapMethod().methodName(), - "invocation type", invd.bootstrapMethod().invocationType().descriptorString())); + "bootstrap method", invd.bootstrapMethod().kind().name() + + " " + Util.toInternalName(invd.bootstrapMethod().owner()) + + "::" + invd.bootstrapMethod().methodName())); + in.with(list("arguments", "arg", invd.bootstrapArgs().stream())); + } case NewObjectInstruction newo -> in.with(leaf( "type", newo.className().name().stringValue())); case NewPrimitiveArrayInstruction newa -> in.with(leafs( @@ -884,12 +886,15 @@ private static Node[] attributesToTree(List> attributes, Verbosity bm -> { var mh = bm.bootstrapMethod(); var mref = mh.reference(); - return map("bm", + var bmNode = new MapNodeImpl(FLOW, "bm"); + bmNode.with(leafs( + "index", bm.bsmIndex(), "kind", DirectMethodHandleDesc.Kind.valueOf(mh.kind(), mref instanceof InterfaceMethodRefEntry).name(), - "owner", mref.owner().name().stringValue(), - "name", mref.nameAndType().name().stringValue(), - "type", mref.nameAndType().type().stringValue()); + "owner", mref.owner().asInternalName(), + "name", mref.nameAndType().name().stringValue())); + bmNode.with(list("args", "arg", bm.arguments().stream().map(LoadableConstantEntry::constantValue))); + return bmNode; }))); case ConstantValueAttribute cva -> nodes.add(leaf("constant value", cva.constant().constantValue())); diff --git a/src/java.base/share/classes/jdk/internal/javac/PreviewFeature.java b/src/java.base/share/classes/jdk/internal/javac/PreviewFeature.java index 8549da583c3..c24a58f0230 100644 --- a/src/java.base/share/classes/jdk/internal/javac/PreviewFeature.java +++ b/src/java.base/share/classes/jdk/internal/javac/PreviewFeature.java @@ -77,10 +77,11 @@ public enum Feature { SCOPED_VALUES, @JEP(number=462, title="Structured Concurrency", status="Second Preview") STRUCTURED_CONCURRENCY, - @JEP(number=457, title="ClassFile API", status="Preview") + @JEP(number=466, title="ClassFile API", status="Second Preview") CLASSFILE_API, @JEP(number=461, title="Stream Gatherers", status="Preview") STREAM_GATHERERS, + LANGUAGE_MODEL, /** * A key for testing. */ diff --git a/src/java.base/share/classes/sun/security/provider/certpath/DistributionPointFetcher.java b/src/java.base/share/classes/sun/security/provider/certpath/DistributionPointFetcher.java index b231b7cbc86..31c0f4ecb9c 100644 --- a/src/java.base/share/classes/sun/security/provider/certpath/DistributionPointFetcher.java +++ b/src/java.base/share/classes/sun/security/provider/certpath/DistributionPointFetcher.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2023, 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 @@ -101,16 +101,28 @@ public static Collection getCRLs(X509CRLSelector selector, } return Collections.emptySet(); } - List points = - ext.getDistributionPoints(); + List points = ext.getDistributionPoints(); Set results = new HashSet<>(); + CertStoreException savedCSE = null; for (Iterator t = points.iterator(); t.hasNext() && !Arrays.equals(reasonsMask, ALL_REASONS); ) { - DistributionPoint point = t.next(); - Collection crls = getCRLs(selector, certImpl, - point, reasonsMask, signFlag, prevKey, prevCert, provider, - certStores, trustAnchors, validity, variant, anchor); - results.addAll(crls); + try { + DistributionPoint point = t.next(); + Collection crls = getCRLs(selector, certImpl, + point, reasonsMask, signFlag, prevKey, prevCert, provider, + certStores, trustAnchors, validity, variant, anchor); + results.addAll(crls); + } catch (CertStoreException cse) { + if (savedCSE == null) { + savedCSE = cse; + } else { + savedCSE.addSuppressed(cse); + } + } + } + // only throw CertStoreException if no CRLs are retrieved + if (results.isEmpty() && savedCSE != null) { + throw savedCSE; } if (debug != null) { debug.println("Returning " + results.size() + " CRLs"); @@ -182,7 +194,11 @@ private static Collection getCRLs(X509CRLSelector selector, } } } catch (CertStoreException cse) { - savedCSE = cse; + if (savedCSE == null) { + savedCSE = cse; + } else { + savedCSE.addSuppressed(cse); + } } } // only throw CertStoreException if no CRLs are retrieved diff --git a/src/java.base/share/conf/security/java.security b/src/java.base/share/conf/security/java.security index 7b2f7e957b3..20aad5dd718 100644 --- a/src/java.base/share/conf/security/java.security +++ b/src/java.base/share/conf/security/java.security @@ -892,7 +892,7 @@ jdk.tls.legacyAlgorithms=NULL, anon, RC4, DES, 3DES_EDE_CBC # KeyLimits: # " KeyLimit { , KeyLimit } " # -# WeakKeyLimit: +# KeyLimit: # AlgorithmName Action Length # # AlgorithmName: diff --git a/src/java.base/share/man/java.1 b/src/java.base/share/man/java.1 index 9d5bd5fba98..3754408fbde 100644 --- a/src/java.base/share/man/java.1 +++ b/src/java.base/share/man/java.1 @@ -4308,9 +4308,9 @@ The \f[V]-Xlog\f[R] option supports the following types of outputs: .IP \[bu] 2 \f[V]file=\f[R]\f[I]filename\f[R] --- Sends output to text file(s). .PP -When using \f[V]file=\f[R]\f[I]filename\f[R], specifying \f[V]%p\f[R] -and/or \f[V]%t\f[R] in the file name expands to the JVM\[aq]s PID and -startup timestamp, respectively. +When using \f[V]file=\f[R]\f[I]filename\f[R], specifying \f[V]%p\f[R], +\f[V]%t\f[R] and/or \f[V]%hn\f[R] in the file name expands to the +JVM\[aq]s PID, startup timestamp and host name, respectively. You can also configure text files to handle file rotation based on file size and a number of files to rotate. For example, to rotate the log file every 10 MB and keep 5 files in diff --git a/src/java.compiler/share/classes/javax/annotation/processing/ProcessingEnvironment.java b/src/java.compiler/share/classes/javax/annotation/processing/ProcessingEnvironment.java index 9c04acb3e0b..fe869142b7f 100644 --- a/src/java.compiler/share/classes/javax/annotation/processing/ProcessingEnvironment.java +++ b/src/java.compiler/share/classes/javax/annotation/processing/ProcessingEnvironment.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 @@ -123,6 +123,8 @@ public interface ProcessingEnvironment { * {@code false}. * * @since 13 + * @see + * JEP 12: Preview Features */ default boolean isPreviewEnabled() { return false; 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 new file mode 100644 index 00000000000..0e504e192bd --- /dev/null +++ b/src/java.compiler/share/classes/javax/lang/model/util/AbstractAnnotationValueVisitorPreview.java @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2019, 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. + */ + +package javax.lang.model.util; + +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; + +/** + * A skeletal visitor for annotation values with default behavior + * appropriate for a {@linkplain + * ProcessingEnvironment#isPreviewEnabled preview} source version. + * + * @param the return type of this visitor's methods + * @param

the type of the additional parameter to this visitor's methods. + * + * @see + * Compatibility note for subclasses + * @see AbstractAnnotationValueVisitor6 + * @see AbstractAnnotationValueVisitor7 + * @see AbstractAnnotationValueVisitor8 + * @see AbstractAnnotationValueVisitor9 + * @see AbstractAnnotationValueVisitor14 + * @since 23 + */ +@SupportedSourceVersion(RELEASE_23) +@PreviewFeature(feature=PreviewFeature.Feature.LANGUAGE_MODEL, reflective=true) +public abstract class AbstractAnnotationValueVisitorPreview extends AbstractAnnotationValueVisitor14 { + + /** + * Constructor for concrete subclasses to call. + */ + protected AbstractAnnotationValueVisitorPreview() { + super(); + } +} 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 new file mode 100644 index 00000000000..eb361654394 --- /dev/null +++ b/src/java.compiler/share/classes/javax/lang/model/util/AbstractElementVisitorPreview.java @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2019, 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. + */ + +package javax.lang.model.util; + +import jdk.internal.javac.PreviewFeature; + +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.*; + +/** + * A skeletal visitor of program elements with default behavior + * appropriate for a {@linkplain + * ProcessingEnvironment#isPreviewEnabled preview} source version. + * + * @param the return type of this visitor's methods. Use {@link + * Void} for visitors that do not need to return results. + * @param

the type of the additional parameter to this visitor's + * methods. Use {@code Void} for visitors that do not need an + * additional parameter. + * + * @see + * Compatibility note for subclasses + * @see AbstractElementVisitor6 + * @see AbstractElementVisitor7 + * @see AbstractElementVisitor8 + * @see AbstractElementVisitor9 + * @see AbstractElementVisitor14 + * @since 23 + */ +@SupportedSourceVersion(RELEASE_23) +@PreviewFeature(feature=PreviewFeature.Feature.LANGUAGE_MODEL, reflective=true) +public abstract class AbstractElementVisitorPreview extends AbstractElementVisitor14 { + /** + * Constructor for concrete subclasses to call. + */ + protected AbstractElementVisitorPreview(){ + super(); + } +} 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 new file mode 100644 index 00000000000..5da08ee004e --- /dev/null +++ b/src/java.compiler/share/classes/javax/lang/model/util/AbstractTypeVisitorPreview.java @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2019, 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. + */ + +package javax.lang.model.util; + +import jdk.internal.javac.PreviewFeature; + +import javax.annotation.processing.SupportedSourceVersion; +import javax.annotation.processing.ProcessingEnvironment; +import javax.lang.model.SourceVersion; +import static javax.lang.model.SourceVersion.*; + +/** + * A skeletal visitor of types with default behavior appropriate for a + * {@linkplain ProcessingEnvironment#isPreviewEnabled preview} source + * version. + * + * @param the return type of this visitor's methods. Use {@link + * Void} for visitors that do not need to return results. + * @param

the type of the additional parameter to this visitor's + * methods. Use {@code Void} for visitors that do not need an + * additional parameter. + * + * @see + * Compatibility note for subclasses + * @see AbstractTypeVisitor6 + * @see AbstractTypeVisitor7 + * @see AbstractTypeVisitor8 + * @see AbstractTypeVisitor9 + * @see AbstractTypeVisitor14 + * @since 23 + */ +@SupportedSourceVersion(RELEASE_23) +@PreviewFeature(feature=PreviewFeature.Feature.LANGUAGE_MODEL, reflective=true) +public abstract class AbstractTypeVisitorPreview extends AbstractTypeVisitor14 { + /** + * Constructor for concrete subclasses to call. + */ + protected AbstractTypeVisitorPreview() { + super(); + } +} 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 new file mode 100644 index 00000000000..01c70ea11d5 --- /dev/null +++ b/src/java.compiler/share/classes/javax/lang/model/util/ElementKindVisitorPreview.java @@ -0,0 +1,89 @@ +/* + * Copyright (c) 2019, 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. + */ + +package javax.lang.model.util; + +import jdk.internal.javac.PreviewFeature; + +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.*; + +/** + * A visitor of program elements based on their {@linkplain + * ElementKind kind} with default behavior appropriate for a + * {@linkplain ProcessingEnvironment#isPreviewEnabled preview} source + * version. + * + * For {@linkplain + * Element elements} Xyz that may have more than one + * kind, the visitXyz methods in this class delegate + * to the visitXyzAsKind method corresponding to the + * first argument's kind. The visitXyzAsKind methods + * call {@link #defaultAction defaultAction}, passing their arguments + * to {@code defaultAction}'s corresponding parameters. + * + * @apiNote + * Methods in this class may be overridden subject to their general + * contract. + * + * @param the return type of this visitor's methods. Use {@link + * Void} for visitors that do not need to return results. + * @param

the type of the additional parameter to this visitor's + * methods. Use {@code Void} for visitors that do not need an + * additional parameter. + * + * @see + * Compatibility note for subclasses + * @see ElementKindVisitor6 + * @see ElementKindVisitor7 + * @see ElementKindVisitor8 + * @see ElementKindVisitor9 + * @see ElementKindVisitor14 + * @since 23 + */ +@SupportedSourceVersion(RELEASE_23) +@PreviewFeature(feature=PreviewFeature.Feature.LANGUAGE_MODEL, reflective=true) +public class ElementKindVisitorPreview extends ElementKindVisitor14 { + /** + * Constructor for concrete subclasses; uses {@code null} for the + * default value. + */ + protected ElementKindVisitorPreview() { + super(null); + } + + /** + * Constructor for concrete subclasses; uses the argument for the + * default value. + * + * @param defaultValue the value to assign to {@link #DEFAULT_VALUE} + */ + protected ElementKindVisitorPreview(R defaultValue) { + super(defaultValue); + } +} 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 new file mode 100644 index 00000000000..511141a5093 --- /dev/null +++ b/src/java.compiler/share/classes/javax/lang/model/util/ElementScannerPreview.java @@ -0,0 +1,105 @@ +/* + * Copyright (c) 2019, 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. + */ + +package javax.lang.model.util; + +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.*; + +/** + * A scanning visitor of program elements with default behavior + * appropriate for a {@linkplain + * ProcessingEnvironment#isPreviewEnabled preview} source version. + * + * The visitXyz methods in this class scan their + * component elements by calling {@link ElementScanner6#scan(Element, + * Object) scan} on their {@linkplain Element#getEnclosedElements + * enclosed elements}, {@linkplain ExecutableElement#getParameters + * parameters}, etc., as indicated in the individual method + * specifications. A subclass can control the order elements are + * visited by overriding the visitXyz methods. + * Note that clients of a scanner may get the desired behavior by + * invoking {@code v.scan(e, p)} rather than {@code v.visit(e, p)} on + * the root objects of interest. + * + *

When a subclass overrides a visitXyz method, the + * new method can cause the enclosed elements to be scanned in the + * default way by calling super.visitXyz. In this + * fashion, the concrete visitor can control the ordering of traversal + * over the component elements with respect to the additional + * processing; for example, consistently calling + * super.visitXyz at the start of the overridden + * methods will yield a preorder traversal, etc. If the component + * elements should be traversed in some other order, instead of + * calling super.visitXyz, an overriding visit method + * should call {@code scan} with the elements in the desired order. + * + * @apiNote + * Methods in this class may be overridden subject to their general + * contract. + * + * @param the return type of this visitor's methods. Use {@link + * Void} for visitors that do not need to return results. + * @param

the type of the additional parameter to this visitor's + * methods. Use {@code Void} for visitors that do not need an + * additional parameter. + * + * @see Compatibility note for subclasses + * @see ElementScanner6 + * @see ElementScanner7 + * @see ElementScanner8 + * @see ElementScanner9 + * @see ElementScanner14 + * @since 23 + */ +@SupportedSourceVersion(RELEASE_23) +@PreviewFeature(feature=PreviewFeature.Feature.LANGUAGE_MODEL, reflective=true) +public class ElementScannerPreview extends ElementScanner14 { + /** + * Constructor for concrete subclasses; uses {@code null} for the + * default value. + */ + protected ElementScannerPreview(){ + super(null); + } + + /** + * Constructor for concrete subclasses; uses the argument for the + * default value. + * + * @param defaultValue the default value + */ + protected ElementScannerPreview(R defaultValue){ + super(defaultValue); + } +} 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 new file mode 100644 index 00000000000..a16a82a79fb --- /dev/null +++ b/src/java.compiler/share/classes/javax/lang/model/util/SimpleAnnotationValueVisitorPreview.java @@ -0,0 +1,80 @@ +/* + * Copyright (c) 2019, 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. + */ + +package javax.lang.model.util; + +import jdk.internal.javac.PreviewFeature; + +import javax.annotation.processing.SupportedSourceVersion; +import javax.annotation.processing.ProcessingEnvironment; +import javax.lang.model.SourceVersion; +import static javax.lang.model.SourceVersion.*; + +/** + * A simple visitor for annotation values with default behavior + * appropriate for a {@linkplain + * ProcessingEnvironment#isPreviewEnabled preview} source version. + * + * Visit methods call {@link #defaultAction + * defaultAction} passing their arguments to {@code defaultAction}'s + * corresponding parameters. + * + * @apiNote + * Methods in this class may be overridden subject to their general + * contract. + * + * @param the return type of this visitor's methods + * @param

the type of the additional parameter to this visitor's methods. + * + * @see + * Compatibility note for subclasses + * @see SimpleAnnotationValueVisitor6 + * @see SimpleAnnotationValueVisitor7 + * @see SimpleAnnotationValueVisitor8 + * @see SimpleAnnotationValueVisitor9 + * @see SimpleAnnotationValueVisitor14 + * @since 23 + */ +@SupportedSourceVersion(RELEASE_23) +@PreviewFeature(feature=PreviewFeature.Feature.LANGUAGE_MODEL, reflective=true) +public class SimpleAnnotationValueVisitorPreview extends SimpleAnnotationValueVisitor14 { + /** + * Constructor for concrete subclasses; uses {@code null} for the + * default value. + */ + protected SimpleAnnotationValueVisitorPreview() { + super(null); + } + + /** + * Constructor for concrete subclasses; uses the argument for the + * default value. + * + * @param defaultValue the value to assign to {@link #DEFAULT_VALUE} + */ + protected SimpleAnnotationValueVisitorPreview(R defaultValue) { + super(defaultValue); + } +} 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 new file mode 100644 index 00000000000..02c2d78daed --- /dev/null +++ b/src/java.compiler/share/classes/javax/lang/model/util/SimpleElementVisitorPreview.java @@ -0,0 +1,85 @@ +/* + * Copyright (c) 2019, 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. + */ + +package javax.lang.model.util; + +import jdk.internal.javac.PreviewFeature; + +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.*; + +/** + * A simple visitor of program elements with default behavior + * appropriate for a {@linkplain + * ProcessingEnvironment#isPreviewEnabled preview} source version. + * + * Visit methods corresponding to {@code RELEASE_14} and earlier + * language constructs call {@link #defaultAction defaultAction}, + * passing their arguments to {@code defaultAction}'s corresponding + * parameters. + * + * @apiNote + * Methods in this class may be overridden subject to their general + * contract. + * + * @param the return type of this visitor's methods. Use {@code Void} + * for visitors that do not need to return results. + * @param

the type of the additional parameter to this visitor's methods. Use {@code Void} + * for visitors that do not need an additional parameter. + * + * @see + * Compatibility note for subclasses + * @see SimpleElementVisitor6 + * @see SimpleElementVisitor7 + * @see SimpleElementVisitor8 + * @see SimpleElementVisitor9 + * @see SimpleElementVisitor14 + * @since 23 + */ +@SupportedSourceVersion(RELEASE_23) +@PreviewFeature(feature=PreviewFeature.Feature.LANGUAGE_MODEL, reflective=true) +public class SimpleElementVisitorPreview extends SimpleElementVisitor14 { + /** + * Constructor for concrete subclasses; uses {@code null} for the + * default value. + */ + protected SimpleElementVisitorPreview(){ + super(null); + } + + /** + * Constructor for concrete subclasses; uses the argument for the + * default value. + * + * @param defaultValue the value to assign to {@link #DEFAULT_VALUE} + */ + protected SimpleElementVisitorPreview(R defaultValue){ + super(defaultValue); + } +} 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 new file mode 100644 index 00000000000..bac2e2a87a1 --- /dev/null +++ b/src/java.compiler/share/classes/javax/lang/model/util/SimpleTypeVisitorPreview.java @@ -0,0 +1,84 @@ +/* + * Copyright (c) 2019, 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. + */ + +package javax.lang.model.util; + +import jdk.internal.javac.PreviewFeature; + +import javax.annotation.processing.SupportedSourceVersion; +import javax.annotation.processing.ProcessingEnvironment; +import javax.lang.model.SourceVersion; +import static javax.lang.model.SourceVersion.*; + +/** + * A simple visitor of types with default behavior appropriate for a + * {@linkplain ProcessingEnvironment#isPreviewEnabled preview} source + * version. + * + * Visit methods corresponding to {@code RELEASE_14} and earlier + * language constructs call {@link #defaultAction defaultAction}, + * passing their arguments to {@code defaultAction}'s corresponding + * parameters. + * + * @apiNote + * Methods in this class may be overridden subject to their general + * contract. + * + * @param the return type of this visitor's methods. Use {@link + * Void} for visitors that do not need to return results. + * @param

the type of the additional parameter to this visitor's + * methods. Use {@code Void} for visitors that do not need an + * additional parameter. + * + * @see + * Compatibility note for subclasses + * @see SimpleTypeVisitor6 + * @see SimpleTypeVisitor7 + * @see SimpleTypeVisitor8 + * @see SimpleTypeVisitor9 + * @see SimpleTypeVisitor14 + * @since 23 + */ +@SupportedSourceVersion(RELEASE_23) +@PreviewFeature(feature=PreviewFeature.Feature.LANGUAGE_MODEL, reflective=true) +public class SimpleTypeVisitorPreview extends SimpleTypeVisitor14 { + /** + * Constructor for concrete subclasses; uses {@code null} for the + * default value. + */ + protected SimpleTypeVisitorPreview(){ + super(null); + } + + /** + * Constructor for concrete subclasses; uses the argument for the + * default value. + * + * @param defaultValue the value to assign to {@link #DEFAULT_VALUE} + */ + protected SimpleTypeVisitorPreview(R defaultValue){ + super(defaultValue); + } +} 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 new file mode 100644 index 00000000000..b1458706091 --- /dev/null +++ b/src/java.compiler/share/classes/javax/lang/model/util/TypeKindVisitorPreview.java @@ -0,0 +1,88 @@ +/* + * Copyright (c) 2019, 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. + */ + +package javax.lang.model.util; + +import jdk.internal.javac.PreviewFeature; + +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.*; + +/** + * A visitor of types based on their {@linkplain TypeKind kind} with + * default behavior appropriate for a {@linkplain + * ProcessingEnvironment#isPreviewEnabled preview} source version. + * + * For {@linkplain + * TypeMirror types} Xyz that may have more than one + * kind, the visitXyz methods in this class delegate + * to the visitXyzAsKind method corresponding to the + * first argument's kind. The visitXyzAsKind methods + * call {@link #defaultAction defaultAction}, passing their arguments + * to {@code defaultAction}'s corresponding parameters. + * + * @apiNote + * Methods in this class may be overridden subject to their general + * contract. + * + * @param the return type of this visitor's methods. Use {@link + * Void} for visitors that do not need to return results. + * @param

the type of the additional parameter to this visitor's + * methods. Use {@code Void} for visitors that do not need an + * additional parameter. + * + * @see + * Compatibility note for subclasses + * @see TypeKindVisitor6 + * @see TypeKindVisitor7 + * @see TypeKindVisitor8 + * @see TypeKindVisitor9 + * @see TypeKindVisitor14 + * @since 23 + */ +@SupportedSourceVersion(RELEASE_23) +@PreviewFeature(feature=PreviewFeature.Feature.LANGUAGE_MODEL, reflective=true) +public class TypeKindVisitorPreview extends TypeKindVisitor14 { + /** + * Constructor for concrete subclasses to call; uses {@code null} + * for the default value. + */ + protected TypeKindVisitorPreview() { + super(null); + } + + /** + * Constructor for concrete subclasses to call; uses the argument + * for the default value. + * + * @param defaultValue the value to assign to {@link #DEFAULT_VALUE} + */ + protected TypeKindVisitorPreview(R defaultValue) { + super(defaultValue); + } +} diff --git a/src/java.desktop/share/classes/javax/swing/text/StyleContext.java b/src/java.desktop/share/classes/javax/swing/text/StyleContext.java index e01703ea35f..67508a314cc 100644 --- a/src/java.desktop/share/classes/javax/swing/text/StyleContext.java +++ b/src/java.desktop/share/classes/javax/swing/text/StyleContext.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 @@ -44,7 +44,6 @@ import java.util.Hashtable; import java.util.Map; import java.util.NoSuchElementException; -import java.util.Vector; import java.util.WeakHashMap; import javax.swing.SwingUtilities; @@ -212,10 +211,9 @@ public Font getFont(AttributeSet attr) { String family = StyleConstants.getFontFamily(attr); int size = StyleConstants.getFontSize(attr); - /** - * if either superscript or subscript is - * is set, we need to reduce the font size - * by 2. + /* + * If either superscript or subscript is set, + * we need to reduce the font size by 2. */ if (StyleConstants.isSuperscript(attr) || StyleConstants.isSubscript(attr)) { @@ -763,7 +761,6 @@ private void readObject(ObjectInputStream s) throw new InvalidObjectException("Null styles"); } styles = newStyles; - unusedSets = f.get("unusedSets", 0); } // --- variables --------------------------------------------------- @@ -785,14 +782,6 @@ private void readObject(ObjectInputStream s) synchronizedMap(new WeakHashMap>()); private transient MutableAttributeSet search = new SimpleAttributeSet(); - /** - * Number of immutable sets that are not currently - * being used. This helps indicate when the sets need - * to be cleaned out of the hashtable they are stored - * in. - */ - private int unusedSets; - /** * The threshold for no longer sharing the set of attributes * in an immutable table. @@ -1055,7 +1044,7 @@ public AttributeSet getResolveParent() { /** * An enumeration of the keys in a SmallAttributeSet. */ - static class KeyEnumeration implements Enumeration { + static final class KeyEnumeration implements Enumeration { KeyEnumeration(Object[] attr) { this.attr = attr; @@ -1093,149 +1082,10 @@ public Object nextElement() { int i; } - /** - * Sorts the key strings so that they can be very quickly compared - * in the attribute set searches. - */ - static class KeyBuilder { - - public void initialize(AttributeSet a) { - if (a instanceof SmallAttributeSet) { - initialize(((SmallAttributeSet)a).attributes); - } else { - keys.removeAllElements(); - data.removeAllElements(); - Enumeration names = a.getAttributeNames(); - while (names.hasMoreElements()) { - Object name = names.nextElement(); - addAttribute(name, a.getAttribute(name)); - } - } - } - - /** - * Initialize with a set of already sorted - * keys (data from an existing SmallAttributeSet). - */ - private void initialize(Object[] sorted) { - keys.removeAllElements(); - data.removeAllElements(); - int n = sorted.length; - for (int i = 0; i < n; i += 2) { - keys.addElement(sorted[i]); - data.addElement(sorted[i+1]); - } - } - - /** - * Creates a table of sorted key/value entries - * suitable for creation of an instance of - * SmallAttributeSet. - */ - public Object[] createTable() { - int n = keys.size(); - Object[] tbl = new Object[2 * n]; - for (int i = 0; i < n; i ++) { - int offs = 2 * i; - tbl[offs] = keys.elementAt(i); - tbl[offs + 1] = data.elementAt(i); - } - return tbl; - } - - /** - * The number of key/value pairs contained - * in the current key being forged. - */ - int getCount() { - return keys.size(); - } - - /** - * Adds a key/value to the set. - */ - public void addAttribute(Object key, Object value) { - keys.addElement(key); - data.addElement(value); - } - - /** - * Adds a set of key/value pairs to the set. - */ - public void addAttributes(AttributeSet attr) { - if (attr instanceof SmallAttributeSet) { - // avoid searching the keys, they are already interned. - Object[] tbl = ((SmallAttributeSet)attr).attributes; - int n = tbl.length; - for (int i = 0; i < n; i += 2) { - addAttribute(tbl[i], tbl[i+1]); - } - } else { - Enumeration names = attr.getAttributeNames(); - while (names.hasMoreElements()) { - Object name = names.nextElement(); - addAttribute(name, attr.getAttribute(name)); - } - } - } - - /** - * Removes the given name from the set. - */ - public void removeAttribute(Object key) { - int n = keys.size(); - for (int i = 0; i < n; i++) { - if (keys.elementAt(i).equals(key)) { - keys.removeElementAt(i); - data.removeElementAt(i); - return; - } - } - } - - /** - * Removes the set of keys from the set. - */ - public void removeAttributes(Enumeration names) { - while (names.hasMoreElements()) { - Object name = names.nextElement(); - removeAttribute(name); - } - } - - /** - * Removes the set of matching attributes from the set. - */ - public void removeAttributes(AttributeSet attr) { - Enumeration names = attr.getAttributeNames(); - while (names.hasMoreElements()) { - Object name = names.nextElement(); - Object value = attr.getAttribute(name); - removeSearchAttribute(name, value); - } - } - - private void removeSearchAttribute(Object ikey, Object value) { - int n = keys.size(); - for (int i = 0; i < n; i++) { - if (keys.elementAt(i).equals(ikey)) { - if (data.elementAt(i).equals(value)) { - keys.removeElementAt(i); - data.removeElementAt(i); - } - return; - } - } - } - - private Vector keys = new Vector(); - private Vector data = new Vector(); - } - /** * key for a font table */ - static class FontKey { + static final class FontKey { private String family; private int style; diff --git a/src/java.desktop/share/native/libawt/awt/image/gif/gifdecoder.c b/src/java.desktop/share/native/libawt/awt/image/gif/gifdecoder.c index 502bb1640f5..02b10bef76f 100644 --- a/src/java.desktop/share/native/libawt/awt/image/gif/gifdecoder.c +++ b/src/java.desktop/share/native/libawt/awt/image/gif/gifdecoder.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1995, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1995, 2024, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -82,19 +82,6 @@ if (rasline) \ if (block) \ (*env)->ReleasePrimitiveArrayCritical(env, blockh, block, 0) -/* Place holders for the old native interface. */ - -long -sun_awt_image_GifImageDecoder_parseImage() -{ - return 0; -} - -void -sun_awt_image_GifImageDecoder_initIDs() -{ -} - static jmethodID readID; static jmethodID sendID; static jfieldID prefixID; diff --git a/src/java.desktop/share/native/libawt/awt/image/imageInitIDs.h b/src/java.desktop/share/native/libawt/awt/image/imageInitIDs.h index 62c52450f55..c1c7a61680a 100644 --- a/src/java.desktop/share/native/libawt/awt/image/imageInitIDs.h +++ b/src/java.desktop/share/native/libawt/awt/image/imageInitIDs.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2022, 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 @@ -42,7 +42,6 @@ IMGEXTERN jmethodID g_BImgSetRGBMID; /* Raster ids */ IMGEXTERN jfieldID g_RasterWidthID; IMGEXTERN jfieldID g_RasterHeightID; -IMGEXTERN jfieldID g_RasterBaseRasterID; IMGEXTERN jfieldID g_RasterMinXID; IMGEXTERN jfieldID g_RasterMinYID; IMGEXTERN jfieldID g_RasterBaseOriginXID; diff --git a/src/java.desktop/windows/classes/sun/awt/shell/Win32ShellFolderManager2.java b/src/java.desktop/windows/classes/sun/awt/shell/Win32ShellFolderManager2.java index c75d7738144..20df99eb7d6 100644 --- a/src/java.desktop/windows/classes/sun/awt/shell/Win32ShellFolderManager2.java +++ b/src/java.desktop/windows/classes/sun/awt/shell/Win32ShellFolderManager2.java @@ -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 @@ -522,7 +522,7 @@ static int compareShellFolders(Win32ShellFolder2 sf1, Win32ShellFolder2 sf2) { boolean special1 = sf1.isSpecial(); boolean special2 = sf2.isSpecial(); - if (special1 || special2) { + if (special1 && special2) { if (topFolderList == null) { ArrayList tmpTopFolderList = new ArrayList<>(); tmpTopFolderList.add(Win32ShellFolderManager2.getPersonal()); diff --git a/src/java.desktop/windows/native/libawt/java2d/d3d/D3DGlyphCache.cpp b/src/java.desktop/windows/native/libawt/java2d/d3d/D3DGlyphCache.cpp index cc72e66f146..39f58d6340f 100644 --- a/src/java.desktop/windows/native/libawt/java2d/d3d/D3DGlyphCache.cpp +++ b/src/java.desktop/windows/native/libawt/java2d/d3d/D3DGlyphCache.cpp @@ -27,7 +27,7 @@ #include "D3DTextRenderer.h" #include "D3DRenderQueue.h" -void D3DGlyphCache_FlushGlyphVertexCache(); +static void D3DGlyphCache_FlushGlyphVertexCache(); // static HRESULT diff --git a/src/java.desktop/windows/native/libawt/java2d/windows/GDIRenderer.cpp b/src/java.desktop/windows/native/libawt/java2d/windows/GDIRenderer.cpp index 835911e1fff..bea2b07e08f 100644 --- a/src/java.desktop/windows/native/libawt/java2d/windows/GDIRenderer.cpp +++ b/src/java.desktop/windows/native/libawt/java2d/windows/GDIRenderer.cpp @@ -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 @@ -877,20 +877,6 @@ Java_sun_java2d_windows_GDIRenderer_doShape } /* extern "C" */ -INLINE BOOL RectInMonitorRect(RECT *rCheck, RECT *rContainer) -{ - // Assumption: left <= right, top <= bottom - if (rCheck->left >= rContainer->left && - rCheck->right <= rContainer->right && - rCheck->top >= rContainer->top && - rCheck->bottom <= rContainer->bottom) - { - return TRUE; - } else { - return FALSE; - } -} - /* * Class: sun_java2d_windows_GDIRenderer * Method: devCopyArea diff --git a/src/java.desktop/windows/native/libawt/java2d/windows/GDIWindowSurfaceData.cpp b/src/java.desktop/windows/native/libawt/java2d/windows/GDIWindowSurfaceData.cpp index 6dae331f88f..2489ac21952 100644 --- a/src/java.desktop/windows/native/libawt/java2d/windows/GDIWindowSurfaceData.cpp +++ b/src/java.desktop/windows/native/libawt/java2d/windows/GDIWindowSurfaceData.cpp @@ -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 @@ -253,44 +253,6 @@ __inline HDC GetThreadDC(JNIEnv *env, GDIWinSDOps *wsdo) { * code. */ -static BOOL GDIWinSD_CheckMonitorArea(GDIWinSDOps *wsdo, - SurfaceDataBounds *bounds, - HDC hDC) -{ - HWND hW = wsdo->window; - BOOL retCode = TRUE; - - J2dTraceLn(J2D_TRACE_INFO, "GDIWinSD_CheckMonitorArea"); - int numScreens; - { - Devices::InstanceAccess devices; - numScreens = devices->GetNumDevices(); - } - if( numScreens > 1 ) { - - LPMONITORINFO miInfo; - RECT rSect ={0,0,0,0}; - RECT rView ={bounds->x1, bounds->y1, bounds->x2, bounds->y2}; - retCode = FALSE; - - miInfo = wsdo->device->GetMonitorInfo(); - - POINT ptOrig = {0, 0}; - ::ClientToScreen(hW, &ptOrig); - ::OffsetRect(&rView, - (ptOrig.x), (ptOrig.y)); - - ::IntersectRect(&rSect,&rView,&(miInfo->rcMonitor)); - - if( FALSE == ::IsRectEmpty(&rSect) ) { - if( TRUE == ::EqualRect(&rSect,&rView) ) { - retCode = TRUE; - } - } - } - return retCode; -} - extern "C" { void @@ -552,111 +514,6 @@ GDIWindowSurfaceData_GetWindow(JNIEnv *env, GDIWinSDOps *wsdo) } /* extern "C" */ -static jboolean GDIWinSD_SimpleClip(JNIEnv *env, GDIWinSDOps *wsdo, - SurfaceDataBounds *bounds, - HDC hDC) -{ - RECT rClip; - - J2dTraceLn(J2D_TRACE_INFO, "GDIWinSD_SimpleClip"); - if (hDC == NULL) { - return JNI_FALSE; - } - - int nComplexity = ::GetClipBox(hDC, &rClip); - - switch (nComplexity) { - case COMPLEXREGION: - { - J2dTraceLn(J2D_TRACE_VERBOSE, - " complex clipping region"); - // if complex user/system clip, more detailed testing required - // check to see if the view itself has a complex clip. - // ::GetClipBox is only API which returns overlapped window status - // so we set the rView as our clip, and then see if resulting - // clip is complex. - // Only other way to figure this out would be to walk the - // overlapping windows (no API to get the actual visible clip - // list). Then we'd still have to merge that info with the - // clip region for the dc (if it exists). - // REMIND: we can cache the CreateRectRgnIndirect result, - // and only override with ::SetRectRgn - - // First, create a region handle (need existing HRGN for - // the following call). - HRGN rgnSave = ::CreateRectRgn(0, 0, 0, 0); - int clipStatus = ::GetClipRgn(hDC, rgnSave); - if (-1 == clipStatus) { - J2dTraceLn(J2D_TRACE_WARNING, - "GDIWinSD_SimpleClip: failed due to clip status"); - ::DeleteObject(rgnSave); - return JNI_FALSE; - } - HRGN rgnBounds = ::CreateRectRgn( - bounds->x1 - wsdo->insets.left, - bounds->y1 - wsdo->insets.top, - bounds->x2 - wsdo->insets.left, - bounds->y2 - wsdo->insets.top); - ::SelectClipRgn(hDC, rgnBounds); - nComplexity = ::GetClipBox(hDC, &rClip); - ::SelectClipRgn(hDC, clipStatus? rgnSave: NULL); - ::DeleteObject(rgnSave); - ::DeleteObject(rgnBounds); - - // Now, test the new clip box. If it's still not a - // SIMPLE region, then our bounds must intersect part of - // the clipping article - if (SIMPLEREGION != nComplexity) { - J2dTraceLn(J2D_TRACE_WARNING, - "GDIWinSD_SimpleClip: failed due to complexity"); - return JNI_FALSE; - } - } - // NOTE: No break here - we want to fall through into the - // SIMPLE case, adjust our bounds by the new rClip rect - // and make sure that our locking bounds are not empty. - case SIMPLEREGION: - J2dTraceLn(J2D_TRACE_VERBOSE, " simple clipping region"); - // Constrain the bounds to the given clip box - if (bounds->x1 < rClip.left) { - bounds->x1 = rClip.left; - } - if (bounds->y1 < rClip.top) { - bounds->y1 = rClip.top; - } - if (bounds->x2 > rClip.right) { - bounds->x2 = rClip.right; - } - if (bounds->y2 > rClip.bottom) { - bounds->y2 = rClip.bottom; - } - // If the bounds are 0 or negative, then the bounds have - // been obscured by the clip box, so return FALSE - if ((bounds->x2 <= bounds->x1) || - (bounds->y2 <= bounds->y1)) { - // REMIND: We should probably do something different here - // instead of simply returning FALSE. Since the bounds are - // empty we won't end up drawing anything, so why spend the - // effort of returning false and having GDI do a LOCK_BY_DIB? - // Perhaps we need a new lock code that will indicate that we - // shouldn't bother drawing? - J2dTraceLn(J2D_TRACE_WARNING, - "GDIWinSD_SimpleClip: failed due to empty bounds"); - return JNI_FALSE; - } - break; - case NULLREGION: - case ERROR: - default: - J2dTraceLn1(J2D_TRACE_ERROR, - "GDIWinSD_SimpleClip: failed due to incorrect complexity=%d", - nComplexity); - return JNI_FALSE; - } - - return JNI_TRUE; -} - static jint GDIWinSD_Lock(JNIEnv *env, SurfaceDataOps *ops, SurfaceDataRasInfo *pRasInfo, diff --git a/src/java.desktop/windows/native/libawt/windows/WPrinterJob.cpp b/src/java.desktop/windows/native/libawt/windows/WPrinterJob.cpp index 16b20afd030..245a4749950 100644 --- a/src/java.desktop/windows/native/libawt/windows/WPrinterJob.cpp +++ b/src/java.desktop/windows/native/libawt/windows/WPrinterJob.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 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 @@ -44,27 +44,6 @@ static const char *HPRINTER_STR = "hPrintJob"; #define PAPERNAME_LENGTH 64 #define TRAYNAME_LENGTH 24 - -static BOOL IsSupportedLevel(HANDLE hPrinter, DWORD dwLevel) { - BOOL isSupported = FALSE; - DWORD cbBuf = 0; - LPBYTE pPrinter = NULL; - - DASSERT(hPrinter != NULL); - - VERIFY(::GetPrinter(hPrinter, dwLevel, NULL, 0, &cbBuf) == 0); - if (::GetLastError() == ERROR_INSUFFICIENT_BUFFER) { - pPrinter = new BYTE[cbBuf]; - if (::GetPrinter(hPrinter, dwLevel, pPrinter, cbBuf, &cbBuf)) { - isSupported = TRUE; - } - delete[] pPrinter; - } - - return isSupported; -} - - extern "C" { JNIEXPORT jstring JNICALL diff --git a/src/java.desktop/windows/native/libawt/windows/awt.h b/src/java.desktop/windows/native/libawt/windows/awt.h index 708307fc51b..3703bfbb0cb 100644 --- a/src/java.desktop/windows/native/libawt/windows/awt.h +++ b/src/java.desktop/windows/native/libawt/windows/awt.h @@ -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 @@ -252,41 +252,6 @@ extern JavaVM *jvm; #endif -struct EnvHolder -{ - JavaVM *m_pVM; - JNIEnv *m_env; - bool m_isOwner; - EnvHolder( - JavaVM *pVM, - LPCSTR name = "COM holder", - jint ver = JNI_VERSION_1_2) - : m_pVM(pVM), - m_env((JNIEnv *)JNU_GetEnv(pVM, ver)), - m_isOwner(false) - { - if (NULL == m_env) { - JavaVMAttachArgs attachArgs; - attachArgs.version = ver; - attachArgs.name = const_cast(name); - attachArgs.group = NULL; - jint status = m_pVM->AttachCurrentThread( - (void**)&m_env, - &attachArgs); - m_isOwner = (NULL!=m_env); - } - } - ~EnvHolder() { - if (m_isOwner) { - m_pVM->DetachCurrentThread(); - } - } - operator bool() const { return NULL!=m_env; } - bool operator !() const { return NULL==m_env; } - operator JNIEnv*() const { return m_env; } - JNIEnv* operator ->() const { return m_env; } -}; - template class JLocalRef { JNIEnv* m_env; diff --git a/src/java.desktop/windows/native/libawt/windows/awt_Canvas.cpp b/src/java.desktop/windows/native/libawt/windows/awt_Canvas.cpp index a152b8ebbd7..55a0b0f4207 100644 --- a/src/java.desktop/windows/native/libawt/windows/awt_Canvas.cpp +++ b/src/java.desktop/windows/native/libawt/windows/awt_Canvas.cpp @@ -206,19 +206,31 @@ void AwtCanvas::_SetEraseBackground(void *param) { JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2); - SetEraseBackgroundStruct *sebs = (SetEraseBackgroundStruct *)param; + SetEraseBackgroundStruct *sebs = static_cast(param); jobject canvas = sebs->canvas; jboolean doErase = sebs->doErase; jboolean doEraseOnResize = sebs->doEraseOnResize; - PDATA pData; - JNI_CHECK_PEER_GOTO(canvas, ret); + AwtCanvas *c = NULL; + + if (canvas == NULL) { + env->ExceptionClear(); + JNU_ThrowNullPointerException(env, "canvas"); + delete sebs; + return; + } else { + c = (AwtCanvas*)JNI_GET_PDATA(canvas); + if (c == NULL) { + THROW_NULL_PDATA_IF_NOT_DESTROYED(canvas); + env->DeleteGlobalRef(canvas); + delete sebs; + return; + } + } - AwtCanvas *c = (AwtCanvas*)pData; c->m_eraseBackground = doErase; c->m_eraseBackgroundOnResize = doEraseOnResize; -ret: env->DeleteGlobalRef(canvas); delete sebs; } diff --git a/src/java.desktop/windows/native/libawt/windows/awt_Component.cpp b/src/java.desktop/windows/native/libawt/windows/awt_Component.cpp index b9e55848f75..4f87e8ef4c1 100644 --- a/src/java.desktop/windows/native/libawt/windows/awt_Component.cpp +++ b/src/java.desktop/windows/native/libawt/windows/awt_Component.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2023, 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 @@ -80,7 +80,6 @@ LPCTSTR szAwtComponentClassName = TEXT("SunAwtComponent"); const UINT AwtComponent::WmAwtIsComponent = ::RegisterWindowMessage(szAwtComponentClassName); -static HWND g_hwndDown = NULL; static DCList activeDCList; static DCList passiveDCList; @@ -198,10 +197,6 @@ UINT AwtComponent::m_CodePage jint *AwtComponent::masks; -static BOOL bLeftShiftIsDown = false; -static BOOL bRightShiftIsDown = false; -static UINT lastShiftKeyPressed = 0; // init to safe value - // Added by waleed to initialize the RTL Flags BOOL AwtComponent::sm_rtl = PRIMARYLANGID(GetInputLanguage()) == LANG_ARABIC || PRIMARYLANGID(GetInputLanguage()) == LANG_HEBREW; @@ -1292,23 +1287,16 @@ void SpyWinMessage(HWND hwnd, UINT message, LPCTSTR szComment) { WIN_MSG(WM_AWT_WINDOW_SETACTIVE) WIN_MSG(WM_AWT_LIST_SETMULTISELECT) WIN_MSG(WM_AWT_HANDLE_EVENT) - WIN_MSG(WM_AWT_PRINT_COMPONENT) WIN_MSG(WM_AWT_RESHAPE_COMPONENT) WIN_MSG(WM_AWT_SETALWAYSONTOP) WIN_MSG(WM_AWT_BEGIN_VALIDATE) WIN_MSG(WM_AWT_END_VALIDATE) WIN_MSG(WM_AWT_FORWARD_CHAR) - WIN_MSG(WM_AWT_FORWARD_BYTE) - WIN_MSG(WM_AWT_SET_SCROLL_INFO) WIN_MSG(WM_AWT_CREATECONTEXT) WIN_MSG(WM_AWT_DESTROYCONTEXT) WIN_MSG(WM_AWT_ASSOCIATECONTEXT) WIN_MSG(WM_AWT_GET_DEFAULT_IME_HANDLER) WIN_MSG(WM_AWT_HANDLE_NATIVE_IME_EVENT) - WIN_MSG(WM_AWT_PRE_KEYDOWN) - WIN_MSG(WM_AWT_PRE_KEYUP) - WIN_MSG(WM_AWT_PRE_SYSKEYDOWN) - WIN_MSG(WM_AWT_PRE_SYSKEYUP) WIN_MSG(WM_AWT_ENDCOMPOSITION,) WIN_MSG(WM_AWT_DISPOSE,) WIN_MSG(WM_AWT_DELETEOBJECT,) @@ -1320,17 +1308,12 @@ void SpyWinMessage(HWND hwnd, UINT message, LPCTSTR szComment) { WIN_MSG(WM_AWT_OPENCANDIDATEWINDOW) WIN_MSG(WM_AWT_DLG_SHOWMODAL,) WIN_MSG(WM_AWT_DLG_ENDMODAL,) - WIN_MSG(WM_AWT_SETCURSOR,) WIN_MSG(WM_AWT_WAIT_FOR_SINGLE_OBJECT,) WIN_MSG(WM_AWT_INVOKE_METHOD,) WIN_MSG(WM_AWT_INVOKE_VOID_METHOD,) - WIN_MSG(WM_AWT_EXECUTE_SYNC,) - WIN_MSG(WM_AWT_CURSOR_SYNC) WIN_MSG(WM_AWT_GETDC) WIN_MSG(WM_AWT_RELEASEDC) WIN_MSG(WM_AWT_RELEASE_ALL_DCS) - WIN_MSG(WM_AWT_SHOWCURSOR) - WIN_MSG(WM_AWT_HIDECURSOR) WIN_MSG(WM_AWT_CREATE_PRINTED_PIXELS) WIN_MSG(WM_AWT_OBJECTLISTCLEANUP) default: @@ -1417,12 +1400,6 @@ LRESULT AwtComponent::WindowProc(UINT message, WPARAM wParam, LPARAM lParam) mr = mrConsume; break; } - case WM_AWT_SHOWCURSOR: - ::ShowCursor(TRUE); - break; - case WM_AWT_HIDECURSOR: - ::ShowCursor(FALSE); - break; case WM_CREATE: mr = WmCreate(); break; case WM_CLOSE: mr = WmClose(); break; case WM_DESTROY: mr = WmDestroy(); break; @@ -1840,10 +1817,6 @@ LRESULT AwtComponent::WindowProc(UINT message, WPARAM wParam, LPARAM lParam) mr = WmForwardChar(LOWORD(wParam), lParam, HIWORD(wParam)); break; - case WM_AWT_FORWARD_BYTE: - mr = HandleEvent( (MSG *) lParam, (BOOL) wParam); - break; - case WM_PASTE: mr = WmPaste(); break; @@ -1976,13 +1949,6 @@ LRESULT AwtComponent::WindowProc(UINT message, WPARAM wParam, LPARAM lParam) mr = mrConsume; break; - case WM_AWT_SET_SCROLL_INFO: { - SCROLLINFO *si = (SCROLLINFO *) lParam; - ::SetScrollInfo(GetHWnd(), (int) wParam, si, TRUE); - delete si; - mr = mrConsume; - break; - } case WM_AWT_CREATE_PRINTED_PIXELS: { CreatePrintedPixelsStruct* cpps = (CreatePrintedPixelsStruct*)wParam; SIZE loc = { cpps->srcx, cpps->srcy }; @@ -5233,89 +5199,6 @@ AwtComponent::SendMouseWheelEvent(jint id, jlong when, jint x, jint y, env->DeleteLocalRef(target); } -void AwtComponent::SendFocusEvent(jint id, HWND opposite) -{ - JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2); - - CriticalSection::Lock l(GetLock()); - if (GetPeer(env) == NULL) { - /* event received during termination. */ - return; - } - - static jclass focusEventCls; - if (focusEventCls == NULL) { - jclass focusEventClsLocal - = env->FindClass("java/awt/event/FocusEvent"); - DASSERT(focusEventClsLocal); - CHECK_NULL(focusEventClsLocal); - focusEventCls = (jclass)env->NewGlobalRef(focusEventClsLocal); - env->DeleteLocalRef(focusEventClsLocal); - } - - static jmethodID focusEventConst; - if (focusEventConst == NULL) { - focusEventConst = - env->GetMethodID(focusEventCls, "", - "(Ljava/awt/Component;IZLjava/awt/Component;)V"); - DASSERT(focusEventConst); - CHECK_NULL(focusEventConst); - } - - static jclass sequencedEventCls; - if (sequencedEventCls == NULL) { - jclass sequencedEventClsLocal = - env->FindClass("java/awt/SequencedEvent"); - DASSERT(sequencedEventClsLocal); - CHECK_NULL(sequencedEventClsLocal); - sequencedEventCls = - (jclass)env->NewGlobalRef(sequencedEventClsLocal); - env->DeleteLocalRef(sequencedEventClsLocal); - } - - static jmethodID sequencedEventConst; - if (sequencedEventConst == NULL) { - sequencedEventConst = - env->GetMethodID(sequencedEventCls, "", - "(Ljava/awt/AWTEvent;)V"); - DASSERT(sequencedEventConst); - CHECK_NULL(sequencedEventConst); - } - - if (env->EnsureLocalCapacity(3) < 0) { - return; - } - - jobject target = GetTarget(env); - jobject jOpposite = NULL; - if (opposite != NULL) { - AwtComponent *awtOpposite = AwtComponent::GetComponent(opposite); - if (awtOpposite != NULL) { - jOpposite = awtOpposite->GetTarget(env); - } - } - jobject focusEvent = env->NewObject(focusEventCls, focusEventConst, - target, id, JNI_FALSE, jOpposite); - DASSERT(!safe_ExceptionOccurred(env)); - DASSERT(focusEvent != NULL); - if (jOpposite != NULL) { - env->DeleteLocalRef(jOpposite); jOpposite = NULL; - } - env->DeleteLocalRef(target); target = NULL; - CHECK_NULL(focusEvent); - - jobject sequencedEvent = env->NewObject(sequencedEventCls, - sequencedEventConst, - focusEvent); - DASSERT(!safe_ExceptionOccurred(env)); - DASSERT(sequencedEvent != NULL); - env->DeleteLocalRef(focusEvent); focusEvent = NULL; - CHECK_NULL(sequencedEvent); - SendEvent(sequencedEvent); - - env->DeleteLocalRef(sequencedEvent); -} - /* * Forward a filtered event directly to the subclassed window. * This method is needed so that DefWindowProc is invoked on the @@ -6360,18 +6243,46 @@ void AwtComponent::_SetParent(void * param) { if (AwtToolkit::IsMainThread()) { JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2); - SetParentStruct *data = (SetParentStruct*) param; + SetParentStruct *data = static_cast(param); jobject self = data->component; jobject parent = data->parentComp; AwtComponent *awtComponent = NULL; AwtComponent *awtParent = NULL; - PDATA pData; - JNI_CHECK_PEER_GOTO(self, ret); - awtComponent = (AwtComponent *)pData; - JNI_CHECK_PEER_GOTO(parent, ret); - awtParent = (AwtComponent *)pData; + if (self == NULL) { + env->ExceptionClear(); + JNU_ThrowNullPointerException(env, "self"); + env->DeleteGlobalRef(parent); + delete data; + return; + } else { + awtComponent = (AwtComponent *)JNI_GET_PDATA(self);; + if (awtComponent == NULL) { + THROW_NULL_PDATA_IF_NOT_DESTROYED(self); + env->DeleteGlobalRef(self); + env->DeleteGlobalRef(parent); + delete data; + return; + } + } + + if (parent == NULL) { + env->ExceptionClear(); + JNU_ThrowNullPointerException(env, "parent"); + env->DeleteGlobalRef(self); + delete data; + return; + } else { + awtParent = (AwtComponent *)JNI_GET_PDATA(parent); + if (awtParent == NULL) { + THROW_NULL_PDATA_IF_NOT_DESTROYED(parent); + env->DeleteGlobalRef(self); + env->DeleteGlobalRef(parent); + delete data; + return; + } + } HWND selfWnd = awtComponent->GetHWnd(); HWND parentWnd = awtParent->GetHWnd(); @@ -6380,7 +6291,7 @@ void AwtComponent::_SetParent(void * param) // (only the proxy may be the native focus owner). ::SetParent(selfWnd, parentWnd); } -ret: + env->DeleteGlobalRef(self); env->DeleteGlobalRef(parent); delete data; @@ -6539,19 +6450,31 @@ static void _GetInsets(void* param) { JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2); - GetInsetsStruct *gis = (GetInsetsStruct *)param; + GetInsetsStruct *gis = static_cast(param); jobject self = gis->window; gis->insets->left = gis->insets->top = gis->insets->right = gis->insets->bottom = 0; - PDATA pData; - JNI_CHECK_PEER_GOTO(self, ret); - AwtComponent *component = (AwtComponent *)pData; + AwtComponent *component = NULL; + + if (self == NULL) { + env->ExceptionClear(); + JNU_ThrowNullPointerException(env, "self"); + delete gis; + return; + } else { + component = (AwtComponent *)JNI_GET_PDATA(self); + if (component == NULL) { + THROW_NULL_PDATA_IF_NOT_DESTROYED(self); + env->DeleteGlobalRef(self); + delete gis; + return; + } + } component->GetInsets(gis->insets); - ret: env->DeleteGlobalRef(self); delete gis; } diff --git a/src/java.desktop/windows/native/libawt/windows/awt_Component.h b/src/java.desktop/windows/native/libawt/windows/awt_Component.h index 47c9b93633e..740eb8c72f9 100644 --- a/src/java.desktop/windows/native/libawt/windows/awt_Component.h +++ b/src/java.desktop/windows/native/libawt/windows/awt_Component.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2020, 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 @@ -402,13 +402,6 @@ class AwtComponent : public AwtObject { jint scrollAmount, jint wheelRotation, jdouble preciseWheelRotation, MSG *msg = NULL); - /* - * Allocate and initialize a new java.awt.event.FocusEvent, and - * post it to the peer's target object. No response is expected - * from the target. - */ - void SendFocusEvent(jint id, HWND opposite); - /* Forward a filtered event directly to the subclassed window. synthetic should be TRUE iff the message was generated because of a synthetic Java event, rather than a native event. */ diff --git a/src/java.desktop/windows/native/libawt/windows/awt_Cursor.cpp b/src/java.desktop/windows/native/libawt/windows/awt_Cursor.cpp index 4a1a4c08131..84f1d3a6d82 100644 --- a/src/java.desktop/windows/native/libawt/windows/awt_Cursor.cpp +++ b/src/java.desktop/windows/native/libawt/windows/awt_Cursor.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2020, 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 @@ -519,7 +519,7 @@ static void GlobalSetCursor(void* pStruct) { } if (!blocked) { - ::SetCursor(hCursor); // don't need WM_AWT_SETCURSOR + ::SetCursor(hCursor); } env->DeleteGlobalRef(((GlobalSetCursorStruct*)pStruct)->cursor); 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 148170b5a9a..9e4b1ff1bf0 100644 --- a/src/java.desktop/windows/native/libawt/windows/awt_Debug.cpp +++ b/src/java.desktop/windows/native/libawt/windows/awt_Debug.cpp @@ -70,60 +70,6 @@ void operator delete(void *ptr) throw() { //////////////////////////////////////////////////////////////////////////////////// -static void DumpRegion(HRGN rgn) { - DWORD size = ::GetRegionData(rgn, 0, NULL); - char* buffer = (char *)safe_Malloc(size); - memset(buffer, 0, size); - LPRGNDATA rgndata = (LPRGNDATA)buffer; - rgndata->rdh.dwSize = sizeof(RGNDATAHEADER); - rgndata->rdh.iType = RDH_RECTANGLES; - VERIFY(::GetRegionData(rgn, size, rgndata)); - - RECT* r = (RECT*)(buffer + rgndata->rdh.dwSize); - for (DWORD i=0; irdh.nCount; i++) { - if ( !::IsRectEmpty(r) ) { - DTrace_PrintImpl("\trect %d %d %d %d\n", r->left, r->top, r->right, r->bottom); - } - r++; - } - - free(buffer); -} - -/* - * DTRACE print callback to dump HDC clip region bounding rectangle - */ -void DumpClipRectangle(const char * file, int line, int argc, const char * fmt, va_list arglist) { - const char *msg = va_arg(arglist, const char *); - HDC hdc = va_arg(arglist, HDC); - RECT r; - - DASSERT(argc == 2 && hdc != NULL); - DASSERT(msg != NULL); - - ::GetClipBox(hdc, &r); - DTrace_PrintImpl("%s: hdc=%x, %d %d %d %d\n", msg, hdc, r.left, r.top, r.right, r.bottom); -} - -/* - * DTRACE print callback to dump window's update region bounding rectangle - */ -void DumpUpdateRectangle(const char * file, int line, int argc, const char * fmt, va_list arglist) { - const char *msg = va_arg(arglist, const char *); - HWND hwnd = va_arg(arglist, HWND); - RECT r; - - DASSERT(argc == 2 && ::IsWindow(hwnd)); - DASSERT(msg != NULL); - - ::GetUpdateRect(hwnd, &r, FALSE); - HRGN rgn = ::CreateRectRgn(0,0,1,1); - int updated = ::GetUpdateRgn(hwnd, rgn, FALSE); - DTrace_PrintImpl("%s: hwnd=%x, %d %d %d %d\n", msg, hwnd, r.left, r.top, r.right, r.bottom); - DumpRegion(rgn); - DeleteObject(rgn); -} - // // Declare a static object to init/fini the debug code // diff --git a/src/java.desktop/windows/native/libawt/windows/awt_Debug.h b/src/java.desktop/windows/native/libawt/windows/awt_Debug.h index a17f569e04a..0b674e7b558 100644 --- a/src/java.desktop/windows/native/libawt/windows/awt_Debug.h +++ b/src/java.desktop/windows/native/libawt/windows/awt_Debug.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2018, 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 @@ -54,14 +54,6 @@ extern void operator delete[](void *ptr, const char*, int); extern void operator delete(void *ptr) throw(); - extern void DumpClipRectangle(const char * file, int line, int argc, const char * fmt, va_list arglist); - extern void DumpUpdateRectangle(const char * file, int line, int argc, const char * fmt, va_list arglist); - - #define AWT_DUMP_UPDATE_RECTANGLE(_msg, _hwnd) \ - _DTrace_Template(DumpUpdateRectangle, 2, "", (_msg), (_hwnd), 0, 0, 0, 0, 0, 0) - - #define AWT_DUMP_CLIP_RECTANGLE(_msg, _hwnd) \ - _DTrace_Template(DumpClipRectangle, 2, "", (_msg), (_hwnd), 0, 0, 0, 0, 0, 0) #define new new(__FILE__, __LINE__) @@ -71,9 +63,6 @@ /* Disable inlining. */ #define INLINE #else - #define AWT_DUMP_UPDATE_RECTANGLE(_msg, _hwnd) ((void)0) - #define AWT_DUMP_CLIP_RECTANGLE(_msg, _hwnd) ((void)0) - #define UNIMPLEMENTED() \ SignalError(0, JAVAPKG "NullPointerException","unimplemented"); diff --git a/src/java.desktop/windows/native/libawt/windows/awt_DnDDS.cpp b/src/java.desktop/windows/native/libawt/windows/awt_DnDDS.cpp index 8146d62c4a7..2c67b65cc41 100644 --- a/src/java.desktop/windows/native/libawt/windows/awt_DnDDS.cpp +++ b/src/java.desktop/windows/native/libawt/windows/awt_DnDDS.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2022, 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 @@ -39,10 +39,15 @@ void * operator new(size_t size) {return operator new(size, "stl", 1);} #pragma pop_macro("bad_alloc") //"bad_alloc" is undefined from here -#include #include +// These files must be included before awt.h, since the latter redefines malloc +// to Do_Not_Use_Malloc, etc, and that will break these files. +#include "awt_ole.h" +#include "awt_DCHolder.h" + #include "jlong.h" +#include "awt.h" #include "awt_DataTransferer.h" #include "awt_DnDDS.h" #include "awt_DnDDT.h" @@ -54,9 +59,6 @@ void * operator new(size_t size) {return operator new(size, "stl", 1);} #include "java_awt_dnd_DnDConstants.h" #include "sun_awt_windows_WDragSourceContextPeer.h" -#include "awt_ole.h" -#include "awt_DCHolder.h" - bool operator < (const FORMATETC &fr, const FORMATETC &fl) { return memcmp(&fr, &fl, sizeof(FORMATETC)) < 0; } @@ -154,7 +156,6 @@ class PictureDragHelper } static const FORMATETC *FindFormat(const FORMATETC &format) { - static FORMATETC fm = {0}; CDataMap::iterator i = st.find(format); if (st.end() != i) { return &i->first; @@ -1266,8 +1267,6 @@ AwtDragSource::call_dSCmouseMoved(JNIEnv* env, jobject self, jint targetActions, } } -DECLARE_JAVA_CLASS(awtIEClazz, "java/awt/event/InputEvent") - /** * Constructor */ diff --git a/src/java.desktop/windows/native/libawt/windows/awt_DnDDS.h b/src/java.desktop/windows/native/libawt/windows/awt_DnDDS.h index 1549ca64210..6b22b46cd7c 100644 --- a/src/java.desktop/windows/native/libawt/windows/awt_DnDDS.h +++ b/src/java.desktop/windows/native/libawt/windows/awt_DnDDS.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2020, 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 @@ -264,7 +264,6 @@ class AwtDragSource : virtual public IDropSource, virtual public IDataObject { // static's ... static jclass dSCClazz; - static jclass awtIEClazz; static jmethodID dSCdragenter; static jmethodID dSCdragmotion; diff --git a/src/java.desktop/windows/native/libawt/windows/awt_DnDDT.cpp b/src/java.desktop/windows/native/libawt/windows/awt_DnDDT.cpp index ccb394bf8b9..b33a45a4b07 100644 --- a/src/java.desktop/windows/native/libawt/windows/awt_DnDDT.cpp +++ b/src/java.desktop/windows/native/libawt/windows/awt_DnDDT.cpp @@ -27,11 +27,13 @@ #include #include +// awt_ole.h must be included before awt.h, since the latter redefines malloc +// to Do_Not_Use_Malloc, etc, and that will break awt_ole.h. +#include "awt_ole.h" #include "awt_DataTransferer.h" #include "java_awt_dnd_DnDConstants.h" #include "sun_awt_windows_WDropTargetContextPeer.h" #include "awt_Container.h" -#include "awt_ole.h" #include "awt_Toolkit.h" #include "awt_DnDDT.h" #include "awt_DnDDS.h" diff --git a/src/java.desktop/windows/native/libawt/windows/awt_Frame.cpp b/src/java.desktop/windows/native/libawt/windows/awt_Frame.cpp index 8876a5a8d98..9ca12aa5802 100644 --- a/src/java.desktop/windows/native/libawt/windows/awt_Frame.cpp +++ b/src/java.desktop/windows/native/libawt/windows/awt_Frame.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2020, 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 @@ -1264,7 +1264,7 @@ LRESULT AwtFrame::WinThreadExecProc(ExecuteArgs * args) } default: - AwtWindow::WinThreadExecProc(args); + DASSERT(FALSE); break; } @@ -1340,15 +1340,27 @@ void AwtFrame::_SetState(void *param) { JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2); - SetStateStruct *sss = (SetStateStruct *)param; + SetStateStruct *sss = static_cast(param); jobject self = sss->frame; jint state = sss->state; AwtFrame *f = NULL; - PDATA pData; - JNI_CHECK_PEER_GOTO(self, ret); - f = (AwtFrame *)pData; + if (self == NULL) { + env->ExceptionClear(); + JNU_ThrowNullPointerException(env, "self"); + delete sss; + return; + } else { + f = (AwtFrame *)JNI_GET_PDATA(self); + if (f == NULL) { + THROW_NULL_PDATA_IF_NOT_DESTROYED(self); + env->DeleteGlobalRef(self); + delete sss; + return; + } + } + HWND hwnd = f->GetHWnd(); if (::IsWindow(hwnd)) { @@ -1405,7 +1417,7 @@ void AwtFrame::_SetState(void *param) f->setZoomed(zoom); } } -ret: + env->DeleteGlobalRef(self); delete sss; @@ -1569,21 +1581,59 @@ void AwtFrame::_NotifyModalBlocked(void *param) { JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2); - NotifyModalBlockedStruct *nmbs = (NotifyModalBlockedStruct *)param; + NotifyModalBlockedStruct *nmbs = static_cast(param); jobject self = nmbs->frame; jobject peer = nmbs->peer; jobject blockerPeer = nmbs->blockerPeer; jboolean blocked = nmbs->blocked; - PDATA pData; + AwtFrame *f = NULL; - JNI_CHECK_PEER_GOTO(peer, ret); - AwtFrame *f = (AwtFrame *)pData; + if (peer == NULL) { + env->ExceptionClear(); + JNU_ThrowNullPointerException(env, "peer"); + env->DeleteGlobalRef(self); + env->DeleteGlobalRef(blockerPeer); + + delete nmbs; + return; + } else { + f = (AwtFrame *)JNI_GET_PDATA(peer); + if (f == NULL) { + THROW_NULL_PDATA_IF_NOT_DESTROYED(peer); + env->DeleteGlobalRef(self); + env->DeleteGlobalRef(peer); + env->DeleteGlobalRef(blockerPeer); + + delete nmbs; + return; + } + } // dialog here may be NULL, for example, if the blocker is a native dialog // however, we need to install/unistall modal hooks anyway - JNI_CHECK_PEER_GOTO(blockerPeer, ret); - AwtDialog *d = (AwtDialog *)pData; + AwtDialog *d = NULL; + + if (blockerPeer == NULL) { + env->ExceptionClear(); + JNU_ThrowNullPointerException(env, "blockerPeer"); + env->DeleteGlobalRef(self); + env->DeleteGlobalRef(peer); + + delete nmbs; + return; + } else { + d = (AwtDialog *)JNI_GET_PDATA(blockerPeer); + if (d == NULL) { + THROW_NULL_PDATA_IF_NOT_DESTROYED(blockerPeer); + env->DeleteGlobalRef(self); + env->DeleteGlobalRef(peer); + env->DeleteGlobalRef(blockerPeer); + + delete nmbs; + return; + } + } if ((f != NULL) && ::IsWindow(f->GetHWnd())) { @@ -1634,7 +1684,7 @@ void AwtFrame::_NotifyModalBlocked(void *param) } } } -ret: + env->DeleteGlobalRef(self); env->DeleteGlobalRef(peer); env->DeleteGlobalRef(blockerPeer); diff --git a/src/java.desktop/windows/native/libawt/windows/awt_Object.cpp b/src/java.desktop/windows/native/libawt/windows/awt_Object.cpp index 13507b9846c..fa9bf520f09 100644 --- a/src/java.desktop/windows/native/libawt/windows/awt_Object.cpp +++ b/src/java.desktop/windows/native/libawt/windows/awt_Object.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2011, 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 @@ -174,53 +174,6 @@ void AwtObject::SendEvent(jobject event) DASSERT(!safe_ExceptionOccurred(env)); } -// -// (static) -// Switches to Windows thread via SendMessage and synchronously -// calls AwtObject::WinThreadExecProc with the given command id -// and parameters. -// -// Useful for writing code that needs to be synchronized with -// what's happening on the Windows thread. -// -LRESULT AwtObject::WinThreadExec( - jobject peerObject, - UINT cmdId, - LPARAM param1, - LPARAM param2, - LPARAM param3, - LPARAM param4 ) -{ - DASSERT( peerObject != NULL); - - JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2); - // since we pass peerObject to another thread we must - // make a global ref - jobject peerObjectGlobalRef = env->NewGlobalRef(peerObject); - - ExecuteArgs args; - LRESULT retVal; - - // setup arguments - args.cmdId = cmdId; - args.param1 = param1; - args.param2 = param2; - args.param3 = param3; - args.param4 = param4; - - // call WinThreadExecProc on the toolkit thread - retVal = AwtToolkit::GetInstance().SendMessage(WM_AWT_EXECUTE_SYNC, - (WPARAM)peerObjectGlobalRef, - (LPARAM)&args); - return retVal; -} - -LRESULT AwtObject::WinThreadExecProc(ExecuteArgs * args) -{ - DASSERT(FALSE); // no default handler - return 0L; -} - /************************************************************************ * WObjectPeer native methods */ diff --git a/src/java.desktop/windows/native/libawt/windows/awt_Object.h b/src/java.desktop/windows/native/libawt/windows/awt_Object.h index 0c1fbfc4719..602cdd930e2 100644 --- a/src/java.desktop/windows/native/libawt/windows/awt_Object.h +++ b/src/java.desktop/windows/native/libawt/windows/awt_Object.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2011, 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 @@ -120,11 +120,6 @@ class AwtObject { DASSERT(FALSE); } - // execute given code on Windows message-pump thread - static LRESULT WinThreadExec(jobject peerObject, UINT cmdId, LPARAM param1 = 0L, LPARAM param2 = 0L, LPARAM param3 = 0L, LPARAM param4 = 0L); - // callback function to execute code on Windows message-pump thread - virtual LRESULT WinThreadExecProc(AwtObject::ExecuteArgs * args); - // overridden in AwtComponent to return FALSE if any messages // are being processed by this component virtual BOOL CanBeDeleted() { diff --git a/src/java.desktop/windows/native/libawt/windows/awt_PrintDialog.h b/src/java.desktop/windows/native/libawt/windows/awt_PrintDialog.h index 34809d72a90..669b1e0cbe8 100644 --- a/src/java.desktop/windows/native/libawt/windows/awt_PrintDialog.h +++ b/src/java.desktop/windows/native/libawt/windows/awt_PrintDialog.h @@ -35,10 +35,10 @@ class AwtPrintDialog { public: - static jfieldID AwtPrintDialog::controlID; - static jfieldID AwtPrintDialog::parentID; - static jfieldID AwtPrintDialog::pageID; - static jmethodID AwtPrintDialog::setHWndMID; + static jfieldID controlID; + static jfieldID parentID; + static jfieldID pageID; + static jmethodID setHWndMID; static BOOL PrintDlg(LPPRINTDLG); diff --git a/src/java.desktop/windows/native/libawt/windows/awt_PrintJob.cpp b/src/java.desktop/windows/native/libawt/windows/awt_PrintJob.cpp index 5d3f337036d..c7615336218 100644 --- a/src/java.desktop/windows/native/libawt/windows/awt_PrintJob.cpp +++ b/src/java.desktop/windows/native/libawt/windows/awt_PrintJob.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2023, 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 @@ -57,17 +57,14 @@ */ #define ROUND_TO_INT(num) ((int) floor((num) + 0.5)) +jfieldID AwtPrintDialog::pageID; + /************************************************************************ * WPrintJob native methods */ extern "C" { -/*** Private Constants ***/ - -static const char *kJavaIntStr = "I"; -static const char *kJavaLongStr = "J"; - /* 2D printing uses 3 byte BGR pixels in Raster printing */ static int J2DRasterBPP = 3; @@ -209,7 +206,6 @@ static const double POINTS_TO_HIMETRIC = (2540.0 / 72.0); */ static const double POINTS_TO_LOMETRIC = (254.0 / 72.0); -jfieldID AwtPrintDialog::pageID; /*** Private Macros ***/ @@ -307,18 +303,11 @@ static void matchPaperSize(HDC printDC, HGLOBAL hDevMode, HGLOBAL hDevNames, static jboolean jFontToWFontW(JNIEnv *env, HDC printDC, jstring fontName, jfloat fontSize, jboolean isBold, jboolean isItalic, jint rotation, jfloat awScale); -static jboolean jFontToWFontA(JNIEnv *env, HDC printDC, jstring fontName, - jfloat fontSize, jboolean isBold, jboolean isItalic, - jint rotation, jfloat awScale); static int CALLBACK fontEnumProcW(ENUMLOGFONTEXW *lpelfe, NEWTEXTMETRICEX *lpntme, int FontType, LPARAM lParam); -static int CALLBACK fontEnumProcA(ENUMLOGFONTEXA *logfont, - NEWTEXTMETRICEX *lpntme, - int FontType, - LPARAM lParam); static int embolden(int currentWeight); static BOOL getPrintableArea(HDC pdc, HANDLE hDevMode, RectDouble *margin); @@ -493,6 +482,18 @@ Java_sun_awt_windows_WPageDialog_initIDs(JNIEnv *env, jclass cls) * WPageDialogPeer native methods */ +#define CLEANUP_SHOW { \ + env->DeleteGlobalRef(peerGlobalRef); \ + if (target != NULL) { \ + env->DeleteLocalRef(target); \ + } \ + if (parent != NULL) { \ + env->DeleteLocalRef(parent); \ + } \ + env->DeleteLocalRef(page); \ + env->DeleteLocalRef(self); \ +} + /* * Class: sun_awt_windows_WPageDialogPeer * Method: show @@ -521,8 +522,6 @@ Java_sun_awt_windows_WPageDialogPeer__1show(JNIEnv *env, jobject peer) AwtComponent *awtParent = (parent != NULL) ? (AwtComponent *)JNI_GET_PDATA(parent) : NULL; HWND hwndOwner = awtParent ? awtParent->GetHWnd() : NULL; - - jboolean doIt = JNI_FALSE; // Assume the user will cancel the dialog. PAGESETUPDLG setup; memset(&setup, 0, sizeof(setup)); @@ -572,13 +571,13 @@ Java_sun_awt_windows_WPageDialogPeer__1show(JNIEnv *env, jobject peer) */ if (AwtPrintControl::getPrintHDMode(env, self) == NULL || AwtPrintControl::getPrintHDName(env,self) == NULL) { - (void)::PageSetupDlg(&setup); + static_cast(::PageSetupDlg(&setup)); /* check if hDevMode and hDevNames are set. * If both are null, then there is no default printer. */ if ((setup.hDevMode == NULL) && (setup.hDevNames == NULL)) { - doIt = JNI_FALSE; - goto done; + CLEANUP_SHOW; + return JNI_FALSE; } } else { int measure = PSD_INTHOUSANDTHSOFINCHES; @@ -605,8 +604,8 @@ Java_sun_awt_windows_WPageDialogPeer__1show(JNIEnv *env, jobject peer) */ pageFormatToSetup(env, self, page, &setup, AwtPrintControl::getPrintDC(env, self)); if (env->ExceptionCheck()) { - doIt = JNI_FALSE; - goto done; + CLEANUP_SHOW; + return JNI_FALSE; } setup.lpfnPageSetupHook = reinterpret_cast(pageDlgHook); @@ -619,8 +618,8 @@ Java_sun_awt_windows_WPageDialogPeer__1show(JNIEnv *env, jobject peer) jobject paper = getPaper(env, page); if (paper == NULL) { - doIt = JNI_FALSE; - goto done; + CLEANUP_SHOW; + return JNI_FALSE; } int units = setup.Flags & PSD_INTHOUSANDTHSOFINCHES ? MM_HIENGLISH : @@ -660,9 +659,9 @@ Java_sun_awt_windows_WPageDialogPeer__1show(JNIEnv *env, jobject peer) * and place them into a Paper instance. */ setPaperValues(env, paper, &paperSize, &margins, units); - if (env->ExceptionCheck()) { - doIt = JNI_FALSE; - goto done; + if (env->ExceptionCheck()) { + CLEANUP_SHOW; + return JNI_FALSE; } /* * Put the updated Paper instance and the orientation into @@ -670,13 +669,13 @@ Java_sun_awt_windows_WPageDialogPeer__1show(JNIEnv *env, jobject peer) */ setPaper(env, page, paper); if (env->ExceptionCheck()) { - doIt = JNI_FALSE; - goto done; + CLEANUP_SHOW; + return JNI_FALSE; } setPageFormatOrientation(env, page, orientation); if (env->ExceptionCheck()) { - doIt = JNI_FALSE; - goto done; + CLEANUP_SHOW; + return JNI_FALSE; } if (setup.hDevMode != NULL) { DEVMODE *devmode = (DEVMODE *)::GlobalLock(setup.hDevMode); @@ -684,14 +683,13 @@ Java_sun_awt_windows_WPageDialogPeer__1show(JNIEnv *env, jobject peer) if (devmode->dmFields & DM_PAPERSIZE) { jboolean err = setPrintPaperSize(env, self, devmode->dmPaperSize); if (err) { - doIt = JNI_FALSE; - goto done; + CLEANUP_SHOW; + return JNI_FALSE; } } } ::GlobalUnlock(setup.hDevMode); } - doIt = JNI_TRUE; } AwtDialog::CheckUninstallModalHook(); @@ -708,18 +706,9 @@ Java_sun_awt_windows_WPageDialogPeer__1show(JNIEnv *env, jobject peer) AwtPrintControl::setPrintHDName(env, self, setup.hDevNames); } -done: - env->DeleteGlobalRef(peerGlobalRef); - if (target != NULL) { - env->DeleteLocalRef(target); - } - if (parent != NULL) { - env->DeleteLocalRef(parent); - } - env->DeleteLocalRef(page); - env->DeleteLocalRef(self); + CLEANUP_SHOW; - return doIt; + return JNI_TRUE; CATCH_BAD_ALLOC_RET(0); } @@ -881,6 +870,21 @@ Java_sun_awt_windows_WPrinterJob_getDefaultPage(JNIEnv *env, jobject self, } +#define CLEANUP_VALIDATE_PAPER { \ + if (privateDC == TRUE) { \ + if (printDC != NULL) { \ + /* In this case we know that this DC has no GDI objects to free */ \ + ::DeleteDC(printDC); \ + } \ + if (hDevMode != NULL) { \ + ::GlobalFree(hDevMode); \ + } \ + if (hDevNames != NULL) { \ + ::GlobalFree(hDevNames); \ + } \ + } \ +} + /* * Class: sun_awt_windows_WPrinterJob * Method: validatePaper @@ -919,7 +923,12 @@ Java_sun_awt_windows_WPrinterJob_validatePaper(JNIEnv *env, jobject self, } } - JNI_CHECK_NULL_GOTO(printDC, "Invalid printDC", done); + if (printDC == NULL) { + env->ExceptionClear(); + JNU_ThrowNullPointerException(env, "Invalid printDC"); + CLEANUP_VALIDATE_PAPER; + return; + } /* We try to mitigate the effects of floating point rounding errors * by only setting a value if it would differ from the value in the @@ -932,7 +941,10 @@ Java_sun_awt_windows_WPrinterJob_validatePaper(JNIEnv *env, jobject self, jdouble paperWidth, paperHeight; jboolean err; WORD dmPaperSize = getPrintPaperSize(env, &err, self); - if (err) goto done; + if (err) { + CLEANUP_VALIDATE_PAPER; + return; + } double ix, iy, iw, ih, pw, ph; @@ -940,24 +952,59 @@ Java_sun_awt_windows_WPrinterJob_validatePaper(JNIEnv *env, jobject self, jmethodID getID; jclass paperClass = env->GetObjectClass(origPaper); - JNI_CHECK_NULL_GOTO(paperClass, "paper class not found", done); + if (paperClass == NULL) { + env->ExceptionClear(); + JNU_ThrowNullPointerException(env, "paper class not found"); + CLEANUP_VALIDATE_PAPER; + return; + } getID = env->GetMethodID(paperClass, GETWIDTH_STR, GETWIDTH_SIG); - JNI_CHECK_NULL_GOTO(getID, "no getWidth method", done); + if (getID == NULL) { + env->ExceptionClear(); + JNU_ThrowNullPointerException(env, "no getWidth method"); + CLEANUP_VALIDATE_PAPER; + return; + } pw = env->CallDoubleMethod(origPaper, getID); getID = env->GetMethodID(paperClass, GETHEIGHT_STR, GETHEIGHT_SIG); - JNI_CHECK_NULL_GOTO(getID, "no getHeight method", done); + if (getID == NULL) { + env->ExceptionClear(); + JNU_ThrowNullPointerException(env, "no getHeight method"); + CLEANUP_VALIDATE_PAPER; + return; + } ph = env->CallDoubleMethod(origPaper, getID); getID = env->GetMethodID(paperClass, GETIMG_X_STR, GETIMG_X_SIG); - JNI_CHECK_NULL_GOTO(getID, "no getX method", done); + if (getID == NULL) { + env->ExceptionClear(); + JNU_ThrowNullPointerException(env, "no getX method"); + CLEANUP_VALIDATE_PAPER; + return; + } ix = env->CallDoubleMethod(origPaper, getID); getID = env->GetMethodID(paperClass, GETIMG_Y_STR, GETIMG_Y_SIG); - JNI_CHECK_NULL_GOTO(getID, "no getY method", done); + if (getID == NULL) { + env->ExceptionClear(); + JNU_ThrowNullPointerException(env, "no getY method"); + CLEANUP_VALIDATE_PAPER; + return; + } iy = env->CallDoubleMethod(origPaper, getID); getID = env->GetMethodID(paperClass, GETIMG_W_STR, GETIMG_W_SIG); - JNI_CHECK_NULL_GOTO(getID, "no getW method", done); + if (getID == NULL) { + env->ExceptionClear(); + JNU_ThrowNullPointerException(env, "no getW method"); + CLEANUP_VALIDATE_PAPER; + return; + } iw = env->CallDoubleMethod(origPaper, getID); getID = env->GetMethodID(paperClass, GETIMG_H_STR, GETIMG_H_SIG); - JNI_CHECK_NULL_GOTO(getID, "no getH method", done); + if (getID == NULL) { + env->ExceptionClear(); + JNU_ThrowNullPointerException(env, "no getH method"); + CLEANUP_VALIDATE_PAPER; + return; + } ih = env->CallDoubleMethod(origPaper, getID); matchPaperSize(printDC, hDevMode, hDevNames, pw, ph, @@ -1050,29 +1097,27 @@ Java_sun_awt_windows_WPrinterJob_validatePaper(JNIEnv *env, jobject self, jmethodID setSizeID = env->GetMethodID(paperClass, SETSIZE_STR, SETSIZE_SIG); - JNI_CHECK_NULL_GOTO(setSizeID, "no setSize method", done); + if (setSizeID == NULL) { + env->ExceptionClear(); + JNU_ThrowNullPointerException(env, "no setSize method"); + CLEANUP_VALIDATE_PAPER; + return; + } jmethodID setImageableID = env->GetMethodID(paperClass, SETIMAGEABLE_STR, SETIMAGEABLE_SIG); - JNI_CHECK_NULL_GOTO(setImageableID, "no setImageable method", done); + if (setImageableID == NULL) { + env->ExceptionClear(); + JNU_ThrowNullPointerException(env, "no setImageable method"); + CLEANUP_VALIDATE_PAPER; + return; + } env->CallVoidMethod(newPaper, setSizeID, paperWidth, paperHeight); env->CallVoidMethod(newPaper, setImageableID, ix, iy, iw, ih); -done: /* Free any resources allocated */ - if (privateDC == TRUE) { - if (printDC != NULL) { - /* In this case we know that this DC has no GDI objects to free */ - ::DeleteDC(printDC); - } - if (hDevMode != NULL) { - ::GlobalFree(hDevMode); - } - if (hDevNames != NULL) { - ::GlobalFree(hDevNames); - } - } + CLEANUP_VALIDATE_PAPER; CATCH_BAD_ALLOC; } @@ -2253,131 +2298,6 @@ JNIEXPORT jboolean JNICALL Java_sun_awt_windows_WPrinterJob_setFont return didSetFont; } -/** - * Try to convert a java font to a GDI font. On entry, 'printDC', - * is the device context we want to draw into. 'fontName' is - * the name of the font to be matched and 'fontSize' is the - * size of the font in device coordinates. If there is an - * equivalent GDI font then this function sets that font - * into 'printDC' and returns a 'true'. If there is no equivalent - * font then 'false' is returned. - */ -static jboolean jFontToWFontA(JNIEnv *env, HDC printDC, jstring fontName, - jfloat fontSize, jboolean isBold, jboolean isItalic, - jint rotation, jfloat awScale) -{ - LOGFONTA lf; - LOGFONTA matchedLogFont; - BOOL foundFont = false; // Assume we didn't find a matching GDI font. - - memset(&matchedLogFont, 0, sizeof(matchedLogFont)); - - LPCWSTR fontNameW = JNU_GetStringPlatformChars(env, fontName, NULL); - - - /* Some fontnames of Non-ASCII fonts like 'MS Minchou' are themselves - * Non-ASCII. They are assumed to be written in Unicode. - * Hereby, they are converted into platform codeset. - */ - int maxlen = static_cast(sizeof(lf.lfFaceName)) - 1; - // maxlen is int due to cbMultiByte parameter is int - int destLen = WideCharToMultiByte(CP_ACP, // convert to ASCII code page - 0, // flags - fontNameW, // Unicode string - -1, // Unicode length is calculated automatically - lf.lfFaceName, // Put ASCII string here - maxlen, // max len - NULL, // default handling of unmappables - NULL); // do not care if def char is used - - /* If WideCharToMultiByte succeeded then the number - * of bytes it copied into the face name buffer will - * be greater than zero and we just need to NULL terminate - * the string. If there was an error then the number of - * bytes copied is zero and we can not match the font. - */ - if (destLen > 0) { - - DASSERT(destLen < sizeof(lf.lfFaceName)); - lf.lfFaceName[destLen] = '\0'; - lf.lfCharSet = DEFAULT_CHARSET; - lf.lfPitchAndFamily = 0; - - foundFont = !EnumFontFamiliesExA((HDC)printDC, &lf, - (FONTENUMPROCA) fontEnumProcA, - (LPARAM) &matchedLogFont, 0); - } - - - if (foundFont) { - - /* Build a font of the requested size with no - * width modifications. A negative font height - * tells GDI that we want that values absolute - * value as the font's point size. If the font - * is successfully built then set it as the current - * GDI font. - */ - matchedLogFont.lfHeight = -ROUND_TO_LONG(fontSize); - matchedLogFont.lfWidth = 0; - matchedLogFont.lfEscapement = rotation; - matchedLogFont.lfOrientation = rotation; - matchedLogFont.lfUnderline = 0; - matchedLogFont.lfStrikeOut = 0; - - /* Force bold or italic if requested. The font name - such as Arial Bold may have already set a weight - so here we just try to increase it. - */ - if (isBold) { - matchedLogFont.lfWeight = embolden(matchedLogFont.lfWeight); - } else { - matchedLogFont.lfWeight = FW_REGULAR; - } - - if (isItalic) { - matchedLogFont.lfItalic = 0xff; // TRUE - } else { - matchedLogFont.lfItalic = FALSE; - } - - HFONT font = CreateFontIndirectA(&matchedLogFont); - if (font) { - HFONT oldFont = (HFONT)::SelectObject(printDC, font); - if (oldFont != NULL) { - ::DeleteObject(oldFont); - if (awScale != 1.0) { - TEXTMETRIC tm; - DWORD avgWidth; - GetTextMetrics(printDC, &tm); - avgWidth = tm.tmAveCharWidth; - matchedLogFont.lfWidth = (LONG)((fabs)(avgWidth*awScale)); - font = CreateFontIndirectA(&matchedLogFont); - if (font) { - oldFont = (HFONT)::SelectObject(printDC, font); - if (oldFont != NULL) { - ::DeleteObject(oldFont); - GetTextMetrics(printDC, &tm); - } else { - foundFont = false; - } - } else { - foundFont = false; - } - } - } else { - foundFont = false; - } - } else { - foundFont = false; - } - } - - JNU_ReleaseStringPlatformChars(env, fontName, fontNameW); - - return foundFont ? JNI_TRUE : JNI_FALSE; -} - /** * Try to convert a java font to a GDI font. On entry, 'printDC', * is the device context we want to draw into. 'fontName' is @@ -2519,29 +2439,6 @@ static int CALLBACK fontEnumProcW(ENUMLOGFONTEXW *logfont,// logical-font data return stop; } -/** - * Invoked by GDI as a result of the EnumFontFamiliesExA - * call this routine choses a GDI font that matches - * a Java font. When a match is found then function - * returns a zero result to terminate the EnumFontFamiliesExA - * call. The information about the chosen font is copied into - * the LOGFONTA structure pointed to by 'lParam'. - */ -static int CALLBACK fontEnumProcA(ENUMLOGFONTEXA *logfont,// logical-font data - NEWTEXTMETRICEX *lpntme, // physical-font data - int FontType, // type of font - LPARAM lParam) -{ - LOGFONTA *matchedLogFont = (LOGFONTA *) lParam; - int stop = 0; // Take the first style found. - - if (matchedLogFont != NULL) { - *matchedLogFont = logfont->elfLogFont; - } - - return stop; -} - /** * Given the weight of a font from a GDI LOGFONT * structure, return a new weight indicating a diff --git a/src/java.desktop/windows/native/libawt/windows/awt_TextComponent.cpp b/src/java.desktop/windows/native/libawt/windows/awt_TextComponent.cpp index 86ab85b1d49..fff4237911c 100644 --- a/src/java.desktop/windows/native/libawt/windows/awt_TextComponent.cpp +++ b/src/java.desktop/windows/native/libawt/windows/awt_TextComponent.cpp @@ -53,12 +53,14 @@ struct EnableEditingStruct { * AwtTextComponent fields */ +jmethodID AwtTextComponent::canAccessClipboardMID; +AwtTextComponent::OleCallback AwtTextComponent::sm_oleCallback; +WNDPROC AwtTextComponent::sm_pDefWindowProc = NULL; + /************************************************************************ * AwtTextComponent methods */ -jmethodID AwtTextComponent::canAccessClipboardMID; - AwtTextComponent::AwtTextComponent() { m_synthetic = FALSE; m_lStartPos = -1; @@ -911,8 +913,6 @@ Java_sun_awt_windows_WTextComponentPeer_initIDs(JNIEnv *env, jclass cls) } -AwtTextComponent::OleCallback AwtTextComponent::sm_oleCallback; - /************************************************************************ * Inner class OleCallback definition. */ @@ -1040,8 +1040,6 @@ AwtTextComponent::OleCallback::GetContextMenu(WORD seltype, * (See AwtTextArea::WmContextMenu for more details). */ -WNDPROC AwtTextComponent::sm_pDefWindowProc = NULL; - LRESULT AwtTextComponent::EditProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { diff --git a/src/java.desktop/windows/native/libawt/windows/awt_Toolkit.cpp b/src/java.desktop/windows/native/libawt/windows/awt_Toolkit.cpp index 8f2e523b500..5d7171addb4 100644 --- a/src/java.desktop/windows/native/libawt/windows/awt_Toolkit.cpp +++ b/src/java.desktop/windows/native/libawt/windows/awt_Toolkit.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2023, 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 @@ -911,20 +911,6 @@ LRESULT CALLBACK AwtToolkit::WndProc(HWND hWnd, UINT message, * the main thread, a widget can always be properly disposed. */ switch (message) { - case WM_AWT_EXECUTE_SYNC: { - jobject peerObject = (jobject)wParam; - AwtObject* object = (AwtObject *)JNI_GET_PDATA(peerObject); - DASSERT( !IsBadReadPtr(object, sizeof(AwtObject))); - AwtObject::ExecuteArgs *args = (AwtObject::ExecuteArgs *)lParam; - DASSERT(!IsBadReadPtr(args, sizeof(AwtObject::ExecuteArgs))); - LRESULT result = 0; - if (object != NULL) - { - result = object->WinThreadExecProc(args); - } - env->DeleteGlobalRef(peerObject); - return result; - } case WM_AWT_COMPONENT_CREATE: { ComponentCreatePacket* ccp = (ComponentCreatePacket*)lParam; DASSERT(ccp->factory != NULL); @@ -1280,10 +1266,6 @@ LRESULT CALLBACK AwtToolkit::WndProc(HWND hWnd, UINT message, ::PostMessage(HWND_BROADCAST, WM_PALETTEISCHANGING, NULL, NULL); break; } - case WM_AWT_SETCURSOR: { - ::SetCursor((HCURSOR)wParam); - return TRUE; - } /* Session management */ case WM_QUERYENDSESSION: { /* Shut down cleanly */ @@ -1969,12 +1951,6 @@ HICON AwtToolkit::GetSecurityWarningIcon(UINT index, UINT w, UINT h) return securityWarningIcon[index]; } -void AwtToolkit::SetHeapCheck(long flag) { - if (flag) { - printf("heap checking not supported with this build\n"); - } -} - void throw_if_shutdown(void) { AwtToolkit::GetInstance().VerifyActive(); diff --git a/src/java.desktop/windows/native/libawt/windows/awt_Toolkit.h b/src/java.desktop/windows/native/libawt/windows/awt_Toolkit.h index 5ff1d499eb9..4a4b2bdcb3f 100644 --- a/src/java.desktop/windows/native/libawt/windows/awt_Toolkit.h +++ b/src/java.desktop/windows/native/libawt/windows/awt_Toolkit.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2023, 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 @@ -413,7 +413,6 @@ class AwtToolkit { INLINE void SetVerbose(long flag) { m_verbose = (flag != 0); } INLINE void SetVerify(long flag) { m_verifyComponents = (flag != 0); } INLINE void SetBreak(long flag) { m_breakOnError = (flag != 0); } - INLINE void SetHeapCheck(long flag); static void SetBusy(BOOL busy); diff --git a/src/java.desktop/windows/native/libawt/windows/awt_Win32GraphicsDevice.cpp b/src/java.desktop/windows/native/libawt/windows/awt_Win32GraphicsDevice.cpp index 7712147c43c..8a84a28685f 100644 --- a/src/java.desktop/windows/native/libawt/windows/awt_Win32GraphicsDevice.cpp +++ b/src/java.desktop/windows/native/libawt/windows/awt_Win32GraphicsDevice.cpp @@ -712,16 +712,6 @@ float AwtWin32GraphicsDevice::GetScaleY() return scaleY; } -/** - * Disables offscreen acceleration for this device. This - * sets a flag in the java object that is used to determine - * whether offscreen surfaces can be created on the device. - */ -void AwtWin32GraphicsDevice::DisableOffscreenAcceleration() -{ - // REMIND: noop for now -} - void AwtWin32GraphicsDevice::DisableScaleAutoRefresh() { disableScaleAutoRefresh = TRUE; @@ -735,7 +725,6 @@ void AwtWin32GraphicsDevice::DisableScaleAutoRefresh() void AwtWin32GraphicsDevice::Invalidate(JNIEnv *env) { int defIndex = AwtWin32GraphicsDevice::GetDefaultDeviceIndex(); - DisableOffscreenAcceleration(); jobject javaDevice = GetJavaDevice(); if (!JNU_IsNull(env, javaDevice)) { JNU_CallMethodByName(env, NULL, javaDevice, "invalidate", @@ -802,22 +791,6 @@ void AwtWin32GraphicsDevice::ResetAllDesktopScales() } } -void AwtWin32GraphicsDevice::DisableOffscreenAccelerationForDevice( - HMONITOR hMonitor) -{ - Devices::InstanceAccess devices; - if (hMonitor == NULL) { - devices->GetDevice(0)->DisableOffscreenAcceleration(); - } else { - int devicesNum = devices->GetNumDevices(); - for (int i = 0; i < devicesNum; ++i) { - if (devices->GetDevice(i)->GetMonitor() == hMonitor) { - devices->GetDevice(i)->DisableOffscreenAcceleration(); - } - } - } -} - HMONITOR AwtWin32GraphicsDevice::GetMonitor(int deviceIndex) { Devices::InstanceAccess devices; diff --git a/src/java.desktop/windows/native/libawt/windows/awt_Win32GraphicsDevice.h b/src/java.desktop/windows/native/libawt/windows/awt_Win32GraphicsDevice.h index 91d5bda76da..55f6c1623a8 100644 --- a/src/java.desktop/windows/native/libawt/windows/awt_Win32GraphicsDevice.h +++ b/src/java.desktop/windows/native/libawt/windows/awt_Win32GraphicsDevice.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2020, 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 @@ -64,7 +64,6 @@ class AwtWin32GraphicsDevice { jobject GetJavaDevice() { return javaDevice; } int GetDeviceIndex() { return screen; } void Release(); - void DisableOffscreenAcceleration(); void DisableScaleAutoRefresh(); void Invalidate(JNIEnv *env); void InitDesktopScales(); @@ -96,7 +95,6 @@ class AwtWin32GraphicsDevice { static void ResetAllDesktopScales(); static BOOL IsPrimaryPalettized() { return primaryPalettized; } static int GetDefaultDeviceIndex() { return primaryIndex; } - static void DisableOffscreenAccelerationForDevice(HMONITOR hMonitor); static HDC GetDCFromScreen(int screen); static int GetScreenFromHMONITOR(HMONITOR mon); diff --git a/src/java.desktop/windows/native/libawt/windows/awt_Window.cpp b/src/java.desktop/windows/native/libawt/windows/awt_Window.cpp index fa692c177ea..a135d6f0113 100644 --- a/src/java.desktop/windows/native/libawt/windows/awt_Window.cpp +++ b/src/java.desktop/windows/native/libawt/windows/awt_Window.cpp @@ -1019,16 +1019,28 @@ void AwtWindow::_RepositionSecurityWarning(void* param) JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2); RepositionSecurityWarningStruct *rsws = - (RepositionSecurityWarningStruct *)param; + static_cast(param); jobject self = rsws->window; - PDATA pData; - JNI_CHECK_PEER_GOTO(self, ret); - AwtWindow *window = (AwtWindow *)pData; + AwtWindow *window = NULL; + + if (self == NULL) { + env->ExceptionClear(); + JNU_ThrowNullPointerException(env, "self"); + delete rsws; + return; + } else { + window = (AwtWindow *)JNI_GET_PDATA(self); + if (window == NULL) { + THROW_NULL_PDATA_IF_NOT_DESTROYED(self); + env->DeleteGlobalRef(self); + delete rsws; + return; + } + } window->RepositionSecurityWarning(env); - ret: env->DeleteGlobalRef(self); delete rsws; } @@ -3116,28 +3128,32 @@ void AwtWindow::_ModalDisable(void *param) { JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2); - ModalDisableStruct *mds = (ModalDisableStruct *)param; + ModalDisableStruct *mds = static_cast(param); jobject self = mds->window; HWND blockerHWnd = (HWND)mds->blockerHWnd; AwtWindow *window = NULL; HWND windowHWnd = 0; - JNI_CHECK_NULL_GOTO(self, "peer", ret); - PDATA pData = JNI_GET_PDATA(self); - if (pData == NULL) { - env->DeleteGlobalRef(self); + if (self == NULL) { + env->ExceptionClear(); + JNU_ThrowNullPointerException(env, "self"); delete mds; return; + } else { + window = (AwtWindow *)JNI_GET_PDATA(self); + if (window == NULL) { + env->DeleteGlobalRef(self); + delete mds; + return; + } } - window = (AwtWindow *)pData; windowHWnd = window->GetHWnd(); if (::IsWindow(windowHWnd)) { AwtWindow::SetAndActivateModalBlocker(windowHWnd, blockerHWnd); } -ret: env->DeleteGlobalRef(self); delete mds; @@ -3147,25 +3163,28 @@ void AwtWindow::_ModalEnable(void *param) { JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2); - jobject self = (jobject)param; + jobject self = static_cast(param); AwtWindow *window = NULL; HWND windowHWnd = 0; - JNI_CHECK_NULL_GOTO(self, "peer", ret); - PDATA pData = JNI_GET_PDATA(self); - if (pData == NULL) { - env->DeleteGlobalRef(self); + if (self == NULL) { + env->ExceptionClear(); + JNU_ThrowNullPointerException(env, "self"); return; + } else { + window = (AwtWindow *)JNI_GET_PDATA(self); + if (window == NULL) { + env->DeleteGlobalRef(self); + return; + } } - window = (AwtWindow *)pData; windowHWnd = window->GetHWnd(); if (::IsWindow(windowHWnd)) { AwtWindow::SetModalBlocker(windowHWnd, NULL); } - ret: env->DeleteGlobalRef(self); } @@ -3173,17 +3192,29 @@ void AwtWindow::_SetOpacity(void* param) { JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2); - OpacityStruct *os = (OpacityStruct *)param; + OpacityStruct *os = static_cast(param); jobject self = os->window; BYTE iOpacity = (BYTE)os->iOpacity; - PDATA pData; - JNI_CHECK_PEER_GOTO(self, ret); - AwtWindow *window = (AwtWindow *)pData; + AwtWindow *window = NULL; + + if (self == NULL) { + env->ExceptionClear(); + JNU_ThrowNullPointerException(env, "self"); + delete os; + return; + } else { + window = (AwtWindow *)JNI_GET_PDATA(self); + if (window == NULL) { + THROW_NULL_PDATA_IF_NOT_DESTROYED(self); + env->DeleteGlobalRef(self); + delete os; + return; + } + } window->SetTranslucency(iOpacity, window->isOpaque()); - ret: env->DeleteGlobalRef(self); delete os; } @@ -3192,17 +3223,29 @@ void AwtWindow::_SetOpaque(void* param) { JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2); - OpaqueStruct *os = (OpaqueStruct *)param; + OpaqueStruct *os = static_cast(param); jobject self = os->window; BOOL isOpaque = (BOOL)os->isOpaque; - PDATA pData; - JNI_CHECK_PEER_GOTO(self, ret); - AwtWindow *window = (AwtWindow *)pData; + AwtWindow *window = NULL; + + if (self == NULL) { + env->ExceptionClear(); + JNU_ThrowNullPointerException(env, "self"); + delete os; + return; + } else { + window = (AwtWindow *)JNI_GET_PDATA(self); + if (window == NULL) { + THROW_NULL_PDATA_IF_NOT_DESTROYED(self); + env->DeleteGlobalRef(self); + delete os; + return; + } + } window->SetTranslucency(window->getOpacity(), isOpaque); - ret: env->DeleteGlobalRef(self); delete os; } @@ -3211,18 +3254,36 @@ void AwtWindow::_UpdateWindow(void* param) { JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2); - UpdateWindowStruct *uws = (UpdateWindowStruct *)param; + UpdateWindowStruct *uws = static_cast(param); jobject self = uws->window; jintArray data = uws->data; - PDATA pData; - JNI_CHECK_PEER_GOTO(self, ret); - AwtWindow *window = (AwtWindow *)pData; + AwtWindow *window = NULL; + + if (self == NULL) { + env->ExceptionClear(); + JNU_ThrowNullPointerException(env, "self"); + if (data != NULL) { + env->DeleteGlobalRef(data); + } + delete uws; + return; + } else { + window = (AwtWindow *)JNI_GET_PDATA(self); + if (window == NULL) { + THROW_NULL_PDATA_IF_NOT_DESTROYED(self); + env->DeleteGlobalRef(self); + if (data != NULL) { + env->DeleteGlobalRef(data); + } + delete uws; + return; + } + } window->UpdateWindow(env, data, (int)uws->width, (int)uws->height, uws->hBitmap); - ret: env->DeleteGlobalRef(self); if (data != NULL) { env->DeleteGlobalRef(data); @@ -3239,13 +3300,25 @@ void AwtWindow::_SetFullScreenExclusiveModeState(void *param) jobject self = data->window; jboolean state = data->isFSEMState; - PDATA pData; - JNI_CHECK_PEER_GOTO(self, ret); - AwtWindow *window = (AwtWindow *)pData; + AwtWindow *window = NULL; + + if (self == NULL) { + env->ExceptionClear(); + JNU_ThrowNullPointerException(env, "self"); + delete data; + return; + } else { + window = (AwtWindow *)JNI_GET_PDATA(self); + if (window == NULL) { + THROW_NULL_PDATA_IF_NOT_DESTROYED(self); + env->DeleteGlobalRef(self); + delete data; + return; + } + } window->setFullScreenExclusiveModeState(state != 0); - ret: env->DeleteGlobalRef(self); delete data; } diff --git a/src/java.desktop/windows/native/libawt/windows/awt_ole.h b/src/java.desktop/windows/native/libawt/windows/awt_ole.h index 4e07eecedda..7a57e8c1329 100644 --- a/src/java.desktop/windows/native/libawt/windows/awt_ole.h +++ b/src/java.desktop/windows/native/libawt/windows/awt_ole.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2009, 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 @@ -180,15 +180,4 @@ struct CLogEntryPoint0 { #define _VE _variant_t() #define _VB(b) _variant_t(bool(b)) -struct OLEHolder -{ - OLEHolder() - : m_hr(::OleInitialize(NULL)) - {} - - ~OLEHolder(){} - operator bool() const { return S_OK==SUCCEEDED(m_hr); } - HRESULT m_hr; -}; - #endif//AWT_OLE_H diff --git a/src/java.desktop/windows/native/libawt/windows/awtmsg.h b/src/java.desktop/windows/native/libawt/windows/awtmsg.h index c4f85fad41c..3ec527c98e2 100644 --- a/src/java.desktop/windows/native/libawt/windows/awtmsg.h +++ b/src/java.desktop/windows/native/libawt/windows/awtmsg.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2020, 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 @@ -209,26 +209,16 @@ enum { WM_AWT_WINDOW_SETACTIVE, WM_AWT_LIST_SETMULTISELECT, WM_AWT_HANDLE_EVENT, - WM_AWT_PRINT_COMPONENT, WM_AWT_RESHAPE_COMPONENT, WM_AWT_SETALWAYSONTOP, WM_AWT_BEGIN_VALIDATE, WM_AWT_END_VALIDATE, WM_AWT_FORWARD_CHAR, - WM_AWT_FORWARD_BYTE, - WM_AWT_SET_SCROLL_INFO, WM_AWT_CREATECONTEXT, WM_AWT_DESTROYCONTEXT, WM_AWT_ASSOCIATECONTEXT, WM_AWT_GET_DEFAULT_IME_HANDLER, WM_AWT_HANDLE_NATIVE_IME_EVENT, - WM_AWT_PRE_KEYDOWN, - WM_AWT_PRE_KEYUP, - WM_AWT_PRE_SYSKEYDOWN, - WM_AWT_PRE_SYSKEYUP, - - /* deleted DND mesg's */ - WM_AWT_ENDCOMPOSITION, WM_AWT_DISPOSE, WM_AWT_DISPOSEPDATA, @@ -241,19 +231,14 @@ enum { WM_AWT_OPENCANDIDATEWINDOW, WM_AWT_DLG_SHOWMODAL, WM_AWT_DLG_ENDMODAL, - WM_AWT_SETCURSOR, WM_AWT_WAIT_FOR_SINGLE_OBJECT, WM_AWT_INVOKE_METHOD, WM_AWT_INVOKE_VOID_METHOD, - WM_AWT_EXECUTE_SYNC, WM_AWT_OBJECTLISTCLEANUP, - WM_AWT_CURSOR_SYNC, WM_AWT_GETDC, WM_AWT_RELEASEDC, WM_AWT_RELEASE_ALL_DCS, - WM_AWT_SHOWCURSOR, - WM_AWT_HIDECURSOR, WM_AWT_CREATE_PRINTED_PIXELS, // Tray messages diff --git a/src/java.management.rmi/share/classes/javax/management/remote/rmi/RMIConnection.java b/src/java.management.rmi/share/classes/javax/management/remote/rmi/RMIConnection.java index dd9175e888f..5ce708ed43a 100644 --- a/src/java.management.rmi/share/classes/javax/management/remote/rmi/RMIConnection.java +++ b/src/java.management.rmi/share/classes/javax/management/remote/rmi/RMIConnection.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 @@ -81,6 +81,11 @@ * of a method is not specified here, it is the same as in the * corresponding MBeanServerConnection method. * + *

JMX Subject Delegation has been removed. All methods that take a + * {@code delegationSubject} parameter will throw {@code UnsupportedOperationException} + * if it is non-null. This parameter is kept for interoperability with older + * remote clients. + * * @since 1.5 */ /* @@ -123,9 +128,7 @@ public interface RMIConnection extends Closeable, Remote { * * @param className The class name of the MBean to be instantiated. * @param name The object name of the MBean. May be null. - * @param delegationSubject The Subject containing the - * delegation principals or null if the authentication - * principal is used instead. + * @param delegationSubject must be {@code null}. * * @return An ObjectInstance, containing the * ObjectName and the Java class name of the newly @@ -152,9 +155,10 @@ public interface RMIConnection extends Closeable, Remote { * passed in parameter is null, the ObjectName passed * in parameter contains a pattern or no ObjectName * is specified for the MBean. - * @throws SecurityException if the client, or the delegated Subject - * if any, does not have permission to perform this operation. + * @throws SecurityException if the client does not have permission + * to perform this operation. * @throws IOException if a general communication exception occurred. + * @throws UnsupportedOperationException if {@code delegationSubject} is non-null. */ public ObjectInstance createMBean(String className, ObjectName name, @@ -175,9 +179,7 @@ public ObjectInstance createMBean(String className, * @param className The class name of the MBean to be instantiated. * @param name The object name of the MBean. May be null. * @param loaderName The object name of the class loader to be used. - * @param delegationSubject The Subject containing the - * delegation principals or null if the authentication - * principal is used instead. + * @param delegationSubject must be {@code null}. * * @return An ObjectInstance, containing the * ObjectName and the Java class name of the newly @@ -206,9 +208,10 @@ public ObjectInstance createMBean(String className, * passed in parameter is null, the ObjectName passed * in parameter contains a pattern or no ObjectName * is specified for the MBean. - * @throws SecurityException if the client, or the delegated Subject - * if any, does not have permission to perform this operation. + * @throws SecurityException if the client does not have permission + * to perform this operation. * @throws IOException if a general communication exception occurred. + * @throws UnsupportedOperationException if {@code delegationSubject} is non-null. */ public ObjectInstance createMBean(String className, ObjectName name, @@ -238,9 +241,7 @@ public ObjectInstance createMBean(String className, * @param signature An array containing the signature of the * constructor to be invoked. Can be null, equivalent to an empty * array. - * @param delegationSubject The Subject containing the - * delegation principals or null if the authentication - * principal is used instead. + * @param delegationSubject must be {@code null}. * * @return An ObjectInstance, containing the * ObjectName and the Java class name of the newly @@ -267,9 +268,10 @@ public ObjectInstance createMBean(String className, * passed in parameter is null, the ObjectName passed * in parameter contains a pattern, or no ObjectName * is specified for the MBean. - * @throws SecurityException if the client, or the delegated Subject - * if any, does not have permission to perform this operation. + * @throws SecurityException if the client does not have permission + * to perform this operation. * @throws IOException if a general communication exception occurred. + * @throws UnsupportedOperationException if {@code delegationSubject} is non-null. */ public ObjectInstance createMBean(String className, ObjectName name, @@ -301,9 +303,7 @@ public ObjectInstance createMBean(String className, * @param signature An array containing the signature of the * constructor to be invoked. Can be null, equivalent to an empty * array. - * @param delegationSubject The Subject containing the - * delegation principals or null if the authentication - * principal is used instead. + * @param delegationSubject must be {@code null}. * * @return An ObjectInstance, containing the * ObjectName and the Java class name of the newly @@ -332,9 +332,10 @@ public ObjectInstance createMBean(String className, * passed in parameter is null, the ObjectName passed * in parameter contains a pattern, or no ObjectName * is specified for the MBean. - * @throws SecurityException if the client, or the delegated Subject - * if any, does not have permission to perform this operation. + * @throws SecurityException if the client does not have permission + * to perform this operation. * @throws IOException if a general communication exception occurred. + * @throws UnsupportedOperationException if {@code delegationSubject} is non-null. */ public ObjectInstance createMBean(String className, ObjectName name, @@ -356,9 +357,7 @@ public ObjectInstance createMBean(String className, * {@link javax.management.MBeanServerConnection#unregisterMBean(ObjectName)}. * * @param name The object name of the MBean to be unregistered. - * @param delegationSubject The Subject containing the - * delegation principals or null if the authentication - * principal is used instead. + * @param delegationSubject must be {@code null}. * * @throws InstanceNotFoundException The MBean specified is not * registered in the MBean server. @@ -370,9 +369,10 @@ public ObjectInstance createMBean(String className, * name in parameter is null or the MBean you are when trying to * unregister is the {@link javax.management.MBeanServerDelegate * MBeanServerDelegate} MBean. - * @throws SecurityException if the client, or the delegated Subject - * if any, does not have permission to perform this operation. + * @throws SecurityException if the client does not have permission + * to perform this operation. * @throws IOException if a general communication exception occurred. + * @throws UnsupportedOperationException if {@code delegationSubject} is non-null. */ public void unregisterMBean(ObjectName name, Subject delegationSubject) throws @@ -385,9 +385,7 @@ public void unregisterMBean(ObjectName name, Subject delegationSubject) * {@link javax.management.MBeanServerConnection#getObjectInstance(ObjectName)}. * * @param name The object name of the MBean. - * @param delegationSubject The Subject containing the - * delegation principals or null if the authentication - * principal is used instead. + * @param delegationSubject must be {@code null}. * * @return The ObjectInstance associated with the MBean * specified by name. The contained ObjectName @@ -399,9 +397,11 @@ public void unregisterMBean(ObjectName name, Subject delegationSubject) * @throws RuntimeOperationsException Wraps a * java.lang.IllegalArgumentException: The object * name in parameter is null. - * @throws SecurityException if the client, or the delegated Subject + * @throws SecurityException if the client does not have permission + * to perform this operation. * if any, does not have permission to perform this operation. * @throws IOException if a general communication exception occurred. + * @throws UnsupportedOperationException if {@code delegationSubject} is non-null. */ public ObjectInstance getObjectInstance(ObjectName name, Subject delegationSubject) @@ -420,17 +420,16 @@ public ObjectInstance getObjectInstance(ObjectName name, * MBeans, encapsulated into a MarshalledObject. If * the MarshalledObject encapsulates a null value no * query expression will be applied for selecting MBeans. - * @param delegationSubject The Subject containing the - * delegation principals or null if the authentication - * principal is used instead. + * @param delegationSubject must be {@code null}. * * @return A set containing the ObjectInstance * objects for the selected MBeans. If no MBean satisfies the * query an empty list is returned. * - * @throws SecurityException if the client, or the delegated Subject - * if any, does not have permission to perform this operation. + * @throws SecurityException if the client does not have permission + * to perform this operation. * @throws IOException if a general communication exception occurred. + * @throws UnsupportedOperationException if {@code delegationSubject} is non-null. */ public Set queryMBeans(ObjectName name, @@ -451,17 +450,16 @@ public ObjectInstance getObjectInstance(ObjectName name, * MBeans, encapsulated into a MarshalledObject. If * the MarshalledObject encapsulates a null value no * query expression will be applied for selecting MBeans. - * @param delegationSubject The Subject containing the - * delegation principals or null if the authentication - * principal is used instead. + * @param delegationSubject must be {@code null}. * * @return A set containing the ObjectNames for the MBeans * selected. If no MBean satisfies the query, an empty list is * returned. * - * @throws SecurityException if the client, or the delegated Subject - * if any, does not have permission to perform this operation. + * @throws SecurityException if the client does not have permission + * to perform this operation. * @throws IOException if a general communication exception occurred. + * @throws UnsupportedOperationException if {@code delegationSubject} is non-null. */ public Set queryNames(ObjectName name, @@ -474,9 +472,7 @@ public ObjectInstance getObjectInstance(ObjectName name, * {@link javax.management.MBeanServerConnection#isRegistered(ObjectName)}. * * @param name The object name of the MBean to be checked. - * @param delegationSubject The Subject containing the - * delegation principals or null if the authentication - * principal is used instead. + * @param delegationSubject must be {@code null}. * * @return True if the MBean is already registered in the MBean * server, false otherwise. @@ -484,9 +480,10 @@ public ObjectInstance getObjectInstance(ObjectName name, * @throws RuntimeOperationsException Wraps a * java.lang.IllegalArgumentException: The object * name in parameter is null. - * @throws SecurityException if the client, or the delegated Subject - * if any, does not have permission to perform this operation. + * @throws SecurityException if the client does not have permission + * to perform this operation. * @throws IOException if a general communication exception occurred. + * @throws UnsupportedOperationException if {@code delegationSubject} is non-null. */ public boolean isRegistered(ObjectName name, Subject delegationSubject) throws IOException; @@ -495,15 +492,14 @@ public boolean isRegistered(ObjectName name, Subject delegationSubject) * Handles the method * {@link javax.management.MBeanServerConnection#getMBeanCount()}. * - * @param delegationSubject The Subject containing the - * delegation principals or null if the authentication - * principal is used instead. + * @param delegationSubject must be {@code null}. * * @return the number of MBeans registered. * - * @throws SecurityException if the client, or the delegated Subject - * if any, does not have permission to perform this operation. + * @throws SecurityException if the client does not have permission + * to perform this operation. * @throws IOException if a general communication exception occurred. + * @throws UnsupportedOperationException if {@code delegationSubject} is non-null. */ public Integer getMBeanCount(Subject delegationSubject) throws IOException; @@ -517,9 +513,7 @@ public Integer getMBeanCount(Subject delegationSubject) * attribute is to be retrieved. * @param attribute A String specifying the name of the attribute * to be retrieved. - * @param delegationSubject The Subject containing the - * delegation principals or null if the authentication - * principal is used instead. + * @param delegationSubject must be {@code null}. * * @return The value of the retrieved attribute. * @@ -538,9 +532,10 @@ public Integer getMBeanCount(Subject delegationSubject) * null. * @throws RuntimeMBeanException Wraps a runtime exception thrown * by the MBean's getter. - * @throws SecurityException if the client, or the delegated Subject - * if any, does not have permission to perform this operation. + * @throws SecurityException if the client does not have permission + * to perform this operation. * @throws IOException if a general communication exception occurred. + * @throws UnsupportedOperationException if {@code delegationSubject} is non-null. * * @see #setAttribute */ @@ -562,9 +557,7 @@ public Object getAttribute(ObjectName name, * @param name The object name of the MBean from which the * attributes are retrieved. * @param attributes A list of the attributes to be retrieved. - * @param delegationSubject The Subject containing the - * delegation principals or null if the authentication - * principal is used instead. + * @param delegationSubject must be {@code null}. * * @return The list of the retrieved attributes. * @@ -575,9 +568,10 @@ public Object getAttribute(ObjectName name, * @throws RuntimeOperationsException Wrap a * java.lang.IllegalArgumentException: The object * name in parameter is null or attributes in parameter is null. - * @throws SecurityException if the client, or the delegated Subject - * if any, does not have permission to perform this operation. + * @throws SecurityException if the client does not have permission + * to perform this operation. * @throws IOException if a general communication exception occurred. + * @throws UnsupportedOperationException if {@code delegationSubject} is non-null. * * @see #setAttributes */ @@ -600,9 +594,7 @@ public AttributeList getAttributes(ObjectName name, * @param attribute The identification of the attribute to be set * and the value it is to be set to, encapsulated into a * MarshalledObject. - * @param delegationSubject The Subject containing the - * delegation principals or null if the authentication - * principal is used instead. + * @param delegationSubject must be {@code null}. * * @throws InstanceNotFoundException The MBean specified is not * registered in the MBean server. @@ -619,9 +611,10 @@ public AttributeList getAttributes(ObjectName name, * java.lang.IllegalArgumentException: The object * name in parameter is null or the attribute in parameter is * null. - * @throws SecurityException if the client, or the delegated Subject - * if any, does not have permission to perform this operation. + * @throws SecurityException if the client does not have permission + * to perform this operation. * @throws IOException if a general communication exception occurred. + * @throws UnsupportedOperationException if {@code delegationSubject} is non-null. * * @see #getAttribute */ @@ -647,9 +640,7 @@ public void setAttribute(ObjectName name, * @param attributes A list of attributes: The identification of * the attributes to be set and the values they are to be set to, * encapsulated into a MarshalledObject. - * @param delegationSubject The Subject containing the - * delegation principals or null if the authentication - * principal is used instead. + * @param delegationSubject must be {@code null}. * * @return The list of attributes that were set, with their new * values. @@ -661,9 +652,10 @@ public void setAttribute(ObjectName name, * @throws RuntimeOperationsException Wraps a * java.lang.IllegalArgumentException: The object * name in parameter is null or attributes in parameter is null. - * @throws SecurityException if the client, or the delegated Subject - * if any, does not have permission to perform this operation. + * @throws SecurityException if the client does not have permission + * to perform this operation. * @throws IOException if a general communication exception occurred. + * @throws UnsupportedOperationException if {@code delegationSubject} is non-null. * * @see #getAttributes */ @@ -693,9 +685,7 @@ public AttributeList setAttributes(ObjectName name, * class loader as the one used for loading the MBean on which the * operation was invoked. Can be null, equivalent to an empty * array. - * @param delegationSubject The Subject containing the - * delegation principals or null if the authentication - * principal is used instead. + * @param delegationSubject must be {@code null}. * * @return The object returned by the operation, which represents * the result of invoking the operation on the MBean specified. @@ -707,12 +697,13 @@ public AttributeList setAttributes(ObjectName name, * @throws ReflectionException Wraps a * java.lang.Exception thrown while trying to invoke * the method. - * @throws SecurityException if the client, or the delegated Subject - * if any, does not have permission to perform this operation. + * @throws SecurityException if the client does not have permission + * to perform this operation. * @throws IOException if a general communication exception occurred. * @throws RuntimeOperationsException Wraps an {@link * IllegalArgumentException} when name or * operationName is null. + * @throws UnsupportedOperationException if {@code delegationSubject} is non-null. */ public Object invoke(ObjectName name, String operationName, @@ -729,15 +720,14 @@ public Object invoke(ObjectName name, * Handles the method * {@link javax.management.MBeanServerConnection#getDefaultDomain()}. * - * @param delegationSubject The Subject containing the - * delegation principals or null if the authentication - * principal is used instead. + * @param delegationSubject must be {@code null}. * * @return the default domain. * - * @throws SecurityException if the client, or the delegated Subject - * if any, does not have permission to perform this operation. + * @throws SecurityException if the client does not have permission + * to perform this operation. * @throws IOException if a general communication exception occurred. + * @throws UnsupportedOperationException if {@code delegationSubject} is non-null. */ public String getDefaultDomain(Subject delegationSubject) throws IOException; @@ -746,15 +736,14 @@ public String getDefaultDomain(Subject delegationSubject) * Handles the method * {@link javax.management.MBeanServerConnection#getDomains()}. * - * @param delegationSubject The Subject containing the - * delegation principals or null if the authentication - * principal is used instead. + * @param delegationSubject must be {@code null}. * * @return the list of domains. * - * @throws SecurityException if the client, or the delegated Subject - * if any, does not have permission to perform this operation. + * @throws SecurityException if the client does not have permission + * to perform this operation. * @throws IOException if a general communication exception occurred. + * @throws UnsupportedOperationException if {@code delegationSubject} is non-null. */ public String[] getDomains(Subject delegationSubject) throws IOException; @@ -764,9 +753,7 @@ public String[] getDomains(Subject delegationSubject) * {@link javax.management.MBeanServerConnection#getMBeanInfo(ObjectName)}. * * @param name The name of the MBean to analyze - * @param delegationSubject The Subject containing the - * delegation principals or null if the authentication - * principal is used instead. + * @param delegationSubject must be {@code null}. * * @return An instance of MBeanInfo allowing the * retrieval of all attributes and operations of this MBean. @@ -777,12 +764,13 @@ public String[] getDomains(Subject delegationSubject) * not found. * @throws ReflectionException An exception occurred when * trying to invoke the getMBeanInfo of a Dynamic MBean. - * @throws SecurityException if the client, or the delegated Subject - * if any, does not have permission to perform this operation. + * @throws SecurityException if the client does not have permission + * to perform this operation. * @throws IOException if a general communication exception occurred. * @throws RuntimeOperationsException Wraps a * java.lang.IllegalArgumentException: The object * name in parameter is null. + * @throws UnsupportedOperationException if {@code delegationSubject} is non-null. */ public MBeanInfo getMBeanInfo(ObjectName name, Subject delegationSubject) throws @@ -798,21 +786,20 @@ public MBeanInfo getMBeanInfo(ObjectName name, Subject delegationSubject) * * @param name The ObjectName of the MBean. * @param className The name of the class. - * @param delegationSubject The Subject containing the - * delegation principals or null if the authentication - * principal is used instead. + * @param delegationSubject must be {@code null}. * * @return true if the MBean specified is an instance of the * specified class according to the rules above, false otherwise. * * @throws InstanceNotFoundException The MBean specified is not * registered in the MBean server. - * @throws SecurityException if the client, or the delegated Subject - * if any, does not have permission to perform this operation. + * @throws SecurityException if the client does not have permission + * to perform this operation. * @throws IOException if a general communication exception occurred. * @throws RuntimeOperationsException Wraps a * java.lang.IllegalArgumentException: The object * name in parameter is null. + * @throws UnsupportedOperationException if {@code delegationSubject} is non-null. */ public boolean isInstanceOf(ObjectName name, String className, @@ -839,9 +826,7 @@ public boolean isInstanceOf(ObjectName name, * @param handback The context to be sent to the listener when a * notification is emitted, encapsulated into a * MarshalledObject. - * @param delegationSubject The Subject containing the - * delegation principals or null if the authentication - * principal is used instead. + * @param delegationSubject must be {@code null}. * * @throws InstanceNotFoundException The MBean name of the * notification listener or of the notification broadcaster does @@ -851,9 +836,10 @@ public boolean isInstanceOf(ObjectName name, * listener exists but does not implement the * {@link javax.management.NotificationListener} interface, * or name or listener is null. - * @throws SecurityException if the client, or the delegated Subject - * if any, does not have permission to perform this operation. + * @throws SecurityException if the client does not have permission + * to perform this operation. * @throws IOException if a general communication exception occurred. + * @throws UnsupportedOperationException if {@code delegationSubject} is non-null. * * @see #removeNotificationListener(ObjectName, ObjectName, Subject) * @see #removeNotificationListener(ObjectName, ObjectName, @@ -874,20 +860,19 @@ public void addNotificationListener(ObjectName name, * @param name The name of the MBean on which the listener should * be removed. * @param listener The object name of the listener to be removed. - * @param delegationSubject The Subject containing the - * delegation principals or null if the authentication - * principal is used instead. + * @param delegationSubject must be {@code null}. * * @throws InstanceNotFoundException The MBean name provided * does not match any of the registered MBeans. * @throws ListenerNotFoundException The listener is not * registered in the MBean. - * @throws SecurityException if the client, or the delegated Subject - * if any, does not have permission to perform this operation. + * @throws SecurityException if the client does not have permission + * to perform this operation. * @throws IOException if a general communication exception occurred. * @throws RuntimeOperationsException Wraps an {@link * IllegalArgumentException} when name or * listener is null. + * @throws UnsupportedOperationException if {@code delegationSubject} is non-null. * * @see #addNotificationListener */ @@ -915,21 +900,20 @@ public void removeNotificationListener(ObjectName name, * was added, encapsulated into a MarshalledObject. * @param handback The handback that was specified when the * listener was added, encapsulated into a MarshalledObject. - * @param delegationSubject The Subject containing the - * delegation principals or null if the authentication - * principal is used instead. + * @param delegationSubject must be {@code null}. * * @throws InstanceNotFoundException The MBean name provided * does not match any of the registered MBeans. * @throws ListenerNotFoundException The listener is not * registered in the MBean, or it is not registered with the given * filter and handback. - * @throws SecurityException if the client, or the delegated Subject - * if any, does not have permission to perform this operation. + * @throws SecurityException if the client does not have permission + * to perform this operation. * @throws IOException if a general communication exception occurred. * @throws RuntimeOperationsException Wraps an {@link * IllegalArgumentException} when name or * listener is null. + * @throws UnsupportedOperationException if {@code delegationSubject} is non-null. * * @see #addNotificationListener */ @@ -972,12 +956,7 @@ public void removeNotificationListener(ObjectName name, * @param filters an array of marshalled representations of the * NotificationFilters. Elements of this array can * be null. - * @param delegationSubjects the Subjects on behalf - * of which the listeners are being added. Elements of this array - * can be null. Also, the delegationSubjects - * parameter itself can be null, which is equivalent to an array - * of null values with the same size as the names and - * filters arrays. + * @param delegationSubjects must be {@code null}. * * @return an array of listenerIDs identifying the * local listeners. This array has the same number of elements as @@ -993,9 +972,9 @@ public void removeNotificationListener(ObjectName name, * @throws InstanceNotFoundException if one of the * names does not correspond to any registered MBean. * @throws SecurityException if, for one of the MBeans, the - * client, or the delegated Subject if any, does not have - * permission to add a listener. + * client does not have permission to add a listener. * @throws IOException if a general communication exception occurred. + * @throws UnsupportedOperationException if {@code delegationSubject} is non-null. */ public Integer[] addNotificationListeners(ObjectName[] names, MarshalledObject[] filters, @@ -1022,9 +1001,7 @@ public Integer[] addNotificationListeners(ObjectName[] names, * emitting the Notifications. * @param listenerIDs the list of the IDs corresponding to the * listeners to remove. - * @param delegationSubject The Subject containing the - * delegation principals or null if the authentication - * principal is used instead. + * @param delegationSubject must be {@code null}. * * @throws InstanceNotFoundException if the given * name does not correspond to any registered MBean. @@ -1032,12 +1009,13 @@ public Integer[] addNotificationListeners(ObjectName[] names, * not found on the server side. This exception can happen if the * MBean discarded a listener for some reason other than a call to * MBeanServer.removeNotificationListener. - * @throws SecurityException if the client, or the delegated Subject - * if any, does not have permission to remove the listeners. + * @throws SecurityException if the client does not have permission + * to remove the listeners. * @throws IOException if a general communication exception occurred. * @throws IllegalArgumentException if ObjectName or * listenerIds is null or if listenerIds * contains a null element. + * @throws UnsupportedOperationException if {@code delegationSubject} is non-null. */ public void removeNotificationListeners(ObjectName name, Integer[] listenerIDs, diff --git a/src/java.management.rmi/share/classes/javax/management/remote/rmi/RMIConnectionImpl.java b/src/java.management.rmi/share/classes/javax/management/remote/rmi/RMIConnectionImpl.java index 43c22f34e31..6b901ea2638 100644 --- a/src/java.management.rmi/share/classes/javax/management/remote/rmi/RMIConnectionImpl.java +++ b/src/java.management.rmi/share/classes/javax/management/remote/rmi/RMIConnectionImpl.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 @@ -52,7 +52,6 @@ import com.sun.jmx.remote.internal.ServerCommunicatorAdmin; import com.sun.jmx.remote.internal.ServerNotifForwarder; import com.sun.jmx.remote.security.JMXSubjectDomainCombiner; -import com.sun.jmx.remote.security.SubjectDelegator; import com.sun.jmx.remote.util.ClassLoaderWithRepository; import com.sun.jmx.remote.util.ClassLogger; import com.sun.jmx.remote.util.EnvHelp; @@ -110,21 +109,13 @@ public RMIConnectionImpl(RMIServerImpl rmiServer, this.connectionId = connectionId; this.defaultClassLoader = defaultClassLoader; - this.subjectDelegator = new SubjectDelegator(); this.subject = subject; if (subject == null) { this.acc = null; - this.removeCallerContext = false; } else { - this.removeCallerContext = - SubjectDelegator.checkRemoveCallerContext(subject); - if (this.removeCallerContext) { - this.acc = - JMXSubjectDomainCombiner.getDomainCombinerContext(subject); - } else { - this.acc = - JMXSubjectDomainCombiner.getContext(subject); - } + // An authenticated Subject was provided. + // Subject Delegation has been removed. + this.acc = JMXSubjectDomainCombiner.getContext(subject); } this.mbeanServer = rmiServer.getMBeanServer(); @@ -236,6 +227,7 @@ public void unreferenced() { // MBeanServerConnection Wrapper //------------------------------------------------------------------------- + /** @throws UnsupportedOperationException {@inheritDoc} */ public ObjectInstance createMBean(String className, ObjectName name, Subject delegationSubject) @@ -278,6 +270,7 @@ public ObjectInstance createMBean(String className, } } + /** @throws UnsupportedOperationException {@inheritDoc} */ public ObjectInstance createMBean(String className, ObjectName name, ObjectName loaderName, @@ -326,6 +319,7 @@ public ObjectInstance createMBean(String className, } } + /** @throws UnsupportedOperationException {@inheritDoc} */ @SuppressWarnings("rawtypes") // MarshalledObject public ObjectInstance createMBean(String className, ObjectName name, @@ -386,6 +380,7 @@ public ObjectInstance createMBean(String className, } } + /** @throws UnsupportedOperationException {@inheritDoc} */ @SuppressWarnings("rawtypes") // MarshalledObject public ObjectInstance createMBean(String className, ObjectName name, @@ -453,6 +448,7 @@ public ObjectInstance createMBean(String className, } } + /** @throws UnsupportedOperationException {@inheritDoc} */ public void unregisterMBean(ObjectName name, Subject delegationSubject) throws InstanceNotFoundException, @@ -481,6 +477,7 @@ public void unregisterMBean(ObjectName name, Subject delegationSubject) } } + /** @throws UnsupportedOperationException {@inheritDoc} */ public ObjectInstance getObjectInstance(ObjectName name, Subject delegationSubject) throws @@ -511,6 +508,7 @@ public ObjectInstance getObjectInstance(ObjectName name, } } + /** @throws UnsupportedOperationException {@inheritDoc} */ @SuppressWarnings("rawtypes") // MarshalledObject public Set queryMBeans(ObjectName name, @@ -546,6 +544,7 @@ public ObjectInstance getObjectInstance(ObjectName name, } } + /** @throws UnsupportedOperationException {@inheritDoc} */ @SuppressWarnings("rawtypes") // MarshalledObject public Set queryNames(ObjectName name, @@ -581,6 +580,7 @@ public ObjectInstance getObjectInstance(ObjectName name, } } + /** @throws UnsupportedOperationException {@inheritDoc} */ public boolean isRegistered(ObjectName name, Subject delegationSubject) throws IOException { try { @@ -598,6 +598,7 @@ public boolean isRegistered(ObjectName name, } } + /** @throws UnsupportedOperationException {@inheritDoc} */ public Integer getMBeanCount(Subject delegationSubject) throws IOException { try { @@ -619,6 +620,7 @@ public Integer getMBeanCount(Subject delegationSubject) } } + /** @throws UnsupportedOperationException {@inheritDoc} */ public Object getAttribute(ObjectName name, String attribute, Subject delegationSubject) @@ -656,6 +658,7 @@ public Object getAttribute(ObjectName name, } } + /** @throws UnsupportedOperationException {@inheritDoc} */ public AttributeList getAttributes(ObjectName name, String[] attributes, Subject delegationSubject) @@ -688,6 +691,7 @@ public AttributeList getAttributes(ObjectName name, } } + /** @throws UnsupportedOperationException {@inheritDoc} */ @SuppressWarnings("rawtypes") // MarshalledObject public void setAttribute(ObjectName name, MarshalledObject attribute, @@ -741,6 +745,7 @@ public void setAttribute(ObjectName name, } } + /** @throws UnsupportedOperationException {@inheritDoc} */ @SuppressWarnings("rawtypes") // MarshalledObject public AttributeList setAttributes(ObjectName name, MarshalledObject attributes, @@ -787,6 +792,7 @@ public AttributeList setAttributes(ObjectName name, } } + /** @throws UnsupportedOperationException {@inheritDoc} */ @SuppressWarnings("rawtypes") // MarshalledObject public Object invoke(ObjectName name, String operationName, @@ -844,6 +850,7 @@ public Object invoke(ObjectName name, } } + /** @throws UnsupportedOperationException {@inheritDoc} */ public String getDefaultDomain(Subject delegationSubject) throws IOException { try { @@ -865,6 +872,7 @@ public String getDefaultDomain(Subject delegationSubject) } } + /** @throws UnsupportedOperationException {@inheritDoc} */ public String[] getDomains(Subject delegationSubject) throws IOException { try { final Object params[] = new Object[] { }; @@ -885,6 +893,7 @@ public String[] getDomains(Subject delegationSubject) throws IOException { } } + /** @throws UnsupportedOperationException {@inheritDoc} */ public MBeanInfo getMBeanInfo(ObjectName name, Subject delegationSubject) throws InstanceNotFoundException, @@ -920,6 +929,7 @@ public MBeanInfo getMBeanInfo(ObjectName name, Subject delegationSubject) } } + /** @throws UnsupportedOperationException {@inheritDoc} */ public boolean isInstanceOf(ObjectName name, String className, Subject delegationSubject) @@ -950,6 +960,8 @@ public boolean isInstanceOf(ObjectName name, } } + + /** @throws UnsupportedOperationException {@inheritDoc} */ @SuppressWarnings("rawtypes") // MarshalledObject public Integer[] addNotificationListeners(ObjectName[] names, MarshalledObject[] filters, @@ -959,9 +971,10 @@ public Integer[] addNotificationListeners(ObjectName[] names, if (names == null || filters == null) { throw new IllegalArgumentException("Got null arguments."); } - - Subject[] sbjs = (delegationSubjects != null) ? delegationSubjects : - new Subject[names.length]; + if (delegationSubjects != null) { + throw new UnsupportedOperationException("Subject Delegation has been removed."); + } + Subject[] sbjs = new Subject[names.length]; if (names.length != filters.length || filters.length != sbjs.length) { final String msg = "The value lengths of 3 parameters are not same."; @@ -1037,6 +1050,7 @@ public Integer[] addNotificationListeners(ObjectName[] names, } } + /** @throws UnsupportedOperationException {@inheritDoc} */ @SuppressWarnings("rawtypes") // MarshalledObject public void addNotificationListener(ObjectName name, ObjectName listener, @@ -1096,6 +1110,7 @@ public void addNotificationListener(ObjectName name, } } + /** @throws UnsupportedOperationException {@inheritDoc} */ public void removeNotificationListeners(ObjectName name, Integer[] listenerIDs, Subject delegationSubject) @@ -1137,6 +1152,7 @@ public void removeNotificationListeners(ObjectName name, } } + /** @throws UnsupportedOperationException {@inheritDoc} */ public void removeNotificationListener(ObjectName name, ObjectName listener, Subject delegationSubject) @@ -1173,6 +1189,7 @@ public void removeNotificationListener(ObjectName name, } } + /** @throws UnsupportedOperationException {@inheritDoc} */ @SuppressWarnings("rawtypes") // MarshalledObject public void removeNotificationListener(ObjectName name, ObjectName listener, @@ -1375,32 +1392,22 @@ public Object run() throws InstanceNotFoundException { } } + /** @throws UnsupportedOperationException {@inheritDoc} */ @SuppressWarnings("removal") private Object doPrivilegedOperation(final int operation, final Object[] params, final Subject delegationSubject) throws PrivilegedActionException, IOException { + // Subject Delegation is removed: locally this is caught earlier, in getMBeanServerConnection, + // but remote connections call into RMIConnectionImpl over RMI, so deny them here: + if (delegationSubject != null) { + throw new UnsupportedOperationException("Subject Delegation has been removed."); + } serverCommunicatorAdmin.reqIncoming(); try { - - final AccessControlContext reqACC; - if (delegationSubject == null) - reqACC = acc; - else { - if (subject == null) { - final String msg = - "Subject delegation cannot be enabled unless " + - "an authenticated subject is put in place"; - throw new SecurityException(msg); - } - reqACC = subjectDelegator.delegatedContext( - acc, delegationSubject, removeCallerContext); - } - - PrivilegedOperation op = - new PrivilegedOperation(operation, params); - if (reqACC == null) { + PrivilegedOperation op = new PrivilegedOperation(operation, params); + if (acc == null) { try { return op.run(); } catch (Exception e) { @@ -1409,7 +1416,7 @@ private Object doPrivilegedOperation(final int operation, throw new PrivilegedActionException(e); } } else { - return AccessController.doPrivileged(op, reqACC); + return AccessController.doPrivileged(op, acc); } } catch (Error e) { throw new JMXServerErrorException(e.toString(),e); @@ -1563,29 +1570,22 @@ private T unwrap(final MarshalledObject mo, final Class wrappedClass, Subject delegationSubject) throws IOException { + + // Subject Delegation is removed: locally this is caught earlier, in getMBeanServerConnection, + // but remote connections call into RMIConnectionImpl over RMI, so deny them here: + if (delegationSubject != null) { + throw new UnsupportedOperationException("Subject Delegation has been removed."); + } if (mo == null) { return null; } try { final ClassLoader old = AccessController.doPrivileged(new SetCcl(cl)); try{ - final AccessControlContext reqACC; - if (delegationSubject == null) - reqACC = acc; - else { - if (subject == null) { - final String msg = - "Subject delegation cannot be enabled unless " + - "an authenticated subject is put in place"; - throw new SecurityException(msg); - } - reqACC = subjectDelegator.delegatedContext( - acc, delegationSubject, removeCallerContext); - } - if(reqACC != null){ + if (acc != null) { return AccessController.doPrivileged( (PrivilegedExceptionAction) () -> - wrappedClass.cast(mo.get()), reqACC); + wrappedClass.cast(mo.get()), acc); }else{ return wrappedClass.cast(mo.get()); } @@ -1704,10 +1704,6 @@ private static void checkNonNull(String what, Object x) { private final Subject subject; - private final SubjectDelegator subjectDelegator; - - private final boolean removeCallerContext; - @SuppressWarnings("removal") private final AccessControlContext acc; diff --git a/src/java.management.rmi/share/classes/javax/management/remote/rmi/RMIConnectionImpl_Stub.java b/src/java.management.rmi/share/classes/javax/management/remote/rmi/RMIConnectionImpl_Stub.java index 4f51d1c25d2..8f72aba5fe6 100644 --- a/src/java.management.rmi/share/classes/javax/management/remote/rmi/RMIConnectionImpl_Stub.java +++ b/src/java.management.rmi/share/classes/javax/management/remote/rmi/RMIConnectionImpl_Stub.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2023, 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 @@ -114,6 +114,7 @@ public RMIConnectionImpl_Stub(java.rmi.server.RemoteRef ref) { // methods from remote interfaces // implementation of addNotificationListener(ObjectName, ObjectName, MarshalledObject, MarshalledObject, Subject) + /** @throws UnsupportedOperationException {@inheritDoc} */ public void addNotificationListener(javax.management.ObjectName $param_ObjectName_1, javax.management.ObjectName $param_ObjectName_2, java.rmi.MarshalledObject $param_MarshalledObject_3, java.rmi.MarshalledObject $param_MarshalledObject_4, javax.security.auth.Subject $param_Subject_5) throws java.io.IOException, javax.management.InstanceNotFoundException { try { @@ -130,6 +131,7 @@ public void addNotificationListener(javax.management.ObjectName $param_ObjectNam } // implementation of addNotificationListeners(ObjectName[], MarshalledObject[], Subject[]) + /** @throws UnsupportedOperationException {@inheritDoc} */ public java.lang.Integer[] addNotificationListeners(javax.management.ObjectName[] $param_arrayOf_ObjectName_1, java.rmi.MarshalledObject[] $param_arrayOf_MarshalledObject_2, javax.security.auth.Subject[] $param_arrayOf_Subject_3) throws java.io.IOException, javax.management.InstanceNotFoundException { try { @@ -161,6 +163,7 @@ public void close() } // implementation of createMBean(String, ObjectName, MarshalledObject, String[], Subject) + /** @throws UnsupportedOperationException {@inheritDoc} */ public javax.management.ObjectInstance createMBean(java.lang.String $param_String_1, javax.management.ObjectName $param_ObjectName_2, java.rmi.MarshalledObject $param_MarshalledObject_3, java.lang.String[] $param_arrayOf_String_4, javax.security.auth.Subject $param_Subject_5) throws java.io.IOException, javax.management.InstanceAlreadyExistsException, javax.management.MBeanException, javax.management.MBeanRegistrationException, javax.management.NotCompliantMBeanException, javax.management.ReflectionException { try { @@ -184,6 +187,7 @@ public javax.management.ObjectInstance createMBean(java.lang.String $param_Strin } // implementation of createMBean(String, ObjectName, ObjectName, MarshalledObject, String[], Subject) + /** @throws UnsupportedOperationException {@inheritDoc} */ public javax.management.ObjectInstance createMBean(java.lang.String $param_String_1, javax.management.ObjectName $param_ObjectName_2, javax.management.ObjectName $param_ObjectName_3, java.rmi.MarshalledObject $param_MarshalledObject_4, java.lang.String[] $param_arrayOf_String_5, javax.security.auth.Subject $param_Subject_6) throws java.io.IOException, javax.management.InstanceAlreadyExistsException, javax.management.InstanceNotFoundException, javax.management.MBeanException, javax.management.MBeanRegistrationException, javax.management.NotCompliantMBeanException, javax.management.ReflectionException { try { @@ -209,6 +213,7 @@ public javax.management.ObjectInstance createMBean(java.lang.String $param_Strin } // implementation of createMBean(String, ObjectName, ObjectName, Subject) + /** @throws UnsupportedOperationException {@inheritDoc} */ public javax.management.ObjectInstance createMBean(java.lang.String $param_String_1, javax.management.ObjectName $param_ObjectName_2, javax.management.ObjectName $param_ObjectName_3, javax.security.auth.Subject $param_Subject_4) throws java.io.IOException, javax.management.InstanceAlreadyExistsException, javax.management.InstanceNotFoundException, javax.management.MBeanException, javax.management.MBeanRegistrationException, javax.management.NotCompliantMBeanException, javax.management.ReflectionException { try { @@ -234,6 +239,7 @@ public javax.management.ObjectInstance createMBean(java.lang.String $param_Strin } // implementation of createMBean(String, ObjectName, Subject) + /** @throws UnsupportedOperationException {@inheritDoc} */ public javax.management.ObjectInstance createMBean(java.lang.String $param_String_1, javax.management.ObjectName $param_ObjectName_2, javax.security.auth.Subject $param_Subject_3) throws java.io.IOException, javax.management.InstanceAlreadyExistsException, javax.management.MBeanException, javax.management.MBeanRegistrationException, javax.management.NotCompliantMBeanException, javax.management.ReflectionException { try { @@ -275,6 +281,7 @@ public javax.management.remote.NotificationResult fetchNotifications(long $param } // implementation of getAttribute(ObjectName, String, Subject) + /** @throws UnsupportedOperationException {@inheritDoc} */ public java.lang.Object getAttribute(javax.management.ObjectName $param_ObjectName_1, java.lang.String $param_String_2, javax.security.auth.Subject $param_Subject_3) throws java.io.IOException, javax.management.AttributeNotFoundException, javax.management.InstanceNotFoundException, javax.management.MBeanException, javax.management.ReflectionException { try { @@ -298,6 +305,7 @@ public java.lang.Object getAttribute(javax.management.ObjectName $param_ObjectNa } // implementation of getAttributes(ObjectName, String[], Subject) + /** @throws UnsupportedOperationException {@inheritDoc} */ public javax.management.AttributeList getAttributes(javax.management.ObjectName $param_ObjectName_1, java.lang.String[] $param_arrayOf_String_2, javax.security.auth.Subject $param_Subject_3) throws java.io.IOException, javax.management.InstanceNotFoundException, javax.management.ReflectionException { try { @@ -332,6 +340,7 @@ public java.lang.String getConnectionId() } // implementation of getDefaultDomain(Subject) + /** @throws UnsupportedOperationException {@inheritDoc} */ public java.lang.String getDefaultDomain(javax.security.auth.Subject $param_Subject_1) throws java.io.IOException { try { @@ -347,6 +356,7 @@ public java.lang.String getDefaultDomain(javax.security.auth.Subject $param_Subj } // implementation of getDomains(Subject) + /** @throws UnsupportedOperationException {@inheritDoc} */ public java.lang.String[] getDomains(javax.security.auth.Subject $param_Subject_1) throws java.io.IOException { try { @@ -362,6 +372,7 @@ public java.lang.String[] getDomains(javax.security.auth.Subject $param_Subject_ } // implementation of getMBeanCount(Subject) + /** @throws UnsupportedOperationException {@inheritDoc} */ public java.lang.Integer getMBeanCount(javax.security.auth.Subject $param_Subject_1) throws java.io.IOException { try { @@ -377,6 +388,7 @@ public java.lang.Integer getMBeanCount(javax.security.auth.Subject $param_Subjec } // implementation of getMBeanInfo(ObjectName, Subject) + /** @throws UnsupportedOperationException {@inheritDoc} */ public javax.management.MBeanInfo getMBeanInfo(javax.management.ObjectName $param_ObjectName_1, javax.security.auth.Subject $param_Subject_2) throws java.io.IOException, javax.management.InstanceNotFoundException, javax.management.IntrospectionException, javax.management.ReflectionException { try { @@ -398,6 +410,7 @@ public javax.management.MBeanInfo getMBeanInfo(javax.management.ObjectName $para } // implementation of getObjectInstance(ObjectName, Subject) + /** @throws UnsupportedOperationException {@inheritDoc} */ public javax.management.ObjectInstance getObjectInstance(javax.management.ObjectName $param_ObjectName_1, javax.security.auth.Subject $param_Subject_2) throws java.io.IOException, javax.management.InstanceNotFoundException { try { @@ -415,6 +428,7 @@ public javax.management.ObjectInstance getObjectInstance(javax.management.Object } // implementation of invoke(ObjectName, String, MarshalledObject, String[], Subject) + /** @throws UnsupportedOperationException {@inheritDoc} */ public java.lang.Object invoke(javax.management.ObjectName $param_ObjectName_1, java.lang.String $param_String_2, java.rmi.MarshalledObject $param_MarshalledObject_3, java.lang.String[] $param_arrayOf_String_4, javax.security.auth.Subject $param_Subject_5) throws java.io.IOException, javax.management.InstanceNotFoundException, javax.management.MBeanException, javax.management.ReflectionException { try { @@ -436,6 +450,7 @@ public java.lang.Object invoke(javax.management.ObjectName $param_ObjectName_1, } // implementation of isInstanceOf(ObjectName, String, Subject) + /** @throws UnsupportedOperationException {@inheritDoc} */ public boolean isInstanceOf(javax.management.ObjectName $param_ObjectName_1, java.lang.String $param_String_2, javax.security.auth.Subject $param_Subject_3) throws java.io.IOException, javax.management.InstanceNotFoundException { try { @@ -453,6 +468,7 @@ public boolean isInstanceOf(javax.management.ObjectName $param_ObjectName_1, jav } // implementation of isRegistered(ObjectName, Subject) + /** @throws UnsupportedOperationException {@inheritDoc} */ public boolean isRegistered(javax.management.ObjectName $param_ObjectName_1, javax.security.auth.Subject $param_Subject_2) throws java.io.IOException { try { @@ -468,6 +484,7 @@ public boolean isRegistered(javax.management.ObjectName $param_ObjectName_1, jav } // implementation of queryMBeans(ObjectName, MarshalledObject, Subject) + /** @throws UnsupportedOperationException {@inheritDoc} */ public java.util.Set queryMBeans(javax.management.ObjectName $param_ObjectName_1, java.rmi.MarshalledObject $param_MarshalledObject_2, javax.security.auth.Subject $param_Subject_3) throws java.io.IOException { try { @@ -483,6 +500,7 @@ public java.util.Set queryMBeans(javax.management.ObjectName $param_ObjectName_1 } // implementation of queryNames(ObjectName, MarshalledObject, Subject) + /** @throws UnsupportedOperationException {@inheritDoc} */ public java.util.Set queryNames(javax.management.ObjectName $param_ObjectName_1, java.rmi.MarshalledObject $param_MarshalledObject_2, javax.security.auth.Subject $param_Subject_3) throws java.io.IOException { try { @@ -498,6 +516,7 @@ public java.util.Set queryNames(javax.management.ObjectName $param_ObjectName_1, } // implementation of removeNotificationListener(ObjectName, ObjectName, MarshalledObject, MarshalledObject, Subject) + /** @throws UnsupportedOperationException {@inheritDoc} */ public void removeNotificationListener(javax.management.ObjectName $param_ObjectName_1, javax.management.ObjectName $param_ObjectName_2, java.rmi.MarshalledObject $param_MarshalledObject_3, java.rmi.MarshalledObject $param_MarshalledObject_4, javax.security.auth.Subject $param_Subject_5) throws java.io.IOException, javax.management.InstanceNotFoundException, javax.management.ListenerNotFoundException { try { @@ -516,6 +535,7 @@ public void removeNotificationListener(javax.management.ObjectName $param_Object } // implementation of removeNotificationListener(ObjectName, ObjectName, Subject) + /** @throws UnsupportedOperationException {@inheritDoc} */ public void removeNotificationListener(javax.management.ObjectName $param_ObjectName_1, javax.management.ObjectName $param_ObjectName_2, javax.security.auth.Subject $param_Subject_3) throws java.io.IOException, javax.management.InstanceNotFoundException, javax.management.ListenerNotFoundException { try { @@ -534,6 +554,7 @@ public void removeNotificationListener(javax.management.ObjectName $param_Object } // implementation of removeNotificationListeners(ObjectName, Integer[], Subject) + /** @throws UnsupportedOperationException {@inheritDoc} */ public void removeNotificationListeners(javax.management.ObjectName $param_ObjectName_1, java.lang.Integer[] $param_arrayOf_Integer_2, javax.security.auth.Subject $param_Subject_3) throws java.io.IOException, javax.management.InstanceNotFoundException, javax.management.ListenerNotFoundException { try { @@ -552,6 +573,7 @@ public void removeNotificationListeners(javax.management.ObjectName $param_Objec } // implementation of setAttribute(ObjectName, MarshalledObject, Subject) + /** @throws UnsupportedOperationException {@inheritDoc} */ public void setAttribute(javax.management.ObjectName $param_ObjectName_1, java.rmi.MarshalledObject $param_MarshalledObject_2, javax.security.auth.Subject $param_Subject_3) throws java.io.IOException, javax.management.AttributeNotFoundException, javax.management.InstanceNotFoundException, javax.management.InvalidAttributeValueException, javax.management.MBeanException, javax.management.ReflectionException { try { @@ -576,6 +598,7 @@ public void setAttribute(javax.management.ObjectName $param_ObjectName_1, java.r } // implementation of setAttributes(ObjectName, MarshalledObject, Subject) + /** @throws UnsupportedOperationException {@inheritDoc} */ public javax.management.AttributeList setAttributes(javax.management.ObjectName $param_ObjectName_1, java.rmi.MarshalledObject $param_MarshalledObject_2, javax.security.auth.Subject $param_Subject_3) throws java.io.IOException, javax.management.InstanceNotFoundException, javax.management.ReflectionException { try { @@ -595,6 +618,7 @@ public javax.management.AttributeList setAttributes(javax.management.ObjectName } // implementation of unregisterMBean(ObjectName, Subject) + /** @throws UnsupportedOperationException {@inheritDoc} */ public void unregisterMBean(javax.management.ObjectName $param_ObjectName_1, javax.security.auth.Subject $param_Subject_2) throws java.io.IOException, javax.management.InstanceNotFoundException, javax.management.MBeanRegistrationException { try { diff --git a/src/java.management.rmi/share/classes/javax/management/remote/rmi/RMIConnector.java b/src/java.management.rmi/share/classes/javax/management/remote/rmi/RMIConnector.java index be63d25a671..24b9f1055b7 100644 --- a/src/java.management.rmi/share/classes/javax/management/remote/rmi/RMIConnector.java +++ b/src/java.management.rmi/share/classes/javax/management/remote/rmi/RMIConnector.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2023, 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 @@ -385,16 +385,7 @@ public synchronized String getConnectionId() throws IOException { return connection.getConnectionId(); } - public synchronized MBeanServerConnection getMBeanServerConnection() - throws IOException { - return getMBeanServerConnection(null); - } - - @SuppressWarnings("removal") - public synchronized MBeanServerConnection - getMBeanServerConnection(Subject delegationSubject) - throws IOException { - + public synchronized MBeanServerConnection getMBeanServerConnection() throws IOException { if (terminated) { if (logger.traceOn()) logger.trace("getMBeanServerConnection","[" + this.toString() + @@ -406,8 +397,7 @@ public synchronized MBeanServerConnection getMBeanServerConnection() "] is not connected."); throw new IOException("Not connected"); } - - return getConnectionWithSubject(delegationSubject); + return getConnection(); } public void @@ -516,10 +506,6 @@ private synchronized void close(boolean intern) throws IOException { } } - // Clean up MBeanServerConnection table - // - rmbscMap.clear(); - /* Send notification of closure. We don't do this if the user * never called connect() on the connector, because there's no * connection id in that case. */ @@ -563,12 +549,9 @@ private Integer addListenerWithSubject(ObjectName name, final ObjectName[] names = new ObjectName[] {name}; final MarshalledObject[] filters = Util.cast(new MarshalledObject[] {filter}); - final Subject[] delegationSubjects = new Subject[] { - delegationSubject - }; final Integer[] listenerIDs = - addListenersWithSubjects(names,filters,delegationSubjects, + addListenersWithSubjects(names,filters,null, reconnect); if (debug) logger.debug("addListenerWithSubject","listenerID=" @@ -594,7 +577,7 @@ private Integer[] addListenersWithSubjects(ObjectName[] names, try { listenerIDs = connection.addNotificationListeners(names, filters, - delegationSubjects); + null); } catch (NoSuchObjectException noe) { // maybe reconnect if (reconnect) { @@ -602,7 +585,7 @@ private Integer[] addListenersWithSubjects(ObjectName[] names, listenerIDs = connection.addNotificationListeners(names, filters, - delegationSubjects); + null); } else { throw noe; } @@ -623,14 +606,8 @@ private Integer[] addListenersWithSubjects(ObjectName[] names, // Implementation of MBeanServerConnection //-------------------------------------------------------------------- private class RemoteMBeanServerConnection implements MBeanServerConnection { - private Subject delegationSubject; public RemoteMBeanServerConnection() { - this(null); - } - - public RemoteMBeanServerConnection(Subject delegationSubject) { - this.delegationSubject = delegationSubject; } public ObjectInstance createMBean(String className, @@ -650,13 +627,13 @@ public ObjectInstance createMBean(String className, try { return connection.createMBean(className, name, - delegationSubject); + null); } catch (IOException ioe) { communicatorAdmin.gotIOException(ioe); return connection.createMBean(className, name, - delegationSubject); + null); } finally { popDefaultClassLoader(old); } @@ -684,7 +661,7 @@ public ObjectInstance createMBean(String className, return connection.createMBean(className, name, loaderName, - delegationSubject); + null); } catch (IOException ioe) { communicatorAdmin.gotIOException(ioe); @@ -692,7 +669,7 @@ public ObjectInstance createMBean(String className, return connection.createMBean(className, name, loaderName, - delegationSubject); + null); } finally { popDefaultClassLoader(old); @@ -722,7 +699,7 @@ public ObjectInstance createMBean(String className, name, sParams, signature, - delegationSubject); + null); } catch (IOException ioe) { communicatorAdmin.gotIOException(ioe); @@ -730,7 +707,7 @@ public ObjectInstance createMBean(String className, name, sParams, signature, - delegationSubject); + null); } finally { popDefaultClassLoader(old); } @@ -762,7 +739,7 @@ public ObjectInstance createMBean(String className, loaderName, sParams, signature, - delegationSubject); + null); } catch (IOException ioe) { communicatorAdmin.gotIOException(ioe); @@ -771,7 +748,7 @@ public ObjectInstance createMBean(String className, loaderName, sParams, signature, - delegationSubject); + null); } finally { popDefaultClassLoader(old); } @@ -786,11 +763,11 @@ public void unregisterMBean(ObjectName name) final ClassLoader old = pushDefaultClassLoader(); try { - connection.unregisterMBean(name, delegationSubject); + connection.unregisterMBean(name, null); } catch (IOException ioe) { communicatorAdmin.gotIOException(ioe); - connection.unregisterMBean(name, delegationSubject); + connection.unregisterMBean(name, null); } finally { popDefaultClassLoader(old); } @@ -804,11 +781,11 @@ public ObjectInstance getObjectInstance(ObjectName name) final ClassLoader old = pushDefaultClassLoader(); try { - return connection.getObjectInstance(name, delegationSubject); + return connection.getObjectInstance(name, null); } catch (IOException ioe) { communicatorAdmin.gotIOException(ioe); - return connection.getObjectInstance(name, delegationSubject); + return connection.getObjectInstance(name, null); } finally { popDefaultClassLoader(old); } @@ -824,11 +801,11 @@ public Set queryMBeans(ObjectName name, new MarshalledObject(query); final ClassLoader old = pushDefaultClassLoader(); try { - return connection.queryMBeans(name, sQuery, delegationSubject); + return connection.queryMBeans(name, sQuery, null); } catch (IOException ioe) { communicatorAdmin.gotIOException(ioe); - return connection.queryMBeans(name, sQuery, delegationSubject); + return connection.queryMBeans(name, sQuery, null); } finally { popDefaultClassLoader(old); } @@ -844,11 +821,11 @@ public Set queryNames(ObjectName name, new MarshalledObject(query); final ClassLoader old = pushDefaultClassLoader(); try { - return connection.queryNames(name, sQuery, delegationSubject); + return connection.queryNames(name, sQuery, null); } catch (IOException ioe) { communicatorAdmin.gotIOException(ioe); - return connection.queryNames(name, sQuery, delegationSubject); + return connection.queryNames(name, sQuery, null); } finally { popDefaultClassLoader(old); } @@ -861,11 +838,11 @@ public boolean isRegistered(ObjectName name) final ClassLoader old = pushDefaultClassLoader(); try { - return connection.isRegistered(name, delegationSubject); + return connection.isRegistered(name, null); } catch (IOException ioe) { communicatorAdmin.gotIOException(ioe); - return connection.isRegistered(name, delegationSubject); + return connection.isRegistered(name, null); } finally { popDefaultClassLoader(old); } @@ -877,11 +854,11 @@ public Integer getMBeanCount() final ClassLoader old = pushDefaultClassLoader(); try { - return connection.getMBeanCount(delegationSubject); + return connection.getMBeanCount(null); } catch (IOException ioe) { communicatorAdmin.gotIOException(ioe); - return connection.getMBeanCount(delegationSubject); + return connection.getMBeanCount(null); } finally { popDefaultClassLoader(old); } @@ -902,13 +879,13 @@ public Object getAttribute(ObjectName name, try { return connection.getAttribute(name, attribute, - delegationSubject); + null); } catch (IOException ioe) { communicatorAdmin.gotIOException(ioe); return connection.getAttribute(name, attribute, - delegationSubject); + null); } finally { popDefaultClassLoader(old); } @@ -927,14 +904,14 @@ public AttributeList getAttributes(ObjectName name, try { return connection.getAttributes(name, attributes, - delegationSubject); + null); } catch (IOException ioe) { communicatorAdmin.gotIOException(ioe); return connection.getAttributes(name, attributes, - delegationSubject); + null); } finally { popDefaultClassLoader(old); } @@ -958,11 +935,11 @@ public void setAttribute(ObjectName name, new MarshalledObject(attribute); final ClassLoader old = pushDefaultClassLoader(); try { - connection.setAttribute(name, sAttribute, delegationSubject); + connection.setAttribute(name, sAttribute, null); } catch (IOException ioe) { communicatorAdmin.gotIOException(ioe); - connection.setAttribute(name, sAttribute, delegationSubject); + connection.setAttribute(name, sAttribute, null); } finally { popDefaultClassLoader(old); } @@ -986,13 +963,13 @@ public AttributeList setAttributes(ObjectName name, try { return connection.setAttributes(name, sAttributes, - delegationSubject); + null); } catch (IOException ioe) { communicatorAdmin.gotIOException(ioe); return connection.setAttributes(name, sAttributes, - delegationSubject); + null); } finally { popDefaultClassLoader(old); } @@ -1021,7 +998,7 @@ public Object invoke(ObjectName name, operationName, sParams, signature, - delegationSubject); + null); } catch (IOException ioe) { communicatorAdmin.gotIOException(ioe); @@ -1029,7 +1006,7 @@ public Object invoke(ObjectName name, operationName, sParams, signature, - delegationSubject); + null); } finally { popDefaultClassLoader(old); } @@ -1042,11 +1019,11 @@ public String getDefaultDomain() final ClassLoader old = pushDefaultClassLoader(); try { - return connection.getDefaultDomain(delegationSubject); + return connection.getDefaultDomain(null); } catch (IOException ioe) { communicatorAdmin.gotIOException(ioe); - return connection.getDefaultDomain(delegationSubject); + return connection.getDefaultDomain(null); } finally { popDefaultClassLoader(old); } @@ -1057,11 +1034,11 @@ public String[] getDomains() throws IOException { final ClassLoader old = pushDefaultClassLoader(); try { - return connection.getDomains(delegationSubject); + return connection.getDomains(null); } catch (IOException ioe) { communicatorAdmin.gotIOException(ioe); - return connection.getDomains(delegationSubject); + return connection.getDomains(null); } finally { popDefaultClassLoader(old); } @@ -1076,11 +1053,11 @@ public MBeanInfo getMBeanInfo(ObjectName name) if (logger.debugOn()) logger.debug("getMBeanInfo", "name=" + name); final ClassLoader old = pushDefaultClassLoader(); try { - return connection.getMBeanInfo(name, delegationSubject); + return connection.getMBeanInfo(name, null); } catch (IOException ioe) { communicatorAdmin.gotIOException(ioe); - return connection.getMBeanInfo(name, delegationSubject); + return connection.getMBeanInfo(name, null); } finally { popDefaultClassLoader(old); } @@ -1099,13 +1076,13 @@ public boolean isInstanceOf(ObjectName name, try { return connection.isInstanceOf(name, className, - delegationSubject); + null); } catch (IOException ioe) { communicatorAdmin.gotIOException(ioe); return connection.isInstanceOf(name, className, - delegationSubject); + null); } finally { popDefaultClassLoader(old); } @@ -1134,7 +1111,7 @@ public void addNotificationListener(ObjectName name, listener, sFilter, sHandback, - delegationSubject); + null); } catch (IOException ioe) { communicatorAdmin.gotIOException(ioe); @@ -1142,7 +1119,7 @@ public void addNotificationListener(ObjectName name, listener, sFilter, sHandback, - delegationSubject); + null); } finally { popDefaultClassLoader(old); } @@ -1163,13 +1140,13 @@ public void removeNotificationListener(ObjectName name, try { connection.removeNotificationListener(name, listener, - delegationSubject); + null); } catch (IOException ioe) { communicatorAdmin.gotIOException(ioe); connection.removeNotificationListener(name, listener, - delegationSubject); + null); } finally { popDefaultClassLoader(old); } @@ -1200,7 +1177,7 @@ public void removeNotificationListener(ObjectName name, listener, sFilter, sHandback, - delegationSubject); + null); } catch (IOException ioe) { communicatorAdmin.gotIOException(ioe); @@ -1208,7 +1185,7 @@ public void removeNotificationListener(ObjectName name, listener, sFilter, sHandback, - delegationSubject); + null); } finally { popDefaultClassLoader(old); } @@ -1237,10 +1214,9 @@ public void addNotificationListener(ObjectName name, final Integer listenerID = addListenerWithSubject(name, new MarshalledObject(filter), - delegationSubject,true); + null, true); rmiNotifClient.addNotificationListener(listenerID, name, listener, - filter, handback, - delegationSubject); + filter, handback); } public void removeNotificationListener(ObjectName name, @@ -1267,13 +1243,13 @@ public void removeNotificationListener(ObjectName name, try { connection.removeNotificationListeners(name, ret, - delegationSubject); + null); } catch (IOException ioe) { communicatorAdmin.gotIOException(ioe); connection.removeNotificationListeners(name, ret, - delegationSubject); + null); } finally { popDefaultClassLoader(old); } @@ -1309,13 +1285,13 @@ public void removeNotificationListener(ObjectName name, try { connection.removeNotificationListeners(name, new Integer[] {ret}, - delegationSubject); + null); } catch (IOException ioe) { communicatorAdmin.gotIOException(ioe); connection.removeNotificationListeners(name, new Integer[] {ret}, - delegationSubject); + null); } finally { popDefaultClassLoader(old); } @@ -1433,12 +1409,11 @@ protected Integer addListenerForMBeanRemovedNotif() new ObjectName[] {MBeanServerDelegate.DELEGATE_NAME}; final MarshalledObject[] filters = Util.cast(new MarshalledObject[] {sFilter}); - final Subject[] subjects = new Subject[] {null}; try { listenerIDs = connection.addNotificationListeners(names, filters, - subjects); + null); } catch (IOException ioe) { communicatorAdmin.gotIOException(ioe); @@ -1446,7 +1421,7 @@ protected Integer addListenerForMBeanRemovedNotif() listenerIDs = connection.addNotificationListeners(names, filters, - subjects); + null); } return listenerIDs[0]; } @@ -1564,7 +1539,6 @@ public void reconnectNotificationListeners(ClientListenerInfo[] old) throws IOEx ClientListenerInfo[] clis = new ClientListenerInfo[len]; - final Subject[] subjects = new Subject[len]; final ObjectName[] names = new ObjectName[len]; final NotificationListener[] listeners = new NotificationListener[len]; final NotificationFilter[] filters = new NotificationFilter[len]; @@ -1573,7 +1547,6 @@ public void reconnectNotificationListeners(ClientListenerInfo[] old) throws IOEx final Object[] handbacks = new Object[len]; for (i=0;i(filters[i]), - subjects[i], + null, false); clis[j++] = new ClientListenerInfo(id, names[i], listeners[i], filters[i], - handbacks[i], - subjects[i]); + handbacks[i]); } catch (InstanceNotFoundException infe) { logger.warning("reconnectNotificationListeners", "Can't reconnect listener for " + @@ -1745,7 +1716,6 @@ private void writeObject(java.io.ObjectOutputStream s) // Initialization of transient variables. private void initTransients() { - rmbscMap = new WeakHashMap>(); connected = false; terminated = false; @@ -1893,21 +1863,13 @@ protected Class resolveClass(ObjectStreamClass classDesc) private final ClassLoader loader; } - private MBeanServerConnection getConnectionWithSubject(Subject delegationSubject) { + private MBeanServerConnection getConnection() { MBeanServerConnection conn = null; - if (delegationSubject == null) { - if (nullSubjectConnRef == null - || (conn = nullSubjectConnRef.get()) == null) { - conn = new RemoteMBeanServerConnection(null); - nullSubjectConnRef = new WeakReference(conn); - } - } else { - WeakReference wr = rmbscMap.get(delegationSubject); - if (wr == null || (conn = wr.get()) == null) { - conn = new RemoteMBeanServerConnection(delegationSubject); - rmbscMap.put(delegationSubject, new WeakReference(conn)); - } + if (nullSubjectConnRef == null + || (conn = nullSubjectConnRef.get()) == null) { + conn = new RemoteMBeanServerConnection(); + nullSubjectConnRef = new WeakReference(conn); } return conn; } @@ -2279,7 +2241,6 @@ public Void run() { private transient long clientNotifSeqNo = 0; - private transient WeakHashMap> rmbscMap; private transient WeakReference nullSubjectConnRef = null; private transient RMINotifClient rmiNotifClient; diff --git a/src/java.management/share/classes/com/sun/jmx/remote/internal/ClientListenerInfo.java b/src/java.management/share/classes/com/sun/jmx/remote/internal/ClientListenerInfo.java index a1ab5db7999..4eb8fdfbd69 100644 --- a/src/java.management/share/classes/com/sun/jmx/remote/internal/ClientListenerInfo.java +++ b/src/java.management/share/classes/com/sun/jmx/remote/internal/ClientListenerInfo.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2006, 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 @@ -29,9 +29,6 @@ import javax.management.NotificationListener; import javax.management.ObjectName; -import javax.security.auth.Subject; - - /** *

An identified listener. A listener has an Integer id that is * unique per connector server. It selects notifications based on the @@ -43,14 +40,12 @@ public ClientListenerInfo(Integer listenerID, ObjectName name, NotificationListener listener, NotificationFilter filter, - Object handback, - Subject delegationSubject) { + Object handback) { this.listenerID = listenerID; this.name = name; this.listener = listener; this.filter = filter; this.handback = handback; - this.delegationSubject = delegationSubject; } public ObjectName getObjectName() { @@ -73,11 +68,6 @@ public Object getHandback() { return handback; } - public Subject getDelegationSubject() { - return delegationSubject; - } - - public boolean sameAs(ObjectName name) { return (getObjectName().equals(name)); } @@ -102,5 +92,4 @@ public boolean sameAs(ObjectName name, NotificationListener listener, Notificati private final NotificationListener listener; private final Object handback; - private final Subject delegationSubject; } diff --git a/src/java.management/share/classes/com/sun/jmx/remote/internal/ClientNotifForwarder.java b/src/java.management/share/classes/com/sun/jmx/remote/internal/ClientNotifForwarder.java index 47677d47ade..471cccecc8a 100644 --- a/src/java.management/share/classes/com/sun/jmx/remote/internal/ClientNotifForwarder.java +++ b/src/java.management/share/classes/com/sun/jmx/remote/internal/ClientNotifForwarder.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 @@ -167,8 +167,7 @@ public synchronized void addNotificationListener(Integer listenerID, ObjectName name, NotificationListener listener, NotificationFilter filter, - Object handback, - Subject delegationSubject) + Object handback) throws IOException, InstanceNotFoundException { if (logger.traceOn()) { @@ -181,9 +180,7 @@ public synchronized void addNotificationListener(Integer listenerID, name, listener, filter, - handback, - delegationSubject)); - + handback)); init(false); } diff --git a/src/java.management/share/classes/com/sun/jmx/remote/security/SubjectDelegator.java b/src/java.management/share/classes/com/sun/jmx/remote/security/SubjectDelegator.java deleted file mode 100644 index f79af7e047f..00000000000 --- a/src/java.management/share/classes/com/sun/jmx/remote/security/SubjectDelegator.java +++ /dev/null @@ -1,128 +0,0 @@ -/* - * Copyright (c) 2003, 2022, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package com.sun.jmx.remote.security; - -import java.security.AccessController; -import java.security.AccessControlContext; -import java.security.Permission; -import java.security.Principal; -import java.security.PrivilegedAction; -import javax.security.auth.Subject; - -import javax.management.remote.SubjectDelegationPermission; - -import java.util.*; - -public class SubjectDelegator { - /* Return the AccessControlContext appropriate to execute an - operation on behalf of the delegatedSubject. If the - authenticatedAccessControlContext does not have permission to - delegate to that subject, throw SecurityException. */ - @SuppressWarnings("removal") - public AccessControlContext - delegatedContext(AccessControlContext authenticatedACC, - Subject delegatedSubject, - boolean removeCallerContext) - throws SecurityException { - - if (System.getSecurityManager() != null && authenticatedACC == null) { - throw new SecurityException("Illegal AccessControlContext: null"); - } - - // Check if the subject delegation permission allows the - // authenticated subject to assume the identity of each - // principal in the delegated subject - // - Collection ps = getSubjectPrincipals(delegatedSubject); - final Collection permissions = new ArrayList<>(ps.size()); - for(Principal p : ps) { - final String pname = p.getClass().getName() + "." + p.getName(); - permissions.add(new SubjectDelegationPermission(pname)); - } - PrivilegedAction action = - new PrivilegedAction<>() { - public Void run() { - for (Permission sdp : permissions) { - AccessController.checkPermission(sdp); - } - return null; - } - }; - AccessController.doPrivileged(action, authenticatedACC); - - return getDelegatedAcc(delegatedSubject, removeCallerContext); - } - - @SuppressWarnings("removal") - private AccessControlContext getDelegatedAcc(Subject delegatedSubject, boolean removeCallerContext) { - if (removeCallerContext) { - return JMXSubjectDomainCombiner.getDomainCombinerContext(delegatedSubject); - } else { - return JMXSubjectDomainCombiner.getContext(delegatedSubject); - } - } - - /** - * Check if the connector server creator can assume the identity of each - * principal in the authenticated subject, i.e. check if the connector - * server creator codebase contains a subject delegation permission for - * each principal present in the authenticated subject. - * - * @return {@code true} if the connector server creator can delegate to all - * the authenticated principals in the subject. Otherwise, {@code false}. - */ - @SuppressWarnings("removal") - public static synchronized boolean - checkRemoveCallerContext(Subject subject) { - try { - for (Principal p : getSubjectPrincipals(subject)) { - final String pname = - p.getClass().getName() + "." + p.getName(); - final Permission sdp = - new SubjectDelegationPermission(pname); - AccessController.checkPermission(sdp); - } - } catch (SecurityException e) { - return false; - } - return true; - } - - /** - * Retrieves the {@linkplain Subject} principals - * @param subject The subject - * @return If the {@code Subject} is immutable it will return the principals directly. - * If the {@code Subject} is mutable it will create an unmodifiable copy. - */ - private static Collection getSubjectPrincipals(Subject subject) { - if (subject.isReadOnly()) { - return subject.getPrincipals(); - } - - List principals = Arrays.asList(subject.getPrincipals().toArray(new Principal[0])); - return Collections.unmodifiableList(principals); - } -} diff --git a/src/java.management/share/classes/javax/management/remote/JMXConnector.java b/src/java.management/share/classes/javax/management/remote/JMXConnector.java index fcd7c443f7e..8618ffa94b0 100644 --- a/src/java.management/share/classes/javax/management/remote/JMXConnector.java +++ b/src/java.management/share/classes/javax/management/remote/JMXConnector.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2023, 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 @@ -115,12 +115,6 @@ public interface JMXConnector extends Closeable { * {@link JMXServerErrorException}, which is seen by the * client.

* - *

Calling this method is equivalent to calling - * {@link #getMBeanServerConnection(Subject) getMBeanServerConnection(null)} - * meaning that no delegation subject is specified and that all the - * operations called on the MBeanServerConnection must - * use the authenticated subject, if any.

- * * @return an object that implements the * MBeanServerConnection interface by forwarding its * methods to the remote MBean server. @@ -135,49 +129,37 @@ public MBeanServerConnection getMBeanServerConnection() throws IOException; /** - *

Returns an MBeanServerConnection object representing - * a remote MBean server on which operations are performed on behalf of - * the supplied delegation subject. For a given JMXConnector - * and Subject, two successful calls to this method will - * usually return the same MBeanServerConnection object, - * though this is not required.

+ *

When {@code delegationSubject} is {@code null}, calling his method + * is equivalent to calling {@link #getMBeanServerConnection()}. * - *

For each method in the returned - * MBeanServerConnection, calling the method causes - * the corresponding method to be called in the remote MBean - * server on behalf of the given delegation subject instead of the - * authenticated subject. The value returned by the MBean server - * method is the value returned to the client. If the MBean server - * method produces an Exception, the same - * Exception is seen by the client. If the MBean - * server method, or the attempt to call it, produces an - * Error, the Error is wrapped in a - * {@link JMXServerErrorException}, which is seen by the - * client.

+ * @implSpec The default implementation of this method throws + * {@code UnsupportedOperationException} if {@code delegationSubject} is + * non-null. Otherwise it calls {@link getMBeanServerConnection()}. * - * @param delegationSubject the Subject on behalf of - * which requests will be performed. Can be null, in which case - * requests will be performed on behalf of the authenticated - * Subject, if any. + * @param delegationSubject must be {@code null}. * * @return an object that implements the MBeanServerConnection - * interface by forwarding its methods to the remote MBean server on behalf - * of a given delegation subject. + * interface by forwarding its methods to the remote MBean server. * * @exception IOException if a valid MBeanServerConnection * cannot be created, for instance because the connection to the remote * MBean server has not yet been established (with the {@link #connect(Map) * connect} method), or it has been closed, or it has broken. * + * @exception UnsupportedOperationException if {@code delegationSubject} is non-null. + * * @deprecated This method supported the legacy Subject Delegation feature, - * and is only useful in conjunction with other APIs which are deprecated and - * subject to removal in a future release. Consequently, this method is also - * deprecated and subject to removal. There is no replacement. + * which has been removed. There is no replacement. */ @Deprecated(since="21", forRemoval=true) - public MBeanServerConnection getMBeanServerConnection( - Subject delegationSubject) - throws IOException; + public default MBeanServerConnection getMBeanServerConnection(Subject delegationSubject) + throws IOException { + + if (delegationSubject != null) { + throw new UnsupportedOperationException("Subject Delegation has been removed."); + } + return getMBeanServerConnection(); + } /** *

Closes the client connection to its server. Any ongoing or new diff --git a/src/jdk.accessibility/windows/native/libjavaaccessbridge/AccessBridgeJavaEntryPoints.cpp b/src/jdk.accessibility/windows/native/libjavaaccessbridge/AccessBridgeJavaEntryPoints.cpp index c16fd791e5b..6f4231b70b9 100644 --- a/src/jdk.accessibility/windows/native/libjavaaccessbridge/AccessBridgeJavaEntryPoints.cpp +++ b/src/jdk.accessibility/windows/native/libjavaaccessbridge/AccessBridgeJavaEntryPoints.cpp @@ -1041,7 +1041,7 @@ AccessBridgeJavaEntryPoints::getParentWithRole(const jobject accessibleContext, rAccessibleContext = jniEnv->CallObjectMethod(accessBridgeObject, getParentWithRoleMethod, accessibleContext, roleName); - EXCEPTION_CHECK("Getting ParentWithRole - call to CallObjectMethod()", (AccessibleContext)0); + EXCEPTION_CHECK("Getting ParentWithRole - call to CallObjectMethod()", reinterpret_cast((AccessibleContext)0)); PrintDebugString("[INFO]: rAccessibleContext = %p", rAccessibleContext); jobject globalRef = jniEnv->NewGlobalRef(rAccessibleContext); EXCEPTION_CHECK("Getting ParentWithRole - call to NewGlobalRef()", FALSE); @@ -1111,7 +1111,7 @@ AccessBridgeJavaEntryPoints::getParentWithRoleElseRoot(const jobject accessibleC rAccessibleContext = jniEnv->CallObjectMethod(accessBridgeObject, getParentWithRoleElseRootMethod, accessibleContext, roleName); - EXCEPTION_CHECK("Getting ParentWithRoleElseRoot - call to CallObjectMethod()", (AccessibleContext)0); + EXCEPTION_CHECK("Getting ParentWithRoleElseRoot - call to CallObjectMethod()", reinterpret_cast((AccessibleContext)0)); PrintDebugString("[INFO]: rAccessibleContext = %p", rAccessibleContext); jobject globalRef = jniEnv->NewGlobalRef(rAccessibleContext); EXCEPTION_CHECK("Getting ParentWithRoleElseRoot - call to NewGlobalRef()", FALSE); @@ -1168,7 +1168,7 @@ AccessBridgeJavaEntryPoints::getActiveDescendent(const jobject accessibleContext rAccessibleContext = jniEnv->CallObjectMethod(accessBridgeObject, getActiveDescendentMethod, accessibleContext); - EXCEPTION_CHECK("Getting ActiveDescendent - call to CallObjectMethod()", (AccessibleContext)0); + EXCEPTION_CHECK("Getting ActiveDescendent - call to CallObjectMethod()", reinterpret_cast((AccessibleContext)0)); PrintDebugString("[INFO]: rAccessibleContext = %p", rAccessibleContext); jobject globalRef = jniEnv->NewGlobalRef(rAccessibleContext); EXCEPTION_CHECK("Getting ActiveDescendant - call to NewGlobalRef()", FALSE); @@ -1177,7 +1177,7 @@ AccessBridgeJavaEntryPoints::getActiveDescendent(const jobject accessibleContext return globalRef; } else { PrintDebugString("[ERROR]: either jniEnv == 0 or getActiveDescendentMethod == 0"); - return (AccessibleContext)0; + return reinterpret_cast((AccessibleContext)0); } } 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 5a6e0fb8556..65da42f3fbc 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 @@ -954,10 +954,10 @@ public void visitClassDef(JCClassDecl tree) { // make sure class has been completed: c.complete(); - // If this class appears as an anonymous class in a constructor - // prologue, disable implicit outer instance from being passed. - // (This would be an illegal access to "this before super"). - if (ctorProloguePrev && env.tree.hasTag(NEWCLASS)) { + // If a class declaration appears in a constructor prologue, + // that means it's either a local class or an anonymous class. + // Either way, there is no immediately enclosing instance. + if (ctorProloguePrev) { c.flags_field |= NOOUTERTHIS; } attribClass(tree.pos(), c); diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Lower.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Lower.java index 3ad0188ee0c..f1c897a917e 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Lower.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Lower.java @@ -1843,7 +1843,6 @@ JCExpression makeOuterThis(DiagnosticPosition pos, TypeSymbol c) { List ots = outerThisStack; if (ots.isEmpty()) { log.error(pos, Errors.NoEnclInstanceOfTypeInScope(c)); - Assert.error(); return makeNull(); } VarSymbol ot = ots.head; diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/TransPatterns.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/TransPatterns.java index 06c41156ad4..5dc85d5f2c5 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/TransPatterns.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/TransPatterns.java @@ -106,7 +106,6 @@ import com.sun.tools.javac.tree.TreeInfo; import com.sun.tools.javac.tree.TreeScanner; import com.sun.tools.javac.util.Assert; -import com.sun.tools.javac.util.JCDiagnostic; import com.sun.tools.javac.util.JCDiagnostic.DiagnosticPosition; import com.sun.tools.javac.util.List; @@ -393,7 +392,7 @@ private void handleSwitch(JCTree tree, boolean hasUnconditionalPattern, boolean patternSwitch) { if (patternSwitch) { - Type seltype = selector.type.hasTag(BOT) + Type seltype = selector.type.hasTag(BOT) || target.usesReferenceOnlySelectorTypes() ? syms.objectType : selector.type; @@ -496,14 +495,12 @@ private void handleSwitch(JCTree tree, .toArray(s -> new LoadableConstant[s]); boolean enumSelector = seltype.tsym.isEnum(); - boolean primitiveSelector = seltype.isPrimitive(); Name bootstrapName = enumSelector ? names.enumSwitch : names.typeSwitch; MethodSymbol bsm = rs.resolveInternalMethod(tree.pos(), env, syms.switchBootstrapsType, bootstrapName, staticArgTypes, List.nil()); - Type resolvedSelectorType = seltype; MethodType indyType = new MethodType( - List.of(resolvedSelectorType, syms.intType), + List.of(seltype, syms.intType), syms.intType, List.nil(), syms.methodClass diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/Target.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/Target.java index 94b77016d86..35461b031f2 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/Target.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/jvm/Target.java @@ -226,4 +226,10 @@ public boolean obsoleteAccStrict() { public boolean optimizeOuterThis() { return compareTo(JDK1_18) >= 0; } + + /** Releases prior to JDK 23 expect a less precise SwitchBootstraps.typeSwitch signature on the selectorType + */ + public boolean usesReferenceOnlySelectorTypes() { + return compareTo(Target.JDK1_23) < 0; + } } diff --git a/src/jdk.crypto.cryptoki/unix/native/libj2pkcs11/p11_md.c b/src/jdk.crypto.cryptoki/unix/native/libj2pkcs11/p11_md.c index 85b9cad03a7..099ef00c6d9 100644 --- a/src/jdk.crypto.cryptoki/unix/native/libj2pkcs11/p11_md.c +++ b/src/jdk.crypto.cryptoki/unix/native/libj2pkcs11/p11_md.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. */ /* Copyright (c) 2002 Graz University of Technology. All rights reserved. @@ -103,7 +103,6 @@ JNIEXPORT jobject JNICALL Java_sun_security_pkcs11_wrapper_PKCS11_connect /* * Load the PKCS #11 DLL */ - dlerror(); /* clear any old error message not fetched */ #ifdef DEBUG hModule = dlopen(libraryNameStr, RTLD_NOW); #else @@ -124,9 +123,6 @@ JNIEXPORT jobject JNICALL Java_sun_security_pkcs11_wrapper_PKCS11_connect goto cleanup; } - // clear any old error message not fetched - dlerror(); - #ifdef DEBUG C_GetInterfaceList = (CK_C_GetInterfaceList) dlsym(hModule, "C_GetInterfaceList"); @@ -158,47 +154,42 @@ JNIEXPORT jobject JNICALL Java_sun_security_pkcs11_wrapper_PKCS11_connect } #endif - if (jGetFunctionList != NULL) { + // if none specified, then we try 3.0 API first before trying 2.40 + if (jGetFunctionList == NULL) { + C_GetInterface = (CK_C_GetInterface) dlsym(hModule, "C_GetInterface"); + if (C_GetInterface != NULL) { + TRACE0("Connect: Found C_GetInterface func\n"); + rv = (C_GetInterface)(NULL, NULL, &interface, 0L); + // don't use ckAssertReturnValueOK as we want to continue trying + // C_GetFunctionList() or method named by "getFunctionListStr" + if (rv == CKR_OK) { + goto setModuleData; + } + } + getFunctionListStr = "C_GetFunctionList"; + } else { getFunctionListStr = (*env)->GetStringUTFChars(env, jGetFunctionList, 0); if (getFunctionListStr == NULL) { goto cleanup; } - C_GetFunctionList = (CK_C_GetFunctionList) dlsym(hModule, + } + + dlerror(); // clear any old error message not fetched + C_GetFunctionList = (CK_C_GetFunctionList) dlsym(hModule, getFunctionListStr); + if (C_GetFunctionList == NULL) { if ((systemErrorMessage = dlerror()) != NULL){ + TRACE2("Connect: error finding %s func: %s\n", getFunctionListStr, + systemErrorMessage); p11ThrowIOException(env, systemErrorMessage); - goto cleanup; - } - if (C_GetFunctionList == NULL) { + } else { TRACE1("Connect: No %s func\n", getFunctionListStr); p11ThrowIOException(env, "ERROR: C_GetFunctionList == NULL"); - goto cleanup; } - TRACE1("Connect: Found %s func\n", getFunctionListStr); - } else { - // if none specified, then we try 3.0 API first before trying 2.40 - C_GetInterface = (CK_C_GetInterface) dlsym(hModule, "C_GetInterface"); - if ((C_GetInterface != NULL) && (dlerror() == NULL)) { - TRACE0("Connect: Found C_GetInterface func\n"); - rv = (C_GetInterface)(NULL, NULL, &interface, 0L); - if (ckAssertReturnValueOK(env, rv) == CK_ASSERT_OK) { - goto setModuleData; - } - } - C_GetFunctionList = (CK_C_GetFunctionList) dlsym(hModule, - "C_GetFunctionList"); - if ((systemErrorMessage = dlerror()) != NULL){ - p11ThrowIOException(env, systemErrorMessage); - goto cleanup; - } - if (C_GetFunctionList == NULL) { - TRACE0("Connect: No C_GetFunctionList func\n"); - p11ThrowIOException(env, "ERROR: C_GetFunctionList == NULL"); - goto cleanup; - } - TRACE0("Connect: Found C_GetFunctionList func\n"); + goto cleanup; } + TRACE1("Connect: Found %s func\n", getFunctionListStr); setModuleData: /* diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/code/CodeBlob.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/code/CodeBlob.java index 976af5bac20..f546a8cea53 100644 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/code/CodeBlob.java +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/code/CodeBlob.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2021, 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 @@ -42,10 +42,9 @@ public class CodeBlob extends VMObject { private static AddressField nameField; private static CIntegerField sizeField; private static CIntegerField headerSizeField; - private static AddressField contentBeginField; - private static AddressField codeBeginField; - private static AddressField codeEndField; - private static AddressField dataEndField; + private static CIntegerField relocationSizeField; + private static CIntegerField contentOffsetField; + private static CIntegerField codeOffsetField; private static CIntegerField frameCompleteOffsetField; private static CIntegerField dataOffsetField; private static CIntegerField frameSizeField; @@ -63,11 +62,10 @@ private static void initialize(TypeDataBase db) { nameField = type.getAddressField("_name"); sizeField = type.getCIntegerField("_size"); headerSizeField = type.getCIntegerField("_header_size"); + relocationSizeField = type.getCIntegerField("_relocation_size"); + contentOffsetField = type.getCIntegerField("_content_offset"); + codeOffsetField = type.getCIntegerField("_code_offset"); frameCompleteOffsetField = type.getCIntegerField("_frame_complete_offset"); - contentBeginField = type.getAddressField("_content_begin"); - codeBeginField = type.getAddressField("_code_begin"); - codeEndField = type.getAddressField("_code_end"); - dataEndField = type.getAddressField("_data_end"); dataOffsetField = type.getCIntegerField("_data_offset"); frameSizeField = type.getCIntegerField("_frame_size"); oopMapsField = type.getAddressField("_oop_maps"); @@ -86,30 +84,35 @@ public void update(Observable o, Object data) { }); } - public Address headerBegin() { return getAddress(); } + public Address headerBegin() { return getAddress(); } - public Address headerEnd() { return getAddress().addOffsetTo(getHeaderSize()); } + public Address headerEnd() { return getAddress().addOffsetTo(getHeaderSize()); } - public Address contentBegin() { return contentBeginField.getValue(addr); } + public Address contentBegin() { return headerBegin().addOffsetTo(getContentOffset()); } - public Address contentEnd() { return headerBegin().addOffsetTo(getDataOffset()); } + public Address contentEnd() { return headerBegin().addOffsetTo(getDataOffset()); } - public Address codeBegin() { return codeBeginField.getValue(addr); } + public Address codeBegin() { return headerBegin().addOffsetTo(getCodeOffset()); } - public Address codeEnd() { return codeEndField.getValue(addr); } + public Address codeEnd() { return headerBegin().addOffsetTo(getDataOffset()); } - public Address dataBegin() { return headerBegin().addOffsetTo(getDataOffset()); } + public Address dataBegin() { return headerBegin().addOffsetTo(getDataOffset()); } - public Address dataEnd() { return dataEndField.getValue(addr); } + public Address dataEnd() { return headerBegin().addOffsetTo(getSize()); } + + // Offsets + public int getContentOffset() { return (int) contentOffsetField.getValue(addr); } + + public int getCodeOffset() { return (int) codeOffsetField .getValue(addr); } public long getFrameCompleteOffset() { return frameCompleteOffsetField.getValue(addr); } - public int getDataOffset() { return (int) dataOffsetField.getValue(addr); } + public int getDataOffset() { return (int) dataOffsetField.getValue(addr); } // Sizes - public int getSize() { return (int) sizeField.getValue(addr); } + public int getSize() { return (int) sizeField.getValue(addr); } - public int getHeaderSize() { return (int) headerSizeField.getValue(addr); } + public int getHeaderSize() { return (int) headerSizeField.getValue(addr); } public long getFrameSizeWords() { return (int) frameSizeField.getValue(addr); diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/code/CompiledMethod.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/code/CompiledMethod.java deleted file mode 100644 index cae1c5389d9..00000000000 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/code/CompiledMethod.java +++ /dev/null @@ -1,76 +0,0 @@ -/* - * Copyright (c) 2016, 2020, 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 sun.jvm.hotspot.code; - -import java.util.*; - -import sun.jvm.hotspot.debugger.Address; -import sun.jvm.hotspot.oops.*; -import sun.jvm.hotspot.runtime.*; -import sun.jvm.hotspot.types.*; -import sun.jvm.hotspot.utilities.*; -import sun.jvm.hotspot.utilities.Observable; -import sun.jvm.hotspot.utilities.Observer; - -public abstract class CompiledMethod extends CodeBlob { - private static AddressField methodField; - private static AddressField deoptHandlerBeginField; - private static AddressField deoptMhHandlerBeginField; - private static AddressField scopesDataBeginField; - - static { - VM.registerVMInitializedObserver(new Observer() { - public void update(Observable o, Object data) { - initialize(VM.getVM().getTypeDataBase()); - } - }); - } - - private static void initialize(TypeDataBase db) { - Type type = db.lookupType("CompiledMethod"); - - methodField = type.getAddressField("_method"); - deoptHandlerBeginField = type.getAddressField("_deopt_handler_begin"); - deoptMhHandlerBeginField = type.getAddressField("_deopt_mh_handler_begin"); - scopesDataBeginField = type.getAddressField("_scopes_data_begin"); - } - - public CompiledMethod(Address addr) { - super(addr); - } - - public Method getMethod() { - return (Method)Metadata.instantiateWrapperFor(methodField.getValue(addr)); - } - - public Address deoptHandlerBegin() { return deoptHandlerBeginField.getValue(addr); } - public Address deoptMhHandlerBegin() { return deoptMhHandlerBeginField.getValue(addr); } - public Address scopesDataBegin() { return scopesDataBeginField.getValue(addr); } - - public static int getMethodOffset() { return (int) methodField.getOffset(); } - - @Override - public boolean isCompiled() { - return true; - } -} diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/code/NMethod.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/code/NMethod.java index 6263f8aa22c..c1f16c7957e 100644 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/code/NMethod.java +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/code/NMethod.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 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,6 +27,7 @@ import java.io.*; import java.util.*; import sun.jvm.hotspot.debugger.*; +import sun.jvm.hotspot.memory.*; import sun.jvm.hotspot.oops.*; import sun.jvm.hotspot.runtime.*; import sun.jvm.hotspot.types.*; @@ -34,8 +35,9 @@ import sun.jvm.hotspot.utilities.Observable; import sun.jvm.hotspot.utilities.Observer; -public class NMethod extends CompiledMethod { +public class NMethod extends CodeBlob { private static long pcDescSize; + private static AddressField methodField; /** != InvocationEntryBci if this nmethod is an on-stack replacement method */ private static CIntegerField entryBCIField; /** To support simple linked-list chaining of nmethods */ @@ -43,10 +45,13 @@ public class NMethod extends CompiledMethod { /** Offsets for different nmethod parts */ private static CIntegerField exceptionOffsetField; + private static CIntegerField deoptHandlerOffsetField; + private static CIntegerField deoptMhHandlerOffsetField; private static CIntegerField origPCOffsetField; private static CIntegerField stubOffsetField; private static CIntegerField oopsOffsetField; private static CIntegerField metadataOffsetField; + private static CIntegerField scopesDataOffsetField; private static CIntegerField scopesPCsOffsetField; private static CIntegerField dependenciesOffsetField; private static CIntegerField handlerTableOffsetField; @@ -76,14 +81,18 @@ public void update(Observable o, Object data) { private static void initialize(TypeDataBase db) { Type type = db.lookupType("nmethod"); + methodField = type.getAddressField("_method"); entryBCIField = type.getCIntegerField("_entry_bci"); osrLinkField = type.getAddressField("_osr_link"); exceptionOffsetField = type.getCIntegerField("_exception_offset"); + deoptHandlerOffsetField = type.getCIntegerField("_deopt_handler_offset"); + deoptMhHandlerOffsetField = type.getCIntegerField("_deopt_mh_handler_offset"); origPCOffsetField = type.getCIntegerField("_orig_pc_offset"); stubOffsetField = type.getCIntegerField("_stub_offset"); oopsOffsetField = type.getCIntegerField("_oops_offset"); metadataOffsetField = type.getCIntegerField("_metadata_offset"); + scopesDataOffsetField = type.getCIntegerField("_scopes_data_offset"); scopesPCsOffsetField = type.getCIntegerField("_scopes_pcs_offset"); dependenciesOffsetField = type.getCIntegerField("_dependencies_offset"); handlerTableOffsetField = type.getCIntegerField("_handler_table_offset"); @@ -105,6 +114,10 @@ public Address getAddress() { return addr; } + public Method getMethod() { + return (Method)Metadata.instantiateWrapperFor(methodField.getValue(addr)); + } + // Type info public boolean isNMethod() { return true; } public boolean isJavaMethod() { return !getMethod().isNative(); } @@ -117,12 +130,15 @@ public Address getAddress() { public Address instsBegin() { return codeBegin(); } public Address instsEnd() { return headerBegin().addOffsetTo(getStubOffset()); } public Address exceptionBegin() { return headerBegin().addOffsetTo(getExceptionOffset()); } + public Address deoptHandlerBegin() { return headerBegin().addOffsetTo(getDeoptHandlerOffset()); } + public Address deoptMhHandlerBegin() { return headerBegin().addOffsetTo(getDeoptMhHandlerOffset()); } public Address stubBegin() { return headerBegin().addOffsetTo(getStubOffset()); } public Address stubEnd() { return headerBegin().addOffsetTo(getOopsOffset()); } public Address oopsBegin() { return headerBegin().addOffsetTo(getOopsOffset()); } public Address oopsEnd() { return headerBegin().addOffsetTo(getMetadataOffset()); } public Address metadataBegin() { return headerBegin().addOffsetTo(getMetadataOffset()); } - public Address metadataEnd() { return scopesDataBegin(); } + public Address metadataEnd() { return headerBegin().addOffsetTo(getScopesDataOffset()); } + public Address scopesDataBegin() { return headerBegin().addOffsetTo(getScopesDataOffset()); } public Address scopesDataEnd() { return headerBegin().addOffsetTo(getScopesPCsOffset()); } public Address scopesPCsBegin() { return headerBegin().addOffsetTo(getScopesPCsOffset()); } public Address scopesPCsEnd() { return headerBegin().addOffsetTo(getDependenciesOffset()); } @@ -420,6 +436,7 @@ public Map getSafepoints() { public static int getVerifiedEntryPointOffset() { return (int) verifiedEntryPointField.getOffset(); } public static int getOSREntryPointOffset() { return (int) osrEntryPointField.getOffset(); } public static int getEntryBCIOffset() { return (int) entryBCIField.getOffset(); } + public static int getMethodOffset() { return (int) methodField.getOffset(); } public void print() { printOn(System.out); @@ -497,9 +514,12 @@ public void dumpReplayData(PrintStream out) { private int getEntryBCI() { return (int) entryBCIField .getValue(addr); } private int getExceptionOffset() { return (int) exceptionOffsetField .getValue(addr); } + private int getDeoptHandlerOffset() { return (int) deoptHandlerOffsetField .getValue(addr); } + private int getDeoptMhHandlerOffset() { return (int) deoptMhHandlerOffsetField.getValue(addr); } private int getStubOffset() { return (int) stubOffsetField .getValue(addr); } private int getOopsOffset() { return (int) oopsOffsetField .getValue(addr); } private int getMetadataOffset() { return (int) metadataOffsetField .getValue(addr); } + private int getScopesDataOffset() { return (int) scopesDataOffsetField .getValue(addr); } private int getScopesPCsOffset() { return (int) scopesPCsOffsetField .getValue(addr); } private int getDependenciesOffset() { return (int) dependenciesOffsetField.getValue(addr); } private int getHandlerTableOffset() { return (int) handlerTableOffsetField.getValue(addr); } diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/tools/PStack.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/tools/PStack.java index 038c871a9f9..8f09dcc48ef 100644 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/tools/PStack.java +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/tools/PStack.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2022, 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 @@ -140,7 +140,7 @@ public void run(PrintStream out, Debugger dbg) { CodeBlob cb = c.findBlobUnsafe(pc); if (cb.isNMethod()) { if (cb.isNativeMethod()) { - out.print(((CompiledMethod)cb).getMethod().externalNameAndSignature()); + out.print(((NMethod)cb).getMethod().externalNameAndSignature()); long diff = pc.minus(cb.codeBegin()); if (diff != 0L) { out.print(" + 0x" + Long.toHexString(diff)); diff --git a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/aarch64/AArch64.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/aarch64/AArch64.java index bb8bf22b38e..609e01a8db1 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/aarch64/AArch64.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/aarch64/AArch64.java @@ -190,7 +190,6 @@ public enum CPUFeature implements CPUFeatureName { */ public enum Flag { UseCRC32, - UseNeon, UseSIMDForMemoryOps, AvoidUnalignedAccesses, UseLSE, diff --git a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotVMConfig.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotVMConfig.java index 7259e0fcab0..c49f24efed5 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotVMConfig.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotVMConfig.java @@ -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 @@ -149,7 +149,7 @@ long prototypeMarkWord() { final int methodVtableIndexOffset = getFieldOffset("Method::_vtable_index", Integer.class, "int"); final int methodDataOffset = getFieldOffset("Method::_method_data", Integer.class, "MethodData*"); - final int methodCodeOffset = getFieldOffset("Method::_code", Integer.class, "CompiledMethod*"); + final int methodCodeOffset = getFieldOffset("Method::_code", Integer.class, "nmethod*"); final int methodFlagsForceInline = getConstant("MethodFlags::_misc_force_inline", Integer.class); final int methodFlagsDontInline = getConstant("MethodFlags::_misc_dont_inline", Integer.class); diff --git a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/aarch64/AArch64HotSpotJVMCIBackendFactory.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/aarch64/AArch64HotSpotJVMCIBackendFactory.java index 9d7d4748fdd..890a3357678 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/aarch64/AArch64HotSpotJVMCIBackendFactory.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/aarch64/AArch64HotSpotJVMCIBackendFactory.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2021, 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 @@ -58,9 +58,6 @@ private static EnumSet computeFlags(AArch64HotSpotVMConfig config) if (config.useCRC32) { flags.add(AArch64.Flag.UseCRC32); } - if (config.useNeon) { - flags.add(AArch64.Flag.UseNeon); - } if (config.useSIMDForMemoryOps) { flags.add(AArch64.Flag.UseSIMDForMemoryOps); } diff --git a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/aarch64/AArch64HotSpotVMConfig.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/aarch64/AArch64HotSpotVMConfig.java index 720bebb30cf..a388687c69a 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/aarch64/AArch64HotSpotVMConfig.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/aarch64/AArch64HotSpotVMConfig.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2022, 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 @@ -44,7 +44,6 @@ class AArch64HotSpotVMConfig extends HotSpotVMConfigAccess { * These flags are set based on the corresponding command line flags. */ final boolean useCRC32 = getFlag("UseCRC32", Boolean.class); - final boolean useNeon = getFlag("UseNeon", Boolean.class); final boolean useSIMDForMemoryOps = getFlag("UseSIMDForMemoryOps", Boolean.class); final boolean avoidUnalignedAccesses = getFlag("AvoidUnalignedAccesses", Boolean.class); final boolean useLSE = getFlag("UseLSE", Boolean.class); diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/AnnotationTypeMemberWriter.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/AnnotationTypeMemberWriter.java index 6c0337513d0..8f8585ecc62 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/AnnotationTypeMemberWriter.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/AnnotationTypeMemberWriter.java @@ -100,7 +100,7 @@ protected void buildAnnotationTypeMember(Content target) { buildAnnotationTypeMemberChildren(div); annotationContent.add(div); memberList.add(writer.getMemberListItem(annotationContent)); - writer.tableOfContents.addLink(htmlIds.forMember(typeElement, (ExecutableElement) member), + writer.tableOfContents.addLink(htmlIds.forMember((ExecutableElement) member).getFirst(), Text.of(name(member))); } Content annotationDetails = getAnnotationDetails(annotationDetailsHeader, memberList); @@ -210,7 +210,7 @@ protected Content getAnnotationHeaderContent(Element member) { Text.of(name(member))); content.add(heading); return HtmlTree.SECTION(HtmlStyle.detail, content) - .setId(htmlIds.forMember(typeElement, (ExecutableElement) member)); + .setId(htmlIds.forMember((ExecutableElement) member).getFirst()); } protected Content getSignature(Element member) { diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/ConstructorWriter.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/ConstructorWriter.java index 5782dcd06a4..1c4af2faf97 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/ConstructorWriter.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/ConstructorWriter.java @@ -116,7 +116,7 @@ protected void buildConstructorDoc(Content target) { buildTagInfo(div); constructorContent.add(div); memberList.add(getMemberListItem(constructorContent)); - writer.tableOfContents.addLink(htmlIds.forMember(currentConstructor), + writer.tableOfContents.addLink(htmlIds.forMember(currentConstructor).getFirst(), Text.of(utils.getSimpleName(constructor) + utils.makeSignature(currentConstructor, typeElement, false, true))); } @@ -189,13 +189,14 @@ protected Content getConstructorHeaderContent(ExecutableElement constructor) { Content content = new ContentBuilder(); var heading = HtmlTree.HEADING(Headings.TypeDeclaration.MEMBER_HEADING, Text.of(name(constructor))); - HtmlId erasureAnchor = htmlIds.forErasure(constructor); - if (erasureAnchor != null) { - heading.setId(erasureAnchor); + + var anchors = htmlIds.forMember(constructor); + if (anchors.size() > 1) { + heading.setId(anchors.getLast()); } content.add(heading); return HtmlTree.SECTION(HtmlStyle.detail, content) - .setId(htmlIds.forMember(constructor)); + .setId(anchors.getFirst()); } protected Content getSignature(ExecutableElement constructor) { diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/HtmlDocletWriter.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/HtmlDocletWriter.java index 7295ba6d513..25ec603a064 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/HtmlDocletWriter.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/HtmlDocletWriter.java @@ -1037,7 +1037,7 @@ public Content getDocLink(HtmlLinkInfo.Kind context, TypeElement typeElement, El if (utils.isExecutableElement(element)) { ExecutableElement ee = (ExecutableElement)element; - HtmlId id = isProperty ? htmlIds.forProperty(ee) : htmlIds.forMember(ee); + HtmlId id = isProperty ? htmlIds.forProperty(ee) : htmlIds.forMember(ee).getFirst(); return getLink(new HtmlLinkInfo(configuration, context, typeElement) .label(label) .fragment(id.name()) diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/HtmlIds.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/HtmlIds.java index 10e91cc1204..fc772107274 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/HtmlIds.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/HtmlIds.java @@ -25,11 +25,16 @@ package jdk.javadoc.internal.doclets.formats.html; +import java.util.HashMap; +import java.util.HashSet; import java.util.List; import java.util.Locale; import java.util.Map; import java.util.Set; +import java.util.stream.Collectors; +import java.util.stream.Stream; import javax.lang.model.element.Element; +import javax.lang.model.element.ElementKind; import javax.lang.model.element.ExecutableElement; import javax.lang.model.element.PackageElement; import javax.lang.model.element.TypeElement; @@ -159,34 +164,89 @@ HtmlId forClass(TypeElement element) { } /** - * Returns an id for an executable element, suitable for use when the - * simple name and argument list will be unique within the page, such as - * in the page for the declaration of the enclosing class or interface. + * {@return a non-empty list of ids to a constructor or a method} + * The ids from the returned list are alternative: the given constructor + * or method can be equally referred to by any of those ids. * - * @param element the element - * - * @return the id + * @param executable a constructor or method */ - HtmlId forMember(ExecutableElement element) { + List forMember(ExecutableElement executable) { + var htmlId = ids.get(executable); + if (htmlId != null) + return htmlId; + if (executable.getKind() != ElementKind.CONSTRUCTOR + && executable.getKind() != ElementKind.METHOD) + throw new IllegalArgumentException(String.valueOf(executable.getKind())); + var vmt = configuration.getVisibleMemberTable((TypeElement) executable.getEnclosingElement()); + var ctors = vmt.getVisibleMembers(VisibleMemberTable.Kind.CONSTRUCTORS); + var methods = vmt.getVisibleMembers(VisibleMemberTable.Kind.METHODS); + record Erased(ExecutableElement element, HtmlId id) { } + // split elements into two buckets: + // - elements whose erased id is present + // - elements whose erased id is absent (i.e. is null) + enum ErasedId { PRESENT, ABSENT } + var buckets = Stream.concat(ctors.stream(), methods.stream()) + .map(e -> (ExecutableElement) e) + .map(e -> new Erased(e, forErasure(e))) + .collect(Collectors.groupingBy(erased -> erased.id == null ? + ErasedId.ABSENT : ErasedId.PRESENT)); + var dups = new HashSet(); + // the order of elements in each bucket is important for reproducibility + // of ids: the same executable element must have the same id in any + // javadoc run + // Use simple id, unless we have to use erased id; for that, do the + // following _in order_: + // 1. Map all elements that can _only_ be addressed by the simple id + for (var e : buckets.getOrDefault(ErasedId.ABSENT, List.of())) { + var simpleId = forMember0(e.element); + ids.put(e.element, List.of(simpleId)); + boolean added = dups.add(simpleId.name()); + // we assume that the simple id for an executable member that + // does not use type parameters is unique + assert added; + } + // 2. Map all elements that can be addressed by simple id or erased id; + // if the simple id is not yet used, use it, otherwise use the erased id + for (var e : buckets.getOrDefault(ErasedId.PRESENT, List.of())) { + var simpleId = forMember0(e.element); + if (dups.add(simpleId.name())) { + ids.put(e.element, List.of(simpleId, e.id)); + } else { + ids.put(e.element, List.of(e.id)); + boolean added = dups.add(e.id.name()); + // Not only must an erased id not clash with any simple id, + // but it must also not clash with any other erased id. + // The latter is because JLS 8.4.2. Method Signature: + // it is a compile-time error to declare two methods + // with override-equivalent signatures in a class + assert added; + } + } + // Safety net: if for whatever reason we cannot find the element + // among those we just expanded, return the simple id. It might + // not be always right, but at least it won't fail. + // + // - one example where it might happen is linking to an inherited + // undocumented method (see test case T5093723) + // TODO the above will need to be revisited if and when we redesign + // VisibleMemberTable, which currently cannot correctly return the + // owner of such a method + // + // - another example is annotation interface methods: they are not + // included in VisibleMemberTable.Kind.METHODS and so cannot be + // found among them + return ids.computeIfAbsent(executable, e -> List.of(forMember0(e))); + } + + private final Map> ids = new HashMap<>(); + + private HtmlId forMember0(ExecutableElement element) { String a = element.getSimpleName() + utils.makeSignature(element, null, true, true); // utils.makeSignature includes spaces return HtmlId.of(a.replaceAll("\\s", "")); } - /** - * Returns an id for an executable element, including the context - * of its documented enclosing class or interface. - * - * @param typeElement the enclosing class or interface - * @param member the element - * - * @return the id - */ - HtmlId forMember(TypeElement typeElement, ExecutableElement member) { - return HtmlId.of(utils.getSimpleName(member) + utils.signature(member, typeElement)); - } - /** * Returns an id for a field, suitable for use when the simple name * will be unique within the page, such as in the page for the @@ -229,7 +289,7 @@ HtmlId forMember(TypeElement typeElement, VariableElement member) { * @param executableElement the element to anchor to * @return the 1.4.x style anchor for the executable element */ - protected HtmlId forErasure(ExecutableElement executableElement) { + private HtmlId forErasure(ExecutableElement executableElement) { final StringBuilder buf = new StringBuilder(executableElement.getSimpleName().toString()); buf.append("("); List parameters = executableElement.getParameters(); @@ -483,7 +543,7 @@ public static HtmlId forTabPanel(HtmlId tableId) { */ public HtmlId forPreviewSection(Element el) { return HtmlId.of("preview-" + switch (el.getKind()) { - case CONSTRUCTOR, METHOD -> forMember((ExecutableElement) el).name(); + case CONSTRUCTOR, METHOD -> forMember((ExecutableElement) el).getFirst().name(); case PACKAGE -> forPackage((PackageElement) el).name(); default -> utils.getFullyQualifiedName(el, false); }); @@ -497,7 +557,7 @@ public HtmlId forPreviewSection(Element el) { * @return the id */ public HtmlId forRestrictedSection(ExecutableElement el) { - return HtmlId.of("restricted-" + forMember(el).name()); + return HtmlId.of("restricted-" + forMember(el).getFirst().name()); } /** diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/HtmlIndexBuilder.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/HtmlIndexBuilder.java index d17b795d9c0..51831b23336 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/HtmlIndexBuilder.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/HtmlIndexBuilder.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2022, 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 @@ -128,7 +128,7 @@ private void addContainingInfo(IndexItem item, boolean addModuleInfo) { item.setContainingModule(utils.getFullyQualifiedName(utils.containingModule(element))); } if (utils.isExecutableElement(element)) { - String url = HtmlTree.encodeURL(htmlIds.forMember((ExecutableElement) element).name()); + String url = HtmlTree.encodeURL(htmlIds.forMember((ExecutableElement) element).getFirst().name()); if (!url.equals(item.getLabel())) { item.setUrl(url); } diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/MethodWriter.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/MethodWriter.java index 5f20f360eb6..521616f982b 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/MethodWriter.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/MethodWriter.java @@ -116,7 +116,7 @@ protected void buildMethodDoc(Content detailsList) { buildTagInfo(div); methodContent.add(div); memberList.add(writer.getMemberListItem(methodContent)); - writer.tableOfContents.addLink(htmlIds.forMember(currentMethod), + writer.tableOfContents.addLink(htmlIds.forMember(currentMethod).getFirst(), Text.of(utils.getSimpleName(method) + utils.makeSignature(currentMethod, typeElement, false, true))); } @@ -204,13 +204,13 @@ protected Content getMethodHeader(ExecutableElement method) { Content content = new ContentBuilder(); var heading = HtmlTree.HEADING(Headings.TypeDeclaration.MEMBER_HEADING, Text.of(name(method))); - HtmlId erasureAnchor; - if ((erasureAnchor = htmlIds.forErasure(method)) != null) { - heading.setId(erasureAnchor); + var anchors = htmlIds.forMember(method); + if (anchors.size() > 1) { + heading.setId(anchors.getLast()); } content.add(heading); return HtmlTree.SECTION(HtmlStyle.detail, content) - .setId(htmlIds.forMember(method)); + .setId(anchors.getFirst()); } protected Content getSignature(ExecutableElement method) { @@ -375,7 +375,7 @@ protected static void addOverridden(HtmlDocletWriter writer, var codeOverriddenTypeLink = HtmlTree.CODE(overriddenTypeLink); Content methlink = writer.getLink( new HtmlLinkInfo(writer.configuration, HtmlLinkInfo.Kind.PLAIN, holder) - .fragment(writer.htmlIds.forMember(method).name()) + .fragment(writer.htmlIds.forMember(method).getFirst().name()) .label(method.getSimpleName())); var codeMethLink = HtmlTree.CODE(methlink); var dd = HtmlTree.DD(codeMethLink); diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/util/Comparators.java b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/util/Comparators.java index f1429922742..92c4cd9228a 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/util/Comparators.java +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/toolkit/util/Comparators.java @@ -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 @@ -32,12 +32,14 @@ import javax.lang.model.element.ModuleElement; import javax.lang.model.element.PackageElement; import javax.lang.model.element.TypeElement; +import javax.lang.model.element.TypeParameterElement; import javax.lang.model.element.VariableElement; import javax.lang.model.type.ArrayType; import javax.lang.model.type.PrimitiveType; import javax.lang.model.type.TypeMirror; import javax.lang.model.util.SimpleElementVisitor14; import javax.lang.model.util.SimpleTypeVisitor9; +import java.util.Arrays; import java.util.Comparator; import java.util.List; @@ -143,7 +145,11 @@ public int compare(Element e1, Element e2) { if (result != 0) { return result; } - return compareModuleNames(e1, e2); + result = compareModuleNames(e1, e2); + if (result != 0) { + return result; + } + return compareTypeParameters(e1, e2); } }; } @@ -264,7 +270,10 @@ public int compare(Element e1, Element e2) { result = compareFullyQualifiedNames(e1, e2); if (result != 0) return result; - return compareModuleNames(e1, e2); + result = compareModuleNames(e1, e2); + if (result != 0) + return result; + return compareTypeParameters(e1, e2); } }; } @@ -364,7 +373,14 @@ public int compare(Element e1, Element e2) { if (result != 0) { return result; } - return compareModuleNames(e1, e2); + result = compareModuleNames(e1, e2); + if (result != 0) { + return result; + } + // this might not be needed: if e1 != e2 and both are + // executables they must differ in FQN and thus we + // shouldn't reach here + return compareTypeParameters(e1, e2); } }; } @@ -423,6 +439,21 @@ protected String defaultAction(TypeMirror e, Void p) { }.visit(t); } + protected final int compareTypeParameters(Element e1, Element e2) { + if (!e1.getKind().isExecutable() || !e2.getKind().isExecutable()) + return 0; + var typeParameters1 = ((ExecutableElement) e1).getTypeParameters(); + var typeParameters2 = ((ExecutableElement) e2).getTypeParameters(); + var parameters1 = typeParameters1.toArray(new TypeParameterElement[0]); + var parameters2 = typeParameters2.toArray(new TypeParameterElement[0]); + return Arrays.compare(parameters1, parameters2, (p1, p2) -> { + var bounds1 = p1.getBounds().toArray(new TypeMirror[0]); + var bounds2 = p2.getBounds().toArray(new TypeMirror[0]); + return Arrays.compare(bounds1, bounds2, (b1, b2) -> + utils.compareStrings(true, b1.toString(), b2.toString())); + }); + } + /** * Compares two Elements, typically the name of a method, * field or constructor. diff --git a/src/jdk.jshell/share/classes/jdk/internal/jshell/tool/resources/l10n.properties b/src/jdk.jshell/share/classes/jdk/internal/jshell/tool/resources/l10n.properties index 56af7e2b743..4cf667a3787 100644 --- a/src/jdk.jshell/share/classes/jdk/internal/jshell/tool/resources/l10n.properties +++ b/src/jdk.jshell/share/classes/jdk/internal/jshell/tool/resources/l10n.properties @@ -218,11 +218,19 @@ where possible options include:\n\ \ -q Quiet feedback. Same as: --feedback concise\n\ \ -s Really quiet feedback. Same as: --feedback silent\n\ \ -v Verbose feedback. Same as: --feedback verbose\n\ -\ -J Pass directly to the runtime system.\n\ -\ Use one -J for each runtime flag or flag argument\n\ -\ -R Pass to the remote runtime system.\n\ -\ Use one -R for each remote flag or flag argument\n\ -\ -C Pass to the compiler.\n\ +\ -J passes to the runtime system, but has no effect\n\ +\ on the execution of code snippets. To specify flags\n\ +\ that affect the execution of code snippets, use\n\ +\ -R. Alternatively, use -J with\n\ +\ --execution local.\n\ +\ -R passes to the runtime system only when code\n\ +\ snippets are executed. For example, -R-Dfoo=bar\n\ +\ means that execution of the snippet\n\ +\ System.getProperty("foo") will return "bar".\n\ +\ -C passes to the Java compiler inside JShell.\n\ +\ For example, -C-Xlint enables all the recommended\n\ +\ lint warnings, and -C--release= compiles for\n\ +\ Java SE N, as if --release N was specified.\n\ \ Use one -C for each compiler flag or flag argument\n\ \ --version Print version information and exit\n\ \ --show-version Print version information and continue\n\ diff --git a/src/jdk.jshell/share/man/jshell.1 b/src/jdk.jshell/share/man/jshell.1 index 76ea665e9ef..28160bb49fd 100644 --- a/src/jdk.jshell/share/man/jshell.1 +++ b/src/jdk.jshell/share/man/jshell.1 @@ -122,9 +122,10 @@ module. Specifies the root modules to resolve in addition to the initial module. .TP \f[V]-C\f[R]\f[I]flag\f[R] -Provides a flag to pass to the compiler. -To pass more than one flag, provide an instance of this option for each -flag or flag argument needed. +passes \f[I]flag\f[R] to the Java compiler inside JShell. +For example, \f[V]-C-Xlint\f[R] enables all the recommended lint +warnings, and \f[V]-C--release=\f[R] compiles for Java SE N, as if +--release N was specified. .TP \f[V]--class-path\f[R] \f[I]path\f[R] Specifies the directories and archives that are searched to locate class @@ -187,9 +188,12 @@ Prints a summary of nonstandard options and exits the tool. Nonstandard options are subject to change without notice. .TP \f[V]-J\f[R]\f[I]flag\f[R] -Provides a flag to pass to the runtime system. -To pass more than one flag, provide an instance of this option for each -flag or flag argument needed. +passes \f[I]flag\f[R] to the runtime system, but has no effect on the +execution of code snippets. +To specify flags that affect the execution of code snippets, use +\f[V]-R\f[R]\f[I]flag\f[R]. +Alternatively, use \f[V]-J\f[R]\f[I]flag\f[R] with +\f[V]--execution local\f[R]. .TP \f[V]--module-path\f[R] \f[I]modulepath\f[R] Specifies where to find application modules. @@ -208,9 +212,11 @@ Sets the feedback mode to \f[V]concise\f[R], which is the same as entering \f[V]--feedback concise\f[R]. .TP \f[V]-R\f[R]\f[I]flag\f[R] -Provides a flag to pass to the remote runtime system. -To pass more than one flag, provide an instance of this option for each -flag or flag argument to pass. +passes \f[I]flag\f[R] to the runtime system only when code snippets are +executed. +For example, \f[V]-R-Dfoo=bar\f[R] means that execution of the snippet +\f[V]System.getProperty(\[dq]foo\[dq])\f[R] will return +\f[V]\[dq]bar\[dq]\f[R]. .TP \f[V]-s\f[R] Sets the feedback mode to \f[V]silent\f[R], which is the same as diff --git a/src/utils/hsdis/binutils/hsdis-binutils.c b/src/utils/hsdis/binutils/hsdis-binutils.c index d011dc579b5..fda6a53a6d3 100644 --- a/src/utils/hsdis/binutils/hsdis-binutils.c +++ b/src/utils/hsdis/binutils/hsdis-binutils.c @@ -120,10 +120,8 @@ static const char* format_insn_close(const char* close, disassemble_info* dinfo, char* buf, size_t bufsize); +JNIEXPORT void* -#ifdef DLL_ENTRY - DLL_ENTRY -#endif decode_instructions_virtual(uintptr_t start_va, uintptr_t end_va, unsigned char* buffer, uintptr_t length, event_callback_t event_callback_arg, void* event_stream_arg, @@ -145,10 +143,8 @@ decode_instructions_virtual(uintptr_t start_va, uintptr_t end_va, } /* This is the compatability interface for older version of hotspot */ +JNIEXPORT void* -#ifdef DLL_ENTRY - DLL_ENTRY -#endif decode_instructions(void* start_pv, void* end_pv, event_callback_t event_callback_arg, void* event_stream_arg, printf_callback_t printf_callback_arg, void* printf_stream_arg, diff --git a/src/utils/hsdis/capstone/hsdis-capstone.c b/src/utils/hsdis/capstone/hsdis-capstone.c index 410b88eb2db..015a617fd8a 100644 --- a/src/utils/hsdis/capstone/hsdis-capstone.c +++ b/src/utils/hsdis/capstone/hsdis-capstone.c @@ -120,9 +120,7 @@ static Options parse_options(const char* options, printf_callback_t printf_callb return ops; } -#ifdef _WIN32 -__declspec(dllexport) -#endif +JNIEXPORT void* decode_instructions_virtual(uintptr_t start_va, uintptr_t end_va, unsigned char* buffer, uintptr_t length, event_callback_t event_callback, diff --git a/src/utils/hsdis/hsdis.h b/src/utils/hsdis/hsdis.h index 7e3b8e397af..ecb3a40a5b5 100644 --- a/src/utils/hsdis/hsdis.h +++ b/src/utils/hsdis/hsdis.h @@ -72,6 +72,8 @@ #ifndef SHARED_TOOLS_HSDIS_H #define SHARED_TOOLS_HSDIS_H +#include "jni.h" + #ifdef __cplusplus extern "C" { diff --git a/src/utils/hsdis/llvm/hsdis-llvm.cpp b/src/utils/hsdis/llvm/hsdis-llvm.cpp index 34edfac2113..ec08c9e6004 100644 --- a/src/utils/hsdis/llvm/hsdis-llvm.cpp +++ b/src/utils/hsdis/llvm/hsdis-llvm.cpp @@ -328,6 +328,7 @@ class hsdis_backend : public hsdis_backend_base { }; +JNIEXPORT void* decode_instructions_virtual(uintptr_t start_va, uintptr_t end_va, unsigned char* buffer, uintptr_t length, event_callback_t event_callback_arg, void* event_stream_arg, @@ -342,6 +343,7 @@ void* decode_instructions_virtual(uintptr_t start_va, uintptr_t end_va, } /* This is the compatability interface for older version of hotspot */ +JNIEXPORT void* decode_instructions(void* start_pv, void* end_pv, event_callback_t event_callback_arg, void* event_stream_arg, printf_callback_t printf_callback_arg, void* printf_stream_arg, diff --git a/test/hotspot/gtest/gc/z/test_zPhysicalMemory.cpp b/test/hotspot/gtest/gc/z/test_zPhysicalMemory.cpp index 69861416928..6e44993986b 100644 --- a/test/hotspot/gtest/gc/z/test_zPhysicalMemory.cpp +++ b/test/hotspot/gtest/gc/z/test_zPhysicalMemory.cpp @@ -25,7 +25,27 @@ #include "gc/z/zPhysicalMemory.inline.hpp" #include "unittest.hpp" +class ZAddressOffsetMaxSetter { +private: + const size_t _old_max; + const size_t _old_mask; + +public: + ZAddressOffsetMaxSetter() + : _old_max(ZAddressOffsetMax), + _old_mask(ZAddressOffsetMask) { + ZAddressOffsetMax = size_t(16) * G * 1024; + ZAddressOffsetMask = ZAddressOffsetMax - 1; + } + ~ZAddressOffsetMaxSetter() { + ZAddressOffsetMax = _old_max; + ZAddressOffsetMask = _old_mask; + } +}; + TEST(ZPhysicalMemoryTest, copy) { + ZAddressOffsetMaxSetter setter; + const ZPhysicalMemorySegment seg0(zoffset(0), 100, true); const ZPhysicalMemorySegment seg1(zoffset(200), 100, true); @@ -52,6 +72,8 @@ TEST(ZPhysicalMemoryTest, copy) { } TEST(ZPhysicalMemoryTest, add) { + ZAddressOffsetMaxSetter setter; + const ZPhysicalMemorySegment seg0(zoffset(0), 1, true); const ZPhysicalMemorySegment seg1(zoffset(1), 1, true); const ZPhysicalMemorySegment seg2(zoffset(2), 1, true); @@ -114,6 +136,8 @@ TEST(ZPhysicalMemoryTest, add) { } TEST(ZPhysicalMemoryTest, remove) { + ZAddressOffsetMaxSetter setter; + ZPhysicalMemory pmem; pmem.add_segment(ZPhysicalMemorySegment(zoffset(10), 10, true)); @@ -130,6 +154,8 @@ TEST(ZPhysicalMemoryTest, remove) { } TEST(ZPhysicalMemoryTest, split) { + ZAddressOffsetMaxSetter setter; + ZPhysicalMemory pmem; pmem.add_segment(ZPhysicalMemorySegment(zoffset(0), 10, true)); @@ -158,6 +184,8 @@ TEST(ZPhysicalMemoryTest, split) { } TEST(ZPhysicalMemoryTest, split_committed) { + ZAddressOffsetMaxSetter setter; + ZPhysicalMemory pmem0; pmem0.add_segment(ZPhysicalMemorySegment(zoffset(0), 10, true)); pmem0.add_segment(ZPhysicalMemorySegment(zoffset(10), 10, false)); @@ -172,3 +200,20 @@ TEST(ZPhysicalMemoryTest, split_committed) { EXPECT_EQ(pmem1.nsegments(), 2); EXPECT_EQ(pmem1.size(), 20u); } + +TEST(ZPhysicalMemoryTest, limits) { + ZAddressOffsetMaxSetter setter; + + const size_t HalfZAddressOffsetMax = ZAddressOffsetMax >> 1; + ZPhysicalMemory pmem0; + pmem0.add_segment(ZPhysicalMemorySegment(zoffset(0), HalfZAddressOffsetMax, true)); + pmem0.add_segment(ZPhysicalMemorySegment(zoffset(HalfZAddressOffsetMax), HalfZAddressOffsetMax, false)); + EXPECT_EQ(pmem0.nsegments(), 2); + EXPECT_EQ(pmem0.size(), ZAddressOffsetMax); + + ZPhysicalMemory pmem1 = pmem0.split_committed(); + EXPECT_EQ(pmem0.nsegments(), 1); + EXPECT_EQ(pmem0.size(), HalfZAddressOffsetMax); + EXPECT_EQ(pmem1.nsegments(), 1); + EXPECT_EQ(pmem1.size(), HalfZAddressOffsetMax); +} diff --git a/test/hotspot/gtest/oops/test_markWord.cpp b/test/hotspot/gtest/oops/test_markWord.cpp index 2797bafc032..36abcce3e44 100644 --- a/test/hotspot/gtest/oops/test_markWord.cpp +++ b/test/hotspot/gtest/oops/test_markWord.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 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 @@ -88,11 +88,11 @@ TEST_VM(markWord, printing) { ObjectLocker ol(h_obj, THREAD); assert_test_pattern(h_obj, "locked"); } - assert_test_pattern(h_obj, "is_neutral no_hash"); + assert_test_pattern(h_obj, "is_unlocked no_hash"); // Hash the object then print it. intx hash = h_obj->identity_hash(); - assert_test_pattern(h_obj, "is_neutral hash=0x"); + assert_test_pattern(h_obj, "is_unlocked hash=0x"); // Wait gets the lock inflated. { diff --git a/test/hotspot/gtest/oops/test_typeArrayOop.cpp b/test/hotspot/gtest/oops/test_typeArrayOop.cpp index 2d9c8cfd990..a7565a23d58 100644 --- a/test/hotspot/gtest/oops/test_typeArrayOop.cpp +++ b/test/hotspot/gtest/oops/test_typeArrayOop.cpp @@ -36,7 +36,7 @@ TEST_VM(typeArrayOopDesc, bool_at_put) { char* addr = align_up(mem, 16); typeArrayOop o = (typeArrayOop) cast_to_oop(addr); - o->set_klass(Universe::boolArrayKlassObj()); + o->set_klass(Universe::boolArrayKlass()); o->set_length(10); diff --git a/test/hotspot/jtreg/compiler/c2/ClearArray.java b/test/hotspot/jtreg/compiler/c2/ClearArray.java index 55d717c3119..25ff254c44f 100644 --- a/test/hotspot/jtreg/compiler/c2/ClearArray.java +++ b/test/hotspot/jtreg/compiler/c2/ClearArray.java @@ -31,6 +31,8 @@ * -XX:InitArrayShortSize=32768 -XX:-IdealizeClearArrayNode compiler.c2.ClearArray * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+IgnoreUnrecognizedVMOptions -XX:-TieredCompilation -Xbatch * -XX:InitArrayShortSize=32768 -XX:-IdealizeClearArrayNode -XX:UseAVX=3 compiler.c2.ClearArray + * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+IgnoreUnrecognizedVMOptions -XX:-TieredCompilation -Xbatch + * -XX:InitArrayShortSize=32768 -XX:MaxVectorSize=8 -XX:-IdealizeClearArrayNode -XX:UseAVX=3 compiler.c2.ClearArray */ package compiler.c2; diff --git a/test/hotspot/jtreg/compiler/c2/TestLWLockingCodeGen.java b/test/hotspot/jtreg/compiler/c2/TestLWLockingCodeGen.java new file mode 100644 index 00000000000..ad91ba0b02e --- /dev/null +++ b/test/hotspot/jtreg/compiler/c2/TestLWLockingCodeGen.java @@ -0,0 +1,38 @@ +/* + * Copyright Amazon.com Inc. 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 + * @summary Tests correct code generation of lightweight locking when using -XX:+ShowMessageBoxOnError; times-out on failure + * @bug 8329726 + * @run main/othervm -XX:+ShowMessageBoxOnError -Xcomp -XX:-TieredCompilation -XX:CompileOnly=TestLWLockingCodeGen::sync TestLWLockingCodeGen + */ +public class TestLWLockingCodeGen { + private static int val = 0; + public static void main(String[] args) { + sync(); + } + private static synchronized void sync() { + val = val + (int)(Math.random() * 42); + } +} diff --git a/test/hotspot/jtreg/compiler/c2/irTests/scalarReplacement/AllocationMergesTests.java b/test/hotspot/jtreg/compiler/c2/irTests/scalarReplacement/AllocationMergesTests.java index 00afe7a330b..a3bbf0f4c33 100644 --- a/test/hotspot/jtreg/compiler/c2/irTests/scalarReplacement/AllocationMergesTests.java +++ b/test/hotspot/jtreg/compiler/c2/irTests/scalarReplacement/AllocationMergesTests.java @@ -46,6 +46,7 @@ public static void main(String[] args) { "-XX:CompileCommand=inline,*::charAt*", "-XX:CompileCommand=inline,*PicturePositions::*", "-XX:CompileCommand=inline,*Point::*", + "-XX:CompileCommand=inline,*Nested::*", "-XX:CompileCommand=exclude,*::dummy*"); } @@ -92,7 +93,9 @@ public static void main(String[] args) { "testSRAndNSR_NoTrap_C2", "testSRAndNSR_Trap_C2", "testString_one_C2", - "testString_two_C2" + "testString_two_C2", + "testLoadNarrowKlass_C2", + "testReReduce_C2" }) public void runner(RunInfo info) { invocations++; @@ -147,6 +150,8 @@ public void runner(RunInfo info) { Asserts.assertEQ(testSRAndNSR_NoTrap_Interp(cond1, x, y), testSRAndNSR_NoTrap_C2(cond1, x, y)); Asserts.assertEQ(testString_one_Interp(cond1), testString_one_C2(cond1)); Asserts.assertEQ(testString_two_Interp(cond1), testString_two_C2(cond1)); + Asserts.assertEQ(testLoadNarrowKlass_Interp(cond1), testLoadNarrowKlass_C2(cond1)); + Asserts.assertEQ(testReReduce_Interp(cond1, x, y), testReReduce_C2(cond1, x, y)); Asserts.assertEQ(testSRAndNSR_Trap_Interp(false, cond1, cond2, x, y), testSRAndNSR_Trap_C2(info.isTestC2Compiled("testSRAndNSR_Trap_C2"), cond1, cond2, x, y)); @@ -295,8 +300,7 @@ int testPollutedPolymorphic(boolean cond, int l) { } @Test - @IR(counts = { IRNode.ALLOC, "2" }) - // Merge won't be reduced because the inputs to the Phi have different Klasses + @IR(failOn = { IRNode.ALLOC }) int testPollutedPolymorphic_C2(boolean cond, int l) { return testPollutedPolymorphic(cond, l); } @DontCompile @@ -404,8 +408,7 @@ int testCondAfterMergeWithNull(boolean cond1, boolean cond2, int x, int y) { } @Test - @IR(counts = { IRNode.ALLOC, "1" }) - // The merge won't be simplified because the merge with NULL + @IR(failOn = { IRNode.ALLOC }) int testCondAfterMergeWithNull_C2(boolean cond1, boolean cond2, int x, int y) { return testCondAfterMergeWithNull(cond1, cond2, x, y); } @DontCompile @@ -510,7 +513,6 @@ int testCmpMergeWithNull_Second(boolean cond, int x, int y) { @Test @IR(counts = { IRNode.ALLOC, "1" }) - // Merge won't be reduced because, among other things, one of the inputs is null. int testCmpMergeWithNull_Second_C2(boolean cond, int x, int y) { return testCmpMergeWithNull_Second(cond, x, y); } @DontCompile @@ -530,8 +532,7 @@ int testObjectIdentity(boolean cond, int x, int y) { } @Test - @IR(counts = { IRNode.ALLOC, "1" }) - // The allocation won't be removed because the merge doesn't have exact type + @IR(failOn = { IRNode.ALLOC }) int testObjectIdentity_C2(boolean cond, int x, int y) { return testObjectIdentity(cond, x, y); } @DontCompile @@ -562,9 +563,7 @@ int testSubclassesTrapping(boolean c1, boolean c2, int x, int y, int w, int z) { } @Test - @IR(counts = { IRNode.ALLOC, "2" }) - // The initial allocation assigned to 's' will always be dead. - // The other two allocations assigned to 's' won't be removed because they have different type. + @IR(failOn = { IRNode.ALLOC }) int testSubclassesTrapping_C2(boolean c1, boolean c2, int x, int y, int w, int z) { return testSubclassesTrapping(c1, c2, x, y, w, z); } @DontCompile @@ -590,7 +589,7 @@ int testCmpMergeWithNull(boolean cond, int x, int y) { } @Test - @IR(counts = { IRNode.ALLOC, "2" }) + @IR(failOn = { IRNode.ALLOC }) int testCmpMergeWithNull_C2(boolean cond, int x, int y) { return testCmpMergeWithNull(cond, x, y); } @DontCompile @@ -620,9 +619,7 @@ int testSubclasses(boolean c1, boolean c2, int x, int y, int w, int z) { } @Test - @IR(counts = { IRNode.ALLOC, "2" }) - // The unused allocation will be removed. - // The other two allocations assigned to 's' won't be removed because they have different type. + @IR(failOn = { IRNode.ALLOC }) int testSubclasses_C2(boolean c1, boolean c2, int x, int y, int w, int z) { return testSubclasses(c1, c2, x, y, w, z); } @DontCompile @@ -1231,7 +1228,7 @@ char testString_one(boolean cond1) { } @Test - @IR(counts = { IRNode.ALLOC, "0" }) + @IR(failOn = { IRNode.ALLOC }) char testString_one_C2(boolean cond1) { return testString_one(cond1); } @DontCompile @@ -1252,12 +1249,68 @@ char testString_two(boolean cond1) { } @Test - @IR(counts = { IRNode.ALLOC, "0" }) + @IR(failOn = { IRNode.ALLOC }) char testString_two_C2(boolean cond1) { return testString_two(cond1); } @DontCompile char testString_two_Interp(boolean cond1) { return testString_two(cond1); } + // ------------------------------------------------------------------------- + + @ForceInline + Class testLoadNarrowKlass(boolean cond1) { + Object p = new Circle(10); + + if (cond1) { + p = dummy(1, 2); + } + + return p.getClass(); + } + + @Test + @IR(counts = { IRNode.ALLOC, "1" }) + // The allocation won't be reduced because we don't support NarrowKlass + // loads under CastPPs. + Class testLoadNarrowKlass_C2(boolean cond1) { return testLoadNarrowKlass(cond1); } + + @DontCompile + Class testLoadNarrowKlass_Interp(boolean cond1) { return testLoadNarrowKlass(cond1); } + + // ------------------------------------------------------------------------- + + @ForceInline + int testReReduce(boolean cond, int x, int y) { + Nested A = new Nested(x, y); + Nested B = new Nested(y, x); + Nested C = new Nested(y, x); + Nested P = null; + + if (x == y) { + A.other = B; + P = A; + } else if (x > y) { + P = B; + } else { + C.other = B; + P = C; + } + + if (x == y) + dummy_defaults(); + + return P.x; + } + + @Test + @IR(counts = { IRNode.ALLOC, "1" }) + // The last allocation won't be reduced because it would cause the creation + // of a nested SafePointScalarMergeNode. + int testReReduce_C2(boolean cond1, int x, int y) { return testReReduce(cond1, x, y); } + + @DontCompile + int testReReduce_Interp(boolean cond1, int x, int y) { return testReReduce(cond1, x, y); } + // ------------------ Utility for Testing ------------------- // @DontCompile @@ -1289,6 +1342,16 @@ static ADefaults dummy_defaults() { return new ADefaults(); } + static class Nested { + int x, y; + Nested other; + Nested(int x, int y) { + this.x = x; + this.y = y; + this.other = null; + } + } + static class Point { int x, y; Point(int x, int y) { diff --git a/test/hotspot/jtreg/compiler/codecache/CheckSegmentedCodeCache.java b/test/hotspot/jtreg/compiler/codecache/CheckSegmentedCodeCache.java index f79d7da7695..0c4fb5a66ae 100644 --- a/test/hotspot/jtreg/compiler/codecache/CheckSegmentedCodeCache.java +++ b/test/hotspot/jtreg/compiler/codecache/CheckSegmentedCodeCache.java @@ -82,6 +82,36 @@ private static void failsWith(ProcessBuilder pb, String message) throws Exceptio out.shouldHaveExitValue(1); } + private static void verifyCodeHeapSize(ProcessBuilder pb, String heapName, long heapSize) throws Exception { + OutputAnalyzer out = new OutputAnalyzer(pb.start()); + out.shouldHaveExitValue(0); + + long actualHeapSize = Long.parseLong(out.firstMatch(heapName + "\\s+=\\s(\\d+)", 1)); + if (heapSize != actualHeapSize) { + throw new RuntimeException("Unexpected " + heapName + " size: " + actualHeapSize + " != " + heapSize); + } + + // Sanity checks: + // - segment sizes are aligned to at least 1KB + // - sum of segment sizes equals ReservedCodeCacheSize + + long nonNMethodCodeHeapSize = Long.parseLong(out.firstMatch("NonNMethodCodeHeapSize\\s+=\\s(\\d+)", 1)); + long nonProfiledCodeHeapSize = Long.parseLong(out.firstMatch("NonProfiledCodeHeapSize\\s+=\\s(\\d+)", 1)); + long profiledCodeHeapSize = Long.parseLong(out.firstMatch(" ProfiledCodeHeapSize\\s+=\\s(\\d+)", 1)); + long reservedCodeCacheSize = Long.parseLong(out.firstMatch("ReservedCodeCacheSize\\s+=\\s(\\d+)", 1)); + + if (reservedCodeCacheSize != nonNMethodCodeHeapSize + nonProfiledCodeHeapSize + profiledCodeHeapSize) { + throw new RuntimeException("Unexpected segments size sum: " + reservedCodeCacheSize + " != " + + nonNMethodCodeHeapSize + "+" + nonProfiledCodeHeapSize + "+" + profiledCodeHeapSize); + } + + if ((reservedCodeCacheSize % 1024 != 0) || (nonNMethodCodeHeapSize % 1024 != 0) || + (nonProfiledCodeHeapSize % 1024 != 0) || (profiledCodeHeapSize % 1024 != 0)) { + throw new RuntimeException("Unexpected segments size alignment: " + reservedCodeCacheSize + ", " + + nonNMethodCodeHeapSize + ", " + nonProfiledCodeHeapSize + ", " + profiledCodeHeapSize); + } + } + /** * Check the result of segmented code cache related VM options. */ @@ -160,9 +190,60 @@ public static void main(String[] args) throws Exception { // minimum size: CodeCacheMinimumUseSpace DEBUG_ONLY(* 3) long minSize = (Platform.isDebugBuild() ? 3 : 1) * minUseSpace; pb = ProcessTools.createLimitedTestJavaProcessBuilder("-XX:+SegmentedCodeCache", + "-XX:NonNMethodCodeHeapSize=" + minSize, "-XX:ReservedCodeCacheSize=" + minSize, "-XX:InitialCodeCacheSize=100K", "-version"); failsWith(pb, "Not enough space in non-nmethod code heap to run VM"); + + // Try different combination of Segment Sizes + + // Fails if there is not enough space for code cache. + // All segments are set to minimum allowed value, but VM still fails + pb = ProcessTools.createLimitedTestJavaProcessBuilder("-XX:+SegmentedCodeCache", + "-XX:ReservedCodeCacheSize=" + minSize, + "-XX:InitialCodeCacheSize=100K", + "-version"); + failsWith(pb, "Invalid code heap sizes"); + + + // Reserved code cache is set but not equal to the sum of other segments + // that are explicitly specified - fails + pb = ProcessTools.createLimitedTestJavaProcessBuilder("-XX:+SegmentedCodeCache", + "-XX:ReservedCodeCacheSize=100M", + "-XX:NonNMethodCodeHeapSize=10M", + "-XX:ProfiledCodeHeapSize=10M", + "-XX:NonProfiledCodeHeapSize=10M", + "-version"); + failsWith(pb, "Invalid code heap sizes"); + + // Reserved code cache is not set - it's automatically adjusted to the sum of other segments + // that are explicitly specified + pb = ProcessTools.createLimitedTestJavaProcessBuilder("-XX:+SegmentedCodeCache", + "-XX:NonNMethodCodeHeapSize=10M", + "-XX:ProfiledCodeHeapSize=10M", + "-XX:NonProfiledCodeHeapSize=10M", + "-XX:+PrintFlagsFinal", + "-version"); + verifyCodeHeapSize(pb, "ReservedCodeCacheSize", 31457280); + + // Reserved code cache is set, NonNmethod segment size is set, two other segments is automatically + // adjusted to half of the remaining space + pb = ProcessTools.createLimitedTestJavaProcessBuilder("-XX:+SegmentedCodeCache", + "-XX:ReservedCodeCacheSize=100M", + "-XX:NonNMethodCodeHeapSize=10M", + "-XX:+PrintFlagsFinal", + "-version"); + verifyCodeHeapSize(pb, " ProfiledCodeHeapSize", 47185920); + + // Reserved code cache is set but NonNmethodCodeHeapSize is not set. + // It's calculated based on the number of compiler threads + pb = ProcessTools.createLimitedTestJavaProcessBuilder("-XX:+SegmentedCodeCache", + "-XX:ReservedCodeCacheSize=100M", + "-XX:ProfiledCodeHeapSize=10M", + "-XX:NonProfiledCodeHeapSize=10M", + "-XX:+PrintFlagsFinal", + "-version"); + verifyCodeHeapSize(pb, "NonNMethodCodeHeapSize", 83886080); } } diff --git a/test/hotspot/jtreg/compiler/codegen/TestConvertImplicitNullCheck.java b/test/hotspot/jtreg/compiler/codegen/TestConvertImplicitNullCheck.java new file mode 100644 index 00000000000..0e0c3545844 --- /dev/null +++ b/test/hotspot/jtreg/compiler/codegen/TestConvertImplicitNullCheck.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. 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. + */ + +/* + * @test + * @bug 8318562 + * @run main/othervm/timeout=200 -XX:CompileCommand=compileonly,TestConvertImplicitNullCheck::test -XX:-TieredCompilation -Xbatch TestConvertImplicitNullCheck + * @summary Exercise float to double conversion with implicit null check + * + */ + + +public class TestConvertImplicitNullCheck { + + float f = 42; + + static double test(TestConvertImplicitNullCheck t) { + return t.f; // float to double conversion with implicit null check of 't' + } + + public static void main(String[] args) { + // Warmup to trigger C2 compilation + TestConvertImplicitNullCheck t = new TestConvertImplicitNullCheck(); + for (int i = 0; i < 50_000; ++i) { + test(t); + } + // implicit null check + try { + test(null); + throw new RuntimeException("Test failed as no NullPointerException is thrown"); + } catch (NullPointerException e) { + // Expected + } + } +} diff --git a/test/hotspot/jtreg/compiler/loopopts/superword/TestLargeCompilation.java b/test/hotspot/jtreg/compiler/loopopts/superword/TestLargeCompilation.java new file mode 100644 index 00000000000..afe19fa1cd8 --- /dev/null +++ b/test/hotspot/jtreg/compiler/loopopts/superword/TestLargeCompilation.java @@ -0,0 +1,130 @@ +/* + * 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 compiler.loopopts.superword; + +/* + * @test + * @bug 8327978 + * @summary Test compile time for large compilation, where SuperWord takes especially much time. + * @requires vm.compiler2.enabled + * @run main/othervm/timeout=30 -XX:LoopUnrollLimit=1000 -Xbatch + * -XX:CompileCommand=compileonly,compiler.loopopts.superword.TestLargeCompilation::test* + * compiler.loopopts.superword.TestLargeCompilation + */ + +import java.util.Random; + +public class TestLargeCompilation { + private static final Random random = new Random(); + static final int RANGE_CON = 1024 * 8; + + static int init = 593436; + static int limit = 599554; + static int offset1 = -592394; + static int offset2 = -592386; + static final int offset3 = -592394; + static final int stride = 4; + static final int scale = 1; + static final int hand_unrolling1 = 2; + static final int hand_unrolling2 = 8; + static final int hand_unrolling3 = 15; + + public static void main(String[] args) { + byte[] aB = generateB(); + byte[] bB = generateB(); + byte[] cB = generateB(); + + for (int i = 1; i < 100; i++) { + testUUBBBH(aB, bB, cB); + } + } + + static byte[] generateB() { + byte[] a = new byte[RANGE_CON]; + for (int i = 0; i < a.length; i++) { + a[i] = (byte)random.nextInt(); + } + return a; + } + + static Object[] testUUBBBH(byte[] a, byte[] b, byte[] c) { + int h1 = hand_unrolling1; + int h2 = hand_unrolling2; + int h3 = hand_unrolling3; + + for (int i = init; i < limit; i += stride) { + if (h1 >= 1) { a[offset1 + i * scale + 0]++; } + if (h1 >= 2) { a[offset1 + i * scale + 1]++; } + if (h1 >= 3) { a[offset1 + i * scale + 2]++; } + if (h1 >= 4) { a[offset1 + i * scale + 3]++; } + if (h1 >= 5) { a[offset1 + i * scale + 4]++; } + if (h1 >= 6) { a[offset1 + i * scale + 5]++; } + if (h1 >= 7) { a[offset1 + i * scale + 6]++; } + if (h1 >= 8) { a[offset1 + i * scale + 7]++; } + if (h1 >= 9) { a[offset1 + i * scale + 8]++; } + if (h1 >= 10) { a[offset1 + i * scale + 9]++; } + if (h1 >= 11) { a[offset1 + i * scale + 10]++; } + if (h1 >= 12) { a[offset1 + i * scale + 11]++; } + if (h1 >= 13) { a[offset1 + i * scale + 12]++; } + if (h1 >= 14) { a[offset1 + i * scale + 13]++; } + if (h1 >= 15) { a[offset1 + i * scale + 14]++; } + if (h1 >= 16) { a[offset1 + i * scale + 15]++; } + + if (h2 >= 1) { b[offset2 + i * scale + 0]++; } + if (h2 >= 2) { b[offset2 + i * scale + 1]++; } + if (h2 >= 3) { b[offset2 + i * scale + 2]++; } + if (h2 >= 4) { b[offset2 + i * scale + 3]++; } + if (h2 >= 5) { b[offset2 + i * scale + 4]++; } + if (h2 >= 6) { b[offset2 + i * scale + 5]++; } + if (h2 >= 7) { b[offset2 + i * scale + 6]++; } + if (h2 >= 8) { b[offset2 + i * scale + 7]++; } + if (h2 >= 9) { b[offset2 + i * scale + 8]++; } + if (h2 >= 10) { b[offset2 + i * scale + 9]++; } + if (h2 >= 11) { b[offset2 + i * scale + 10]++; } + if (h2 >= 12) { b[offset2 + i * scale + 11]++; } + if (h2 >= 13) { b[offset2 + i * scale + 12]++; } + if (h2 >= 14) { b[offset2 + i * scale + 13]++; } + if (h2 >= 15) { b[offset2 + i * scale + 14]++; } + if (h2 >= 16) { b[offset2 + i * scale + 15]++; } + + if (h3 >= 1) { c[offset3 + i * scale + 0]++; } + if (h3 >= 2) { c[offset3 + i * scale + 1]++; } + if (h3 >= 3) { c[offset3 + i * scale + 2]++; } + if (h3 >= 4) { c[offset3 + i * scale + 3]++; } + if (h3 >= 5) { c[offset3 + i * scale + 4]++; } + if (h3 >= 6) { c[offset3 + i * scale + 5]++; } + if (h3 >= 7) { c[offset3 + i * scale + 6]++; } + if (h3 >= 8) { c[offset3 + i * scale + 7]++; } + if (h3 >= 9) { c[offset3 + i * scale + 8]++; } + if (h3 >= 10) { c[offset3 + i * scale + 9]++; } + if (h3 >= 11) { c[offset3 + i * scale + 10]++; } + if (h3 >= 12) { c[offset3 + i * scale + 11]++; } + if (h3 >= 13) { c[offset3 + i * scale + 12]++; } + if (h3 >= 14) { c[offset3 + i * scale + 13]++; } + if (h3 >= 15) { c[offset3 + i * scale + 14]++; } + if (h3 >= 16) { c[offset3 + i * scale + 15]++; } + } + return new Object[]{ a, b, c }; + } +} diff --git a/test/hotspot/jtreg/compiler/predicates/TestCloningWithManyDiamondsInExpression.java b/test/hotspot/jtreg/compiler/predicates/TestCloningWithManyDiamondsInExpression.java index 06af33f9a8e..9efe3ea85b4 100644 --- a/test/hotspot/jtreg/compiler/predicates/TestCloningWithManyDiamondsInExpression.java +++ b/test/hotspot/jtreg/compiler/predicates/TestCloningWithManyDiamondsInExpression.java @@ -24,7 +24,7 @@ /* * @test - * @bug 8327110 + * @bug 8327110 8327111 * @requires vm.compiler2.enabled * @summary Test that DFS algorithm for cloning Template Assertion Predicate Expression does not endlessly process paths. * @run main/othervm/timeout=30 -Xcomp -XX:LoopMaxUnroll=0 @@ -35,9 +35,23 @@ * -XX:CompileCommand=compileonly,*TestCloningWithManyDiamondsInExpression::test* * -XX:CompileCommand=inline,*TestCloningWithManyDiamondsInExpression::create* * compiler.predicates.TestCloningWithManyDiamondsInExpression - * @run main compiler.predicates.TestCloningWithManyDiamondsInExpression + * @run main/timeout=30 compiler.predicates.TestCloningWithManyDiamondsInExpression */ + /* + * @test + * @bug 8327111 + * @summary Test that DFS algorithm for cloning Template Assertion Predicate Expression does not endlessly process paths. + * @run main/othervm/timeout=30 -Xcomp + * -XX:CompileCommand=compileonly,*TestCloningWithManyDiamondsInExpression::test* + * -XX:CompileCommand=inline,*TestCloningWithManyDiamondsInExpression::create* + * compiler.predicates.TestCloningWithManyDiamondsInExpression + * @run main/othervm/timeout=30 -Xbatch + * -XX:CompileCommand=compileonly,*TestCloningWithManyDiamondsInExpression::test* + * -XX:CompileCommand=inline,*TestCloningWithManyDiamondsInExpression::create* + * compiler.predicates.TestCloningWithManyDiamondsInExpression + */ + package compiler.predicates; public class TestCloningWithManyDiamondsInExpression { @@ -51,6 +65,8 @@ public static void main(String[] strArr) { for (int i = 0; i < 10_000; i++) { testSplitIf(i % 2); testLoopUnswitching(i % 2); + testLoopUnrolling(i % 2); + testLoopPeeling(i % 2); } } @@ -98,6 +114,22 @@ static void testSplitIf(int x) { } } + static void testLoopUnrolling(int x) { + int[] a = new int[createExpressionWithManyDiamonds(x) + 1000]; + for (int i = 0; i < limit; i++) { + a[i] = i; // Loop Predication hoists this check and creates a Template Assertion Predicate. + } + } + + static void testLoopPeeling(int x) { + int[] a = new int[createExpressionWithManyDiamonds(x) + 1000]; + for (int i = 0; i < limit; i++) { + a[i] = i; // Loop Predication hoists this check and creates a Template Assertion Predicate. + if (x == 0) { // Reason to peel with LoopMaxUnroll=0 + return; + } + } + } // Creates in int expression with many diamonds. This method is forced-inlined. static int createExpressionWithManyDiamonds(int x) { diff --git a/test/hotspot/jtreg/compiler/testlibrary/sha/predicate/IntrinsicPredicates.java b/test/hotspot/jtreg/compiler/testlibrary/sha/predicate/IntrinsicPredicates.java index b6246f423e4..27fe9989247 100644 --- a/test/hotspot/jtreg/compiler/testlibrary/sha/predicate/IntrinsicPredicates.java +++ b/test/hotspot/jtreg/compiler/testlibrary/sha/predicate/IntrinsicPredicates.java @@ -79,7 +79,7 @@ public class IntrinsicPredicates { public static final BooleanSupplier SHA256_INSTRUCTION_AVAILABLE = new OrPredicate(new CPUSpecificPredicate("aarch64.*", new String[] { "sha256" }, null), - new OrPredicate(new CPUSpecificPredicate("riscv64.*", new String[] { "sha256" }, null), + new OrPredicate(new CPUSpecificPredicate("riscv64.*", new String[] { "zvkn" }, null), new OrPredicate(new CPUSpecificPredicate("s390.*", new String[] { "sha256" }, null), new OrPredicate(new CPUSpecificPredicate("ppc64.*", new String[] { "sha" }, null), new OrPredicate(new CPUSpecificPredicate("ppc64le.*", new String[] { "sha" }, null), @@ -92,7 +92,7 @@ public class IntrinsicPredicates { public static final BooleanSupplier SHA512_INSTRUCTION_AVAILABLE = new OrPredicate(new CPUSpecificPredicate("aarch64.*", new String[] { "sha512" }, null), - new OrPredicate(new CPUSpecificPredicate("riscv64.*", new String[] { "sha512" }, null), + new OrPredicate(new CPUSpecificPredicate("riscv64.*", new String[] { "zvkn" }, null), new OrPredicate(new CPUSpecificPredicate("s390.*", new String[] { "sha512" }, null), new OrPredicate(new CPUSpecificPredicate("ppc64.*", new String[] { "sha" }, null), new OrPredicate(new CPUSpecificPredicate("ppc64le.*", new String[] { "sha" }, null), diff --git a/test/hotspot/jtreg/gc/g1/TestVerificationInConcurrentCycle.java b/test/hotspot/jtreg/gc/g1/TestVerificationInConcurrentCycle.java index 4f81929cac9..044636c7c5f 100644 --- a/test/hotspot/jtreg/gc/g1/TestVerificationInConcurrentCycle.java +++ b/test/hotspot/jtreg/gc/g1/TestVerificationInConcurrentCycle.java @@ -36,7 +36,7 @@ * -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI * -XX:+VerifyBeforeGC -XX:+VerifyDuringGC -XX:+VerifyAfterGC * -XX:+UseG1GC -XX:+G1VerifyHeapRegionCodeRoots - * -XX:+VerifyRememberedSets -XX:+VerifyObjectStartArray + * -XX:+VerifyRememberedSets * -XX:+G1VerifyBitmaps * gc.g1.TestVerificationInConcurrentCycle */ @@ -55,7 +55,7 @@ * -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI * -XX:+VerifyBeforeGC -XX:+VerifyDuringGC -XX:+VerifyAfterGC * -XX:+UseG1GC -XX:+G1VerifyHeapRegionCodeRoots - * -XX:+VerifyRememberedSets -XX:+VerifyObjectStartArray + * -XX:+VerifyRememberedSets * gc.g1.TestVerificationInConcurrentCycle */ diff --git a/test/hotspot/jtreg/runtime/Metaspace/MaxMetaspaceSizeTest.java b/test/hotspot/jtreg/runtime/Metaspace/MaxMetaspaceSizeTest.java index 76c24eb1d25..b2ff8ed9bde 100644 --- a/test/hotspot/jtreg/runtime/Metaspace/MaxMetaspaceSizeTest.java +++ b/test/hotspot/jtreg/runtime/Metaspace/MaxMetaspaceSizeTest.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 @@ -36,14 +36,14 @@ public class MaxMetaspaceSizeTest { public static void main(String... args) throws Exception { ProcessBuilder pb = ProcessTools.createLimitedTestJavaProcessBuilder( + "-Xshare:off", "-Xmx1g", "-XX:MaxMetaspaceSize=4K", "-XX:+UseCompressedClassPointers", "-XX:CompressedClassSpaceSize=1g", "--version"); OutputAnalyzer output = new OutputAnalyzer(pb.start()); - // We do not explicitly limit MaxMetaspaceSize to a lower minimum. User can get as low as he wants. - // However, you most certainly will hit either one of + // -Xshare:off --version loads hundreds of classes and will hit either one of // "OutOfMemoryError: Metaspace" or // "OutOfMemoryError: Compressed class space" output.shouldMatch("OutOfMemoryError.*(Compressed class space|Metaspace)"); diff --git a/test/hotspot/jtreg/runtime/cds/TestCDSVMCrash.java b/test/hotspot/jtreg/runtime/cds/TestCDSVMCrash.java index e949207d03f..270d4cf96d4 100644 --- a/test/hotspot/jtreg/runtime/cds/TestCDSVMCrash.java +++ b/test/hotspot/jtreg/runtime/cds/TestCDSVMCrash.java @@ -25,6 +25,7 @@ * @test TestCDSVMCrash * @summary Verify that an exception is thrown when the VM crashes during executeAndLog * @requires vm.cds + * @requires vm.flagless * @modules java.base/jdk.internal.misc * @library /test/lib * @run driver TestCDSVMCrash @@ -37,19 +38,21 @@ public class TestCDSVMCrash { + static Object[] oa; + public static void main(String[] args) throws Exception { if (args.length == 1) { // This should guarantee to throw: // java.lang.OutOfMemoryError: Requested array size exceeds VM limit try { - Object[] oa = new Object[Integer.MAX_VALUE]; + oa = new Object[Integer.MAX_VALUE]; throw new Error("OOME not triggered"); } catch (OutOfMemoryError err) { throw new Error("OOME didn't abort JVM!"); } } // else this is the main test - ProcessBuilder pb = ProcessTools.createTestJavaProcessBuilder("-XX:+CrashOnOutOfMemoryError", + ProcessBuilder pb = ProcessTools.createLimitedTestJavaProcessBuilder("-XX:+CrashOnOutOfMemoryError", "-XX:-CreateCoredumpOnCrash", "-Xmx128m", "-Xshare:on", TestCDSVMCrash.class.getName(), "throwOOME"); diff --git a/test/hotspot/jtreg/runtime/cds/appcds/LotsOfClasses.java b/test/hotspot/jtreg/runtime/cds/appcds/LotsOfClasses.java index 1c2431d7c81..bf2a1215549 100644 --- a/test/hotspot/jtreg/runtime/cds/appcds/LotsOfClasses.java +++ b/test/hotspot/jtreg/runtime/cds/appcds/LotsOfClasses.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2021, 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 @@ -40,8 +40,9 @@ public class LotsOfClasses { public static void main(String[] args) throws Exception { ArrayList list = new ArrayList<>(); + long start = System.currentTimeMillis(); TestCommon.findAllClasses(list); - + System.out.println("findAllClasses = " + (System.currentTimeMillis() - start) + "ms"); CDSOptions opts = new CDSOptions(); opts.setClassList(list); opts.addSuffix("--add-modules"); diff --git a/test/hotspot/jtreg/runtime/cds/appcds/TestCommon.java b/test/hotspot/jtreg/runtime/cds/appcds/TestCommon.java index 007d9fb4c2c..4f2822a5970 100644 --- a/test/hotspot/jtreg/runtime/cds/appcds/TestCommon.java +++ b/test/hotspot/jtreg/runtime/cds/appcds/TestCommon.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2023, 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 @@ -678,27 +678,26 @@ public static boolean checkOutputStrings(String outputString1, return true; } - static Pattern pattern; - static void findAllClasses(ArrayList list) throws Exception { // Find all the classes in the jrt file system - pattern = Pattern.compile("/modules/[a-z.]*[a-z]+/([^-]*)[.]class"); + Pattern pattern = Pattern.compile("/modules/[a-z.]*[a-z]+/([^-]*)[.]class"); FileSystem fs = FileSystems.getFileSystem(URI.create("jrt:/")); Path base = fs.getPath("/modules/"); - findAllClassesAtPath(base, list); + findAllClassesAtPath(base, pattern, list); } - private static void findAllClassesAtPath(Path p, ArrayList list) throws Exception { + private static void findAllClassesAtPath(Path p, Pattern pattern, ArrayList list) throws Exception { try (DirectoryStream stream = Files.newDirectoryStream(p)) { for (Path entry: stream) { - Matcher matcher = pattern.matcher(entry.toString()); - if (matcher.find()) { - String className = matcher.group(1); - list.add(className); + if (Files.isDirectory(entry)) { + findAllClassesAtPath(entry, pattern, list); + } else { + Matcher matcher = pattern.matcher(entry.toString()); + if (matcher.find()) { + String className = matcher.group(1); + list.add(className); + } } - try { - findAllClassesAtPath(entry, list); - } catch (Exception ex) {} } } } diff --git a/test/jdk/ProblemList-Virtual.txt b/test/jdk/ProblemList-Virtual.txt index 6461c3b4a61..c352e8a95c1 100644 --- a/test/jdk/ProblemList-Virtual.txt +++ b/test/jdk/ProblemList-Virtual.txt @@ -76,5 +76,4 @@ java/util/PluggableLocale/PermissionTest.java 0000000 generic-all java/util/Properties/StoreReproducibilityTest.java 0000000 generic-all java/util/Properties/StoreReproducibilityTest.java 0000000 generic-all javax/management/ImplementationVersion/ImplVersionTest.java 0000000 generic-all -javax/management/remote/mandatory/subjectDelegation/SubjectDelegation1Test.java 0000000 generic-all javax/management/remote/mandatory/version/ImplVersionTest.java 0000000 generic-all diff --git a/test/jdk/ProblemList.txt b/test/jdk/ProblemList.txt index 1864cc456d7..4ffc4bde90c 100644 --- a/test/jdk/ProblemList.txt +++ b/test/jdk/ProblemList.txt @@ -134,7 +134,6 @@ java/awt/Focus/NoAutotransferToDisabledCompTest/NoAutotransferToDisabledCompTest java/awt/Focus/ToFrontFocusTest/ToFrontFocus.java 7156130 linux-all java/awt/Focus/WrongKeyTypedConsumedTest/WrongKeyTypedConsumedTest.java 8169096 macosx-all java/awt/EventQueue/6980209/bug6980209.java 8198615 macosx-all -java/awt/Frame/ExceptionOnSetExtendedStateTest/ExceptionOnSetExtendedStateTest.java 8198237 macosx-all java/awt/grab/EmbeddedFrameTest1/EmbeddedFrameTest1.java 7080150 macosx-all java/awt/event/InputEvent/EventWhenTest/EventWhenTest.java 8168646 generic-all java/awt/Mixing/AWT_Mixing/HierarchyBoundsListenerMixingTest.java 8049405 macosx-all @@ -534,8 +533,6 @@ javax/management/remote/mandatory/connection/RMIConnector_NPETest.java 8267887 g javax/management/remote/mandatory/connection/BrokenConnectionTest.java 8262312 linux-all -javax/management/remote/mandatory/subjectDelegation/SubjectDelegation1Test.java 8149084 linux-aarch64 - ############################################################################ # jdk_net @@ -663,7 +660,7 @@ javax/swing/JTree/DnD/LastNodeLowerHalfDrop.java 8159131 linux-all javax/swing/JTree/4633594/JTreeFocusTest.java 7105441 macosx-all javax/swing/AbstractButton/6711682/bug6711682.java 8060765 windows-all,macosx-all javax/swing/JFileChooser/6396844/TwentyThousandTest.java 8198003 generic-all -javax/swing/JFileChooser/8194044/FileSystemRootTest.java 8320944 windows-all +javax/swing/JFileChooser/8194044/FileSystemRootTest.java 8327236 windows-all javax/swing/JPopupMenu/6800513/bug6800513.java 7184956 macosx-all javax/swing/JTabbedPane/8007563/Test8007563.java 8051591 generic-all javax/swing/JTabbedPane/4624207/bug4624207.java 8064922 macosx-all @@ -800,3 +797,4 @@ java/awt/event/MouseEvent/SpuriousExitEnter/SpuriousExitEnter.java 8254841 macos java/awt/Focus/AppletInitialFocusTest/AppletInitialFocusTest1.java 8256289 windows-x64 java/awt/FullScreen/TranslucentWindow/TranslucentWindow.java 8258103 linux-all java/awt/Focus/FrameMinimizeTest/FrameMinimizeTest.java 8016266 linux-x64 +java/awt/Frame/SizeMinimizedTest.java 8305915 linux-x64 diff --git a/test/jdk/com/sun/jdi/EATests.java b/test/jdk/com/sun/jdi/EATests.java index b38879e22f4..cd80d01a07f 100644 --- a/test/jdk/com/sun/jdi/EATests.java +++ b/test/jdk/com/sun/jdi/EATests.java @@ -1285,7 +1285,7 @@ public int getExpectedIResult() { ///////////////////////////////////////////////////////////////////////////// // Test if an eliminated object can be reallocated *just* before a call returns an object. -// (See CompiledMethod::is_at_poll_return()) +// (See nmethod::is_at_poll_return()) // Details: the callee method has just one safepoint poll at the return. The other safepoint // is at the end of an iteration of the endless loop. We can detect if we suspended the target // there because the local xy is out of scope there. diff --git a/test/jdk/com/sun/net/httpserver/bugs/B6431193.java b/test/jdk/com/sun/net/httpserver/bugs/B6431193.java index 9be9759054b..8b85aa4618c 100644 --- a/test/jdk/com/sun/net/httpserver/bugs/B6431193.java +++ b/test/jdk/com/sun/net/httpserver/bugs/B6431193.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2006, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2006, 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,59 +40,47 @@ public class B6431193 { - static boolean error = false; + static boolean handlerIsDaemon = true; - public static void read (InputStream i) throws IOException { - while (i.read() != -1); - i.close(); - } - - /** - * @param args - */ - public static void main(String[] args) { + public static void main(String[] args) throws IOException { class MyHandler implements HttpHandler { public void handle(HttpExchange t) throws IOException { - InputStream is = t.getRequestBody(); - read(is); - // .. read the request body + try (InputStream is = t.getRequestBody(); + OutputStream os = t.getResponseBody()) { + is.readAllBytes(); + // .. read the request body String response = "This is the response"; - t.sendResponseHeaders(200, response.length()); - OutputStream os = t.getResponseBody(); - os.write(response.getBytes()); - os.close(); - error = Thread.currentThread().isDaemon(); + handlerIsDaemon = Thread.currentThread().isDaemon(); + t.sendResponseHeaders(200, response.length()); + os.write(response.getBytes()); + } } } + InetAddress loopback = InetAddress.getLoopbackAddress(); + HttpServer server = HttpServer.create(new InetSocketAddress(loopback, 0), 10); + server.createContext("/apps", new MyHandler()); + server.setExecutor(null); + server.start(); - HttpServer server; try { - InetAddress loopback = InetAddress.getLoopbackAddress(); - server = HttpServer.create(new InetSocketAddress(loopback, 0), 10); - - server.createContext("/apps", new MyHandler()); - server.setExecutor(null); - // creates a default executor - server.start(); int port = server.getAddress().getPort(); - String s = "http://localhost:"+port+"/apps/foo"; URL url = URIBuilder.newBuilder() - .scheme("http") - .loopback() - .port(port) - .path("/apps/foo") - .toURL(); - InputStream is = url.openConnection(Proxy.NO_PROXY).getInputStream(); - read (is); - server.stop(0); - if (error) { - throw new RuntimeException ("error in test"); + .scheme("http") + .loopback() + .port(port) + .path("/apps/foo") + .toURL(); + try (InputStream is = url.openConnection(Proxy.NO_PROXY).getInputStream()) { + is.readAllBytes(); } - - } - catch (Exception e) { + if (handlerIsDaemon) { + throw new RuntimeException("request was handled by a daemon thread"); + } + } catch (Exception e) { throw new AssertionError("Unexpected exception: " + e, e); + } finally { + server.stop(0); } } } diff --git a/test/jdk/java/awt/Frame/FrameMaximizedTest.java b/test/jdk/java/awt/Frame/FrameMaximizedTest.java new file mode 100644 index 00000000000..368132937fb --- /dev/null +++ b/test/jdk/java/awt/Frame/FrameMaximizedTest.java @@ -0,0 +1,62 @@ +/* + * 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 + * 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.Frame; +import java.awt.Label; + +/* + * @test + * @bug 4106068 + * @summary Test to verify maximized window is not too big + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual FrameMaximizedTest + */ + +public class FrameMaximizedTest { + public static void main (String[] args) throws Exception { + String INSTRUCTIONS = """ + Maximize the frame window. Check that the right and bottom edges of the + window are not off the edge of the screen. If they are not, the test + is successful and the bug is fixed. + """; + + PassFailJFrame.builder() + .title("Test Instructions") + .instructions(INSTRUCTIONS) + .rows(4) + .columns(40) + .testUI(new TestFrame()) + .build() + .awaitAndCheck(); + } +} + +class TestFrame extends Frame { + public TestFrame() { + setTitle("FrameMaximizedTest"); + setSize(500, 300); + add("North", new Label("Maximize me and check if my " + + "bottom and right edge are on screen.")); + } +} diff --git a/test/jdk/java/awt/Frame/FrameMinimizeTest.java b/test/jdk/java/awt/Frame/FrameMinimizeTest.java new file mode 100644 index 00000000000..cd3459a7841 --- /dev/null +++ b/test/jdk/java/awt/Frame/FrameMinimizeTest.java @@ -0,0 +1,59 @@ +/* + * 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 + * 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.Frame; + +/* + * @test + * @bug 4172782 + * @summary Test if non-resizable frame is minimizable + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual FrameMinimizeTest + */ + +public class FrameMinimizeTest { + public static void main(String[] args) throws Exception { + String INSTRUCTIONS = """ + When the blank FrameMinimizeTest frame is shown, verify that + 1. It is not resizable; + 2. It is minimizable. + """; + + PassFailJFrame.builder() + .title("Test Instructions") + .instructions(INSTRUCTIONS) + .rows(4) + .columns(35) + .testUI(FrameMinimizeTest::initialize) + .build() + .awaitAndCheck(); + } + + public static Frame initialize() { + Frame f = new Frame("FrameMinimizeTest"); + f.setSize(200, 200); + f.setResizable(false); + return f; + } +} diff --git a/test/jdk/java/awt/Frame/MegaIconTest/MegaIconTest.java b/test/jdk/java/awt/Frame/MegaIconTest/MegaIconTest.java new file mode 100644 index 00000000000..3132d49df56 --- /dev/null +++ b/test/jdk/java/awt/Frame/MegaIconTest/MegaIconTest.java @@ -0,0 +1,273 @@ +/* + * 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 + * 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.BorderLayout; +import java.awt.Button; +import java.awt.Canvas; +import java.awt.Color; +import java.awt.Dialog; +import java.awt.Dimension; +import java.awt.Frame; +import java.awt.Graphics; +import java.awt.GridLayout; +import java.awt.Image; +import java.awt.Label; +import java.awt.MediaTracker; +import java.awt.Panel; +import java.awt.Toolkit; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.event.WindowAdapter; +import java.awt.event.WindowEvent; +import java.awt.image.ImageProducer; +import java.net.URL; + +/* + * @test + * @bug 4175560 + * @summary Test use of user-defined icons + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual MegaIconTest + */ + +public class MegaIconTest { + public static void main(String[] args) throws Exception { + String INSTRUCTIONS = """ + Each of the buttons in the main window represents a test + of certain icon functionality - background transparency/opacity + of the icon, scaling etc. + Clicking on each button brings up a window displaying the graphic + that should appear in the corresponding icon. + Click on each button, minimize the resulting window, and check that + the icon is displayed as the test name indicates. + On Win32, icons should also be displayed correctly in the title bar. + If all the test pass, then this test passes, else fail. + """; + + PassFailJFrame.builder() + .title("Test Instructions") + .instructions(INSTRUCTIONS) + .rows(10) + .columns(35) + .testUI(MegaIconTest::initialize) + .build() + .awaitAndCheck(); + } + + public static Frame initialize() { + //Create the iconTestFrames and add to IconTestButtons + IconTestButtons itb = new IconTestButtons(new IconTestFrame[]{ + new IconTestFrame("Opaque, Scaled Icon Test", + "duke_404.gif"), + + new IconTestFrame("Transparent Icon", + "dukeWave.gif"), + + new IconTestFrameBG("Transparent, Scaled Icon with bg", + "fight.gif", Color.red), + + new IconTestFrameDlg("Transparent icon w/ Dialog", + "dukeWave.gif") + }); + itb.pack(); + return itb; + } +} + +class IconTestButtons extends Frame { + public IconTestButtons(IconTestFrame[] iconTests) { + IconTestFrame tempTest; + Button newBtn; + Panel newPnl; + DoneLabel newLbl; + + setTitle("MegaIconTest"); + + setLayout(new GridLayout(iconTests.length, 1)); + + //For each icon test frame + //Get name, add button with name and action to + //display the window, and add label "done" after + + for (int i = 0; i < iconTests.length; i++) { + tempTest = iconTests[i]; + newBtn = new Button(tempTest.getTestName()); + newLbl = new DoneLabel(); + newBtn.addActionListener(new IconTestActionListener(tempTest, + newLbl)); + newPnl = new Panel(); + newPnl.add(newBtn); + newPnl.add(newLbl); + add(newPnl); + } + } + + protected class DoneLabel extends Label { + public DoneLabel() { + super("Done"); + setVisible(false); + } + } + + protected class IconTestActionListener implements ActionListener { + IconTestFrame f; + DoneLabel l; + + public IconTestActionListener(IconTestFrame frame, DoneLabel label) { + this.f = frame; + this.l = label; + } + + public void actionPerformed(ActionEvent e) { + f.pack(); + f.setVisible(true); + l.setVisible(true); + IconTestButtons.this.pack(); + } + } +} + +class IconTestFrame extends Frame { + private String testName; + int width, height; + Image iconImage; + MediaTracker tracker; + + public IconTestFrame(String testName, String iconFileName) { + super(testName); + this.testName = testName; + tracker = new MediaTracker(this); + + //Set icon image + URL url = MegaIconTest.class.getResource(iconFileName); + Toolkit tk = Toolkit.getDefaultToolkit(); + if (tk == null) { + System.out.println("Toolkit is null!"); + } + if (url == null) { + System.out.println("Can't load icon is null!"); + return; + } + try { + iconImage = tk.createImage((ImageProducer) url.getContent()); + } catch (java.io.IOException e) { + System.out.println("Unable to load icon image from url: " + url); + } + tracker.addImage(iconImage, 0); + try { + tracker.waitForAll(); + } catch (java.lang.InterruptedException e) { + System.err.println(e); + } + width = iconImage.getWidth(this); + height = iconImage.getHeight(this); + setIconImage(iconImage); + + addWindowListener(new WindowAdapter() { + public void windowClosing(WindowEvent e) { + setVisible(false); + } + }); + + setLayout(new BorderLayout()); + setBackground(Color.YELLOW); + + //Add the icon graphic and instructions to the Frame + add(new IconCanvas(), "Center"); + pack(); + } + + class IconCanvas extends Canvas { + public void paint(Graphics g) { + if (IconTestFrame.this.iconImage == null) { + throw new NullPointerException(); + } + g.drawImage(IconTestFrame.this.iconImage, 0, 0, this); + } + + public Dimension getPreferredSize() { + return new Dimension(IconTestFrame.this.width, + IconTestFrame.this.height); + } + + public Dimension getMinimumSize() { + return getPreferredSize(); + } + + public Dimension getMaximumSize() { + return getPreferredSize(); + } + } + + public String getTestName() { + return testName; + } +} + +class IconTestFrameBG extends IconTestFrame { + public IconTestFrameBG(String testName, String iconFileName, Color bg) { + super(testName, iconFileName); + setBackground(bg); + Panel p = new Panel(); + p.setLayout(new GridLayout(3, 1)); + p.add(new Label("The background of this window has been set.")); + p.add(new Label("Unless the default icon background is the same color,")); + p.add(new Label("the icon background should NOT be this color.")); + add(p, "North"); + pack(); + } +} + +class IconTestFrameDlg extends IconTestFrame implements ActionListener { + Dialog dlg; + Button dlgBtn; + + public IconTestFrameDlg(String testName, String iconFilename) { + super(testName, iconFilename); + Panel p = new Panel(); + p.setLayout(new GridLayout(4, 1)); + p.add(new Label("Click on the button below to display a child dialog.")); + p.add(new Label("On Win32, the Dialog's titlebar icon should match")); + p.add(new Label("the titlebar icon of this window.")); + p.add(new Label("Minimizing this Frame should yield only one icon.")); + add(p, "North"); + + dlg = new Dialog(this); + dlg.setSize(200, 200); + dlg.add(new Label("Dialog stuff.")); + dlg.addWindowListener(new WindowAdapter() { + public void windowClosing(WindowEvent e) { + setVisible(false); + } + }); + + dlgBtn = new Button("Display Dialog"); + dlgBtn.addActionListener(this); + add(dlgBtn, "South"); + } + + public void actionPerformed(ActionEvent e) { + dlg.setVisible(true); + } +} diff --git a/test/jdk/java/awt/Frame/MegaIconTest/dukeWave.gif b/test/jdk/java/awt/Frame/MegaIconTest/dukeWave.gif new file mode 100644 index 00000000000..52ada7979ef Binary files /dev/null and b/test/jdk/java/awt/Frame/MegaIconTest/dukeWave.gif differ diff --git a/test/jdk/java/awt/Frame/MegaIconTest/duke_404.gif b/test/jdk/java/awt/Frame/MegaIconTest/duke_404.gif new file mode 100644 index 00000000000..4958e0d0dfa Binary files /dev/null and b/test/jdk/java/awt/Frame/MegaIconTest/duke_404.gif differ diff --git a/test/jdk/java/awt/Frame/MegaIconTest/fight.gif b/test/jdk/java/awt/Frame/MegaIconTest/fight.gif new file mode 100644 index 00000000000..6be1b4972d0 Binary files /dev/null and b/test/jdk/java/awt/Frame/MegaIconTest/fight.gif differ diff --git a/test/jdk/java/awt/Frame/SizeMinimizedTest.java b/test/jdk/java/awt/Frame/SizeMinimizedTest.java new file mode 100644 index 00000000000..2520cf42892 --- /dev/null +++ b/test/jdk/java/awt/Frame/SizeMinimizedTest.java @@ -0,0 +1,140 @@ +/* + * 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 + * 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.Dimension; +import java.awt.EventQueue; +import java.awt.Frame; +import java.awt.Point; +import java.awt.Robot; +import java.awt.event.WindowAdapter; +import java.awt.event.WindowEvent; + +/* + * @test + * @key headful + * @bug 4065534 + * @summary Frame.setSize() doesn't change size if window is in an iconified state + * @run main SizeMinimizedTest + */ + +public class SizeMinimizedTest { + private static Frame frame; + private static final int INITIAL_SIZE = 100; + private static final int INITIAL_X = 150; + private static final int INITIAL_Y = 50; + private static final int RESET_SIZE = 200; + private static final int OFFSET = 10; + private static int iterationCnt = 0; + private static Dimension expectedSize; + private static Dimension frameSize; + private static Point expectedLoc; + private static Point frameLoc; + + public static void main(String[] args) throws Exception { + Robot robot = new Robot(); + try { + EventQueue.invokeAndWait(() -> { + createUI(); + }); + robot.waitForIdle(); + robot.delay(1000); + + EventQueue.invokeAndWait(() -> { + frame.setState(Frame.ICONIFIED); + }); + robot.waitForIdle(); + robot.delay(100); + + EventQueue.invokeAndWait(() -> { + frame.setSize(RESET_SIZE, RESET_SIZE); + }); + robot.waitForIdle(); + robot.delay(100); + + for (int i = 0; i < 5; i++) { + EventQueue.invokeAndWait(() -> { + Point pt = frame.getLocation(); + frame.setLocation(pt.x + OFFSET, pt.y); + }); + iterationCnt++; + robot.waitForIdle(); + robot.delay(100); + } + EventQueue.invokeAndWait(() -> { + frame.setState(Frame.NORMAL); + }); + robot.waitForIdle(); + robot.delay(100); + + System.out.println("Test Passed!"); + } finally { + EventQueue.invokeAndWait(() -> { + if (frame != null) { + frame.dispose(); + } + }); + } + } + + public static void createUI() { + frame = new Frame("Frame size test"); + frame.setSize(INITIAL_SIZE, INITIAL_SIZE); + frame.setLocation(INITIAL_X, INITIAL_Y); + + frame.addWindowListener(new WindowAdapter() { + @Override + public void windowOpened(WindowEvent e) { + System.out.println("Initial Frame Size: " + frame.getSize()); + System.out.println("Initial Frame Location: " + + frame.getLocationOnScreen()); + } + }); + + frame.addWindowStateListener(new WindowAdapter() { + @Override + public void windowStateChanged(WindowEvent e) { + if (e.getNewState() == Frame.NORMAL) { + System.out.println("Frame Size: " + frame.getSize()); + System.out.println("Frame Location: " + + frame.getLocationOnScreen()); + expectedSize = new Dimension(RESET_SIZE, RESET_SIZE); + frameSize = frame.getSize(); + + if (!expectedSize.equals(frameSize)) { + throw new RuntimeException("Test Failed due to size mismatch."); + } + + expectedLoc = new Point(INITIAL_X + OFFSET * iterationCnt, + INITIAL_Y); + frameLoc = frame.getLocationOnScreen(); + + if (!expectedLoc.equals(frameLoc)) { + throw new RuntimeException("Test Failed due to " + + "location mismatch."); + } + } + } + }); + frame.setVisible(true); + } +} diff --git a/test/jdk/java/lang/String/CompactString/MaxSizeUTF16String.java b/test/jdk/java/lang/String/CompactString/MaxSizeUTF16String.java index 530171e0b64..3511a870f39 100644 --- a/test/jdk/java/lang/String/CompactString/MaxSizeUTF16String.java +++ b/test/jdk/java/lang/String/CompactString/MaxSizeUTF16String.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -118,4 +118,33 @@ public void testMaxCharArray() { } } } + + /* + * Test that UTF-8 of too large strings throws OOME, (not NegativeArraySizeException). + */ + @Test + public void testMaxUTF8_UTF16Encode() { + String s = "\uFFFF"; + final byte[] bytes1 = s.getBytes(StandardCharsets.UTF_8); + assertEquals(3, bytes1.length, "UTF_8 encoded length of 0xffff"); + + int min = Integer.MAX_VALUE / bytes1.length - 1; + int max = min + 3; + + // String of size min can be UTF_8 encoded. + System.out.println("testing size: " + min); + String s1 = s.repeat(min); + byte[] bytes = s1.getBytes(StandardCharsets.UTF_8); + int remaining = Integer.MAX_VALUE - bytes.length; + assertTrue(remaining >= bytes1.length, "remainder too large: " + remaining); + + // Strings of size min+1...min+2, throw OOME + // The resulting byte array would exceed implementation limits + for (int count = min + 1; count < max; count++) { + System.out.println("testing size: " + count); + final String s2 = s.repeat(count); + OutOfMemoryError ex = assertThrows(OutOfMemoryError.class, () -> s2.getBytes(StandardCharsets.UTF_8)); + ex.printStackTrace(); + }; + } } diff --git a/test/jdk/java/net/httpclient/HttpRequestBuilderTest.java b/test/jdk/java/net/httpclient/HttpRequestBuilderTest.java index a0c74048503..1bb26def17d 100644 --- a/test/jdk/java/net/httpclient/HttpRequestBuilderTest.java +++ b/test/jdk/java/net/httpclient/HttpRequestBuilderTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2018, 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 @@ -259,6 +259,16 @@ public static void main(String[] args) throws Exception { () -> HttpRequest.newBuilder(TEST_URI).HEAD(), "HEAD"); + // verify that the default HEAD() method implementation in HttpRequest.Builder + // interface works as expected + HttpRequest defaultHeadReq = new NotOverriddenHEADImpl().HEAD().uri(TEST_URI).build(); + String actualMethod = defaultHeadReq.method(); + if (!actualMethod.equals("HEAD")) { + throw new AssertionError("failed: expected HEAD method but got method: " + actualMethod); + } + if (defaultHeadReq.bodyPublisher().isEmpty()) { + throw new AssertionError("failed: missing bodyPublisher on HEAD request"); + } } private static boolean shouldFail(Class ...exceptions) { @@ -367,4 +377,79 @@ public static R test2(String name, R receiver, BiFunction } } } + + // doesn't override the default HEAD() method + private static final class NotOverriddenHEADImpl implements HttpRequest.Builder { + private final HttpRequest.Builder underlying = HttpRequest.newBuilder(); + + @Override + public HttpRequest.Builder uri(URI uri) { + return this.underlying.uri(uri); + } + + @Override + public HttpRequest.Builder expectContinue(boolean enable) { + return this.underlying.expectContinue(enable); + } + + @Override + public HttpRequest.Builder version(HttpClient.Version version) { + return this.underlying.version(version); + } + + @Override + public HttpRequest.Builder header(String name, String value) { + return this.underlying.header(name, value); + } + + @Override + public HttpRequest.Builder headers(String... headers) { + return this.underlying.headers(headers); + } + + @Override + public HttpRequest.Builder timeout(Duration duration) { + return this.underlying.timeout(duration); + } + + @Override + public HttpRequest.Builder setHeader(String name, String value) { + return this.underlying.setHeader(name, value); + } + + @Override + public HttpRequest.Builder GET() { + return this.underlying.GET(); + } + + @Override + public HttpRequest.Builder POST(HttpRequest.BodyPublisher bodyPublisher) { + return this.underlying.POST(bodyPublisher); + } + + @Override + public HttpRequest.Builder PUT(HttpRequest.BodyPublisher bodyPublisher) { + return this.underlying.PUT(bodyPublisher); + } + + @Override + public HttpRequest.Builder DELETE() { + return this.underlying.DELETE(); + } + + @Override + public HttpRequest.Builder method(String method, HttpRequest.BodyPublisher bodyPublisher) { + return this.underlying.method(method, bodyPublisher); + } + + @Override + public HttpRequest build() { + return this.underlying.build(); + } + + @Override + public HttpRequest.Builder copy() { + return this.underlying.copy(); + } + } } diff --git a/test/jdk/java/security/cert/CertPathValidator/crlDP/CheckAllCRLs.java b/test/jdk/java/security/cert/CertPathValidator/crlDP/CheckAllCRLs.java new file mode 100644 index 00000000000..71627dbc64f --- /dev/null +++ b/test/jdk/java/security/cert/CertPathValidator/crlDP/CheckAllCRLs.java @@ -0,0 +1,231 @@ +/* + * 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.nio.file.Files; +import java.nio.file.Path; +import java.math.BigInteger; +import java.security.KeyPair; +import java.security.KeyPairGenerator; +import java.security.PublicKey; +import java.security.cert.CertificateFactory; +import java.security.cert.CertPath; +import java.security.cert.CertPathValidator; +import java.security.cert.CertPathValidatorException; +import java.security.cert.CertPathValidatorException.BasicReason; +import java.security.cert.PKIXParameters; +import java.security.cert.TrustAnchor; +import java.security.cert.X509Certificate; +import java.security.cert.X509CRL; +import java.util.Date; +import java.util.List; +import java.util.Set; +import java.util.concurrent.TimeUnit; +import sun.security.x509.AuthorityKeyIdentifierExtension; +import sun.security.x509.CRLDistributionPointsExtension; +import sun.security.x509.CRLExtensions; +import sun.security.x509.CRLNumberExtension; +import sun.security.x509.DistributionPoint; +import sun.security.x509.Extension; +import sun.security.x509.GeneralName; +import sun.security.x509.GeneralNames; +import sun.security.x509.KeyIdentifier; +import sun.security.x509.URIName; +import sun.security.x509.X500Name; +import sun.security.x509.X509CRLEntryImpl; +import sun.security.x509.X509CRLImpl; +import static sun.security.x509.X509CRLImpl.TBSCertList; +import sun.security.testlibrary.CertificateBuilder; + +/* + * @test + * @bug 8200566 + * @summary Check that CRL validation continues to check other CRLs in + * CRLDP extension after CRL fetching errors and exhibits same + * behavior (fails because cert is revoked) whether CRL cache is + * fresh or stale. + * @modules java.base/sun.security.x509 + * java.base/sun.security.util + * @library ../../../../../java/security/testlibrary + * @build CertificateBuilder CheckAllCRLs + * @run main/othervm -Dcom.sun.security.enableCRLDP=true CheckAllCRLs + */ +public class CheckAllCRLs { + + public static void main(String[] args) throws Exception { + + CertificateBuilder cb = new CertificateBuilder(); + + // Create CA cert + KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA"); + KeyPair rootKeyPair = kpg.genKeyPair(); + X509Certificate rootCert = createCert(cb, "CN=Root CA", + rootKeyPair, rootKeyPair, null, "SHA384withRSA", true, false); + + // Create EE cert. This EE cert will contain a CRL Distribution + // Points extension with two DistributionPoints - one will be a HTTP + // URL to a non-existant HTTP server, and the other will be a File + // URL to a file containing the CRL. + KeyPair eeKeyPair = kpg.genKeyPair(); + X509Certificate eeCert1 = createCert(cb, "CN=End Entity", + rootKeyPair, eeKeyPair, rootCert, "SHA384withRSA", false, true); + + // Create another EE cert. This EE cert is similar in that it contains + // a CRL Distribution Points extension but with one DistributionPoint + // containing 2 GeneralName URLs as above. + X509Certificate eeCert2 = createCert(cb, "CN=End Entity", + rootKeyPair, eeKeyPair, rootCert, "SHA384withRSA", false, false); + + // Create a CRL with no revoked certificates and store it in a file + X509CRL crl = createCRL(new X500Name("CN=Root CA"), rootKeyPair, + "SHA384withRSA"); + Files.write(Path.of("root.crl"), crl.getEncoded()); + + // Validate path containing eeCert1 + System.out.println("Validating cert with CRLDP containing one " + + "DistributionPoint with 2 entries, the first non-existent"); + validatePath(eeCert1, rootCert); + + // Validate path containing eeCert2 + System.out.println("Validating cert with CRLDP containing two " + + "DistributionPoints with 1 entry each, the first non-existent"); + validatePath(eeCert2, rootCert); + } + + private static X509Certificate createCert(CertificateBuilder cb, + String subjectDN, KeyPair issuerKeyPair, KeyPair subjectKeyPair, + X509Certificate issuerCert, String sigAlg, boolean isCA, + boolean twoDPs) throws Exception { + cb.setSubjectName(subjectDN); + cb.setPublicKey(subjectKeyPair.getPublic()); + cb.setSerialNumber(new BigInteger("1")); + + if (isCA) { + // Make a 3 year validity starting from 60 days ago + long start = System.currentTimeMillis() - TimeUnit.DAYS.toMillis(60); + long end = start + TimeUnit.DAYS.toMillis(1085); + cb.setValidity(new Date(start), new Date(end)); + cb.addBasicConstraintsExt(true, true, -1); + cb.addKeyUsageExt(new boolean[] + {false, false, false, false, false, true, true, false, false}); + } else { + // Make a 1 year validity starting from 7 days ago + long start = System.currentTimeMillis() - TimeUnit.DAYS.toMillis(7); + long end = start + TimeUnit.DAYS.toMillis(365); + cb.setValidity(new Date(start), new Date(end)); + cb.addAuthorityKeyIdExt(issuerKeyPair.getPublic()); + cb.addKeyUsageExt(new boolean[] + {true, false, false, false, false, false, false, false, false}); + cb.addExtendedKeyUsageExt(List.of("1.3.6.1.5.5.7.3.1")); + GeneralName first = new GeneralName(new URIName( + "http://127.0.0.1:48180/crl/will/always/fail/root.crl")); + GeneralName second = new GeneralName(new URIName("file:./root.crl")); + if (twoDPs) { + GeneralNames gn1 = new GeneralNames().add(first); + DistributionPoint dp1 = new DistributionPoint(gn1, null, null); + GeneralNames gn2 = new GeneralNames().add(second); + DistributionPoint dp2 = new DistributionPoint(gn2, null, null); + cb.addExtension(new CRLDistributionPointsExtension(List.of(dp1, dp2))); + } else { + GeneralNames gn = new GeneralNames().add(first).add(second); + DistributionPoint dp = new DistributionPoint(gn, null, null); + cb.addExtension(new CRLDistributionPointsExtension(List.of(dp))); + } + } + cb.addSubjectKeyIdExt(subjectKeyPair.getPublic()); + + // return signed cert + return cb.build(issuerCert, issuerKeyPair.getPrivate(), sigAlg); + } + + private static X509CRL createCRL(X500Name caIssuer, KeyPair caKeyPair, + String sigAlg) throws Exception { + + CRLExtensions crlExts = new CRLExtensions(); + + // add AuthorityKeyIdentifier extension + KeyIdentifier kid = new KeyIdentifier(caKeyPair.getPublic()); + Extension ext = new AuthorityKeyIdentifierExtension(kid, null, null); + crlExts.setExtension(ext.getId(), + new AuthorityKeyIdentifierExtension(kid, null, null)); + + // add CRLNumber extension + ext = new CRLNumberExtension(1); + crlExts.setExtension(ext.getId(), ext); + + // revoke cert + X509CRLEntryImpl crlEntry = + new X509CRLEntryImpl(new BigInteger("1"), new Date()); + + // Create a 1 year validity CRL starting from 7 days ago + long start = System.currentTimeMillis() - TimeUnit.DAYS.toMillis(7); + long end = start + TimeUnit.DAYS.toMillis(365); + TBSCertList tcl = new TBSCertList(caIssuer, new Date(start), + new Date(end), new X509CRLEntryImpl[]{ crlEntry }, crlExts); + + // return signed CRL + return X509CRLImpl.newSigned(tcl, caKeyPair.getPrivate(), sigAlg); + } + + private static void validatePath(X509Certificate eeCert, + X509Certificate rootCert) throws Exception { + + // Create certification path and set up PKIXParameters. + CertificateFactory cf = CertificateFactory.getInstance("X.509"); + CertPath cp = cf.generateCertPath(List.of(eeCert)); + PKIXParameters pp = + new PKIXParameters(Set.of(new TrustAnchor(rootCert, null))); + pp.setRevocationEnabled(true); + + CertPathValidator cpv = CertPathValidator.getInstance("PKIX"); + + // Validate path twice in succession, making sure we get consistent + // results the second time when the CRL cache is fresh. + System.out.println("First time validating path"); + validate(cpv, cp, pp); + System.out.println("Second time validating path"); + validate(cpv, cp, pp); + + // CRL lookup cache time is 30s. Sleep for 35 seconds to ensure + // cache is stale, and validate one more time to ensure we get + // consistent results. + System.out.println("Waiting for CRL cache to be cleared"); + Thread.sleep(30500); + + System.out.println("Third time validating path"); + validate(cpv, cp, pp); + } + + private static void validate(CertPathValidator cpv, CertPath cp, + PKIXParameters pp) throws Exception { + + try { + cpv.validate(cp, pp); + throw new Exception("Validation passed unexpectedly"); + } catch (CertPathValidatorException cpve) { + if (cpve.getReason() != BasicReason.REVOKED) { + throw new Exception("Validation failed with unexpected reason", cpve); + } + System.out.println("Validation failed as expected: " + cpve); + } + } +} diff --git a/test/jdk/java/util/Collection/MOAT.java b/test/jdk/java/util/Collection/MOAT.java index bbc332cc211..0e5eadc9799 100644 --- a/test/jdk/java/util/Collection/MOAT.java +++ b/test/jdk/java/util/Collection/MOAT.java @@ -246,6 +246,7 @@ public static void realMain(String[] args) { testCollection(list); testImmutableList(list); testListMutatorsAlwaysThrow(list); + testImmutableListMutatorsAlwaysThrow(list); if (list.size() >= 1) { // test subLists List headList = list.subList(0, list.size() - 1); @@ -564,6 +565,12 @@ private static void testListMutatorsAlwaysThrow(List c) { () -> c.addAll(0, Collections.emptyList())); } + private static void testImmutableListMutatorsAlwaysThrow(List c) { + THROWS(UnsupportedOperationException.class, + c::removeFirst, + c::removeLast); + } + /** * As above, for an empty list. * diff --git a/test/jdk/java/util/Properties/StoreReproducibilityTest.java b/test/jdk/java/util/Properties/StoreReproducibilityTest.java index b77f3262a4a..7072b24dc0c 100644 --- a/test/jdk/java/util/Properties/StoreReproducibilityTest.java +++ b/test/jdk/java/util/Properties/StoreReproducibilityTest.java @@ -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 @@ -45,6 +45,9 @@ * @test * @summary Tests that the Properties.store() APIs generate output that is reproducible * @bug 8231640 8282023 8316540 + * @comment The test launches several processes and in the presence of -Xcomp it's too slow + * and thus causes timeouts + * @requires vm.compMode != "Xcomp" * @library /test/lib * @run driver StoreReproducibilityTest */ diff --git a/test/jdk/java/util/concurrent/tck/ForkJoinPool9Test.java b/test/jdk/java/util/concurrent/tck/ForkJoinPool9Test.java index 266c2a036fe..a87aa7b916b 100644 --- a/test/jdk/java/util/concurrent/tck/ForkJoinPool9Test.java +++ b/test/jdk/java/util/concurrent/tck/ForkJoinPool9Test.java @@ -79,6 +79,9 @@ public void testCommonPoolThreadContextClassLoader() throws Throwable { assertSame(ForkJoinPool.commonPool(), ForkJoinTask.getPool()); Thread currentThread = Thread.currentThread(); + ClassLoader preexistingContextClassLoader = + currentThread.getContextClassLoader(); + Stream.of(systemClassLoader, null).forEach(cl -> { if (randomBoolean()) // should always be permitted, without effect @@ -95,6 +98,11 @@ public void testCommonPoolThreadContextClassLoader() throws Throwable { () -> System.getProperty("foo"), () -> currentThread.setContextClassLoader( classLoaderDistinctFromSystemClassLoader)); + else { + currentThread.setContextClassLoader(classLoaderDistinctFromSystemClassLoader); + assertSame(currentThread.getContextClassLoader(), classLoaderDistinctFromSystemClassLoader); + currentThread.setContextClassLoader(preexistingContextClassLoader); + } // TODO ? // if (haveSecurityManager // && Thread.currentThread().getClass().getSimpleName() diff --git a/test/jdk/javax/management/remote/mandatory/RemovedSubjectDelegation.java b/test/jdk/javax/management/remote/mandatory/RemovedSubjectDelegation.java new file mode 100644 index 00000000000..8ba445a15b6 --- /dev/null +++ b/test/jdk/javax/management/remote/mandatory/RemovedSubjectDelegation.java @@ -0,0 +1,115 @@ +/* + * 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 8326666 + * @summary Test that Subject Delegation is removed. + * @modules java.management.rmi + * java.management/com.sun.jmx.remote.security + * @run main/othervm RemovedSubjectDelegation + */ + +import java.lang.management.ManagementFactory; +import java.rmi.RemoteException; +import java.rmi.registry.LocateRegistry; +import java.rmi.registry.Registry; +import java.util.Collections; +import java.util.HashMap; +import java.util.Properties; +import javax.management.MBeanServer; +import javax.management.MBeanServerConnection; +import javax.management.remote.JMXConnector; +import javax.management.remote.JMXConnectorFactory; +import javax.management.remote.JMXConnectorServer; +import javax.management.remote.JMXConnectorServerFactory; +import javax.management.remote.JMXPrincipal; +import javax.management.remote.JMXServiceURL; +import javax.security.auth.Subject; + +public class RemovedSubjectDelegation { + + public static void main(String[] args) throws Exception { + JMXConnectorServer jmxcs = null; + JMXConnector jmxc = null; + try { + // Create an RMI registry + // + System.out.println("Start RMI registry..."); + Registry reg = null; + int port = 5900; + while (port++ < 5920) { + try { + reg = LocateRegistry.createRegistry(port); + System.out.println("RMI registry running on port " + port); + break; + } catch (RemoteException e) { + // Failed to create RMI registry... + System.out.println("Failed to create RMI registry " + + "on port " + port); + } + } + if (reg == null) { + throw new RuntimeException("Failed to create RMI registry."); + } + // Instantiate the MBean server + // + System.out.println("Create the MBean server"); + MBeanServer mbs = ManagementFactory.getPlatformMBeanServer(); + // Create an RMI connector server + // + System.out.println("Create an RMI connector server"); + JMXServiceURL url = new JMXServiceURL("rmi", null, 0); + HashMap env = new HashMap(); + jmxcs = JMXConnectorServerFactory.newJMXConnectorServer(url, env, mbs); + jmxcs.start(); + // Create an RMI connector client + // + System.out.println("Create an RMI connector client"); + // Not setting env with "jmx.remote.credentials", should not get as far as verifying: + jmxc = JMXConnectorFactory.connect(jmxcs.getAddress()); + Subject delegationSubject = + new Subject(true, + Collections.singleton(new JMXPrincipal("delegate")), + Collections.EMPTY_SET, + Collections.EMPTY_SET); + + MBeanServerConnection mbsc = null; + try { + mbsc = jmxc.getMBeanServerConnection(delegationSubject); + throw new RuntimeException("FAIL: delegationSubject was accepted. mbsc=" + mbsc); + } catch (UnsupportedOperationException e) { + System.out.println("PASS: " + e); + } + } catch (Exception e) { + System.out.println("Unexpected exception caught = " + e); + e.printStackTrace(); + throw e; + } finally { + if (jmxc != null) + jmxc.close(); + if (jmxcs != null) + jmxcs.stop(); + } + } +} diff --git a/test/jdk/javax/management/remote/mandatory/connection/RMIConnectorInternalMapTest.java b/test/jdk/javax/management/remote/mandatory/connection/RMIConnectorInternalMapTest.java deleted file mode 100644 index b797563017d..00000000000 --- a/test/jdk/javax/management/remote/mandatory/connection/RMIConnectorInternalMapTest.java +++ /dev/null @@ -1,123 +0,0 @@ -/* - * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -import java.lang.management.ManagementFactory; -import java.lang.ref.WeakReference; -import java.lang.reflect.Field; -import java.util.Collections; -import java.util.Map; -import javax.management.MBeanServer; -import javax.management.MBeanServerConnection; -import javax.management.remote.JMXConnector; -import javax.management.remote.JMXConnectorFactory; -import javax.management.remote.JMXConnectorServer; -import javax.management.remote.JMXConnectorServerFactory; -import javax.management.remote.JMXPrincipal; -import javax.management.remote.JMXServiceURL; -import javax.management.remote.rmi.RMIConnector; -import javax.security.auth.Subject; - -/* - * @test - * @bug 6566891 - * @summary Check no memory leak on RMIConnector's rmbscMap - * @author Shanliang JIANG - * @modules java.management.rmi/javax.management.remote.rmi:open - * @run clean RMIConnectorInternalMapTest - * @run build RMIConnectorInternalMapTest - * @run main RMIConnectorInternalMapTest - */ - -public class RMIConnectorInternalMapTest { - public static void main(String[] args) throws Exception { - System.out.println("---RMIConnectorInternalMapTest starting..."); - - JMXConnectorServer connectorServer = null; - JMXConnector connectorClient = null; - - try { - MBeanServer mserver = ManagementFactory.getPlatformMBeanServer(); - JMXServiceURL serverURL = new JMXServiceURL("rmi", "localhost", 0); - connectorServer = JMXConnectorServerFactory.newJMXConnectorServer(serverURL, null, mserver); - connectorServer.start(); - - JMXServiceURL serverAddr = connectorServer.getAddress(); - connectorClient = JMXConnectorFactory.connect(serverAddr, null); - connectorClient.connect(); - - Field rmbscMapField = RMIConnector.class.getDeclaredField("rmbscMap"); - rmbscMapField.setAccessible(true); - Map> map = - (Map>) rmbscMapField.get(connectorClient); - if (map != null && !map.isEmpty()) { // failed - throw new RuntimeException("RMIConnector's rmbscMap must be empty at the initial time."); - } - - Subject delegationSubject = - new Subject(true, - Collections.singleton(new JMXPrincipal("delegate")), - Collections.EMPTY_SET, - Collections.EMPTY_SET); - MBeanServerConnection mbsc1 = - connectorClient.getMBeanServerConnection(delegationSubject); - MBeanServerConnection mbsc2 = - connectorClient.getMBeanServerConnection(delegationSubject); - - if (mbsc1 == null) { - throw new RuntimeException("Got null connection."); - } - if (mbsc1 != mbsc2) { - throw new RuntimeException("Not got same connection with a same subject."); - } - - map = (Map>) rmbscMapField.get(connectorClient); - if (map == null || map.isEmpty()) { // failed - throw new RuntimeException("RMIConnector's rmbscMap has wrong size " - + "after creating a delegated connection."); - } - - delegationSubject = null; - mbsc1 = null; - mbsc2 = null; - - int i = 0; - while (!map.isEmpty() && i++ < 60) { - System.gc(); - Thread.sleep(100); - } - System.out.println("---GC times: " + i); - - if (!map.isEmpty()) { - throw new RuntimeException("Failed to clean RMIConnector's rmbscMap"); - } else { - System.out.println("---RMIConnectorInternalMapTest: PASSED!"); - } - } finally { - try { - connectorClient.close(); - connectorServer.stop(); - } catch (Exception e) { - } - } - } -} diff --git a/test/jdk/javax/management/remote/mandatory/notif/DeadListenerTest.java b/test/jdk/javax/management/remote/mandatory/notif/DeadListenerTest.java index 11942eace3a..f35ee295c1e 100644 --- a/test/jdk/javax/management/remote/mandatory/notif/DeadListenerTest.java +++ b/test/jdk/javax/management/remote/mandatory/notif/DeadListenerTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010, 2016, 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 @@ -75,11 +75,11 @@ public static void main(String[] args) throws Exception { RMIConnectorServer cs = new RMIConnectorServer(url, null, rmiServer, mbs); cs.start(); JMXServiceURL addr = cs.getAddress(); - assertTrue("No connections in new connector server", rmiServer.connections.isEmpty()); + assertTrue("Expected no connections in new connector server", rmiServer.connections.isEmpty()); JMXConnector cc = JMXConnectorFactory.connect(addr); MBeanServerConnection mbsc = cc.getMBeanServerConnection(); - assertTrue("One connection on server after client connect", rmiServer.connections.size() == 1); + assertTrue("Expected one connection on server after client connect", rmiServer.connections.size() == 1); RMIConnectionImpl connection = rmiServer.connections.get(0); Method getServerNotifFwdM = RMIConnectionImpl.class.getDeclaredMethod("getServerNotifFwd"); getServerNotifFwdM.setAccessible(true); @@ -88,7 +88,7 @@ public static void main(String[] args) throws Exception { listenerMapF.setAccessible(true); @SuppressWarnings("unchecked") Map> listenerMap = (Map>) listenerMapF.get(serverNotifForwarder); - assertTrue("Server listenerMap initially empty", mapWithoutKey(listenerMap, delegateName).isEmpty()); + assertTrue("Expected server listenerMap initially empty", mapWithoutKey(listenerMap, delegateName).isEmpty()); final AtomicInteger count1Val = new AtomicInteger(); CountListener count1 = new CountListener(count1Val); @@ -104,12 +104,12 @@ public static void main(String[] args) throws Exception { WeakReference count2Ref = new WeakReference<>(count2); count2 = null; - assertTrue("One entry in listenerMap for two listeners on same MBean", mapWithoutKey(listenerMap, delegateName).size() == 1); + assertTrue("Expected one entry in listenerMap for two listeners on same MBean", mapWithoutKey(listenerMap, delegateName).size() == 1); Set set = listenerMap.get(name); - assertTrue("Set in listenerMap for MBean has two elements", set != null && set.size() == 2); + assertTrue("Expected Set in listenerMap for MBean to have two elements", set != null && set.size() == 2); - assertTrue("Initial value of count1 == 0", count1Val.get() == 0); - assertTrue("Initial value of count2 == 0", count2Val.get() == 0); + assertTrue("Initial value of count1 should be 0", count1Val.get() == 0); + assertTrue("Initial value of count2 should be 0", count2Val.get() == 0); Notification notif = new Notification("type", name, 0); @@ -119,8 +119,8 @@ public static void main(String[] args) throws Exception { while ((count1Val.get() != 1 || count2Val.get() != 1) ) { Thread.sleep(20); } - assertTrue("New value of count1 == 1", count1Val.get() == 1); - assertTrue("Initial value of count2 == 1", count2Val.get() == 1); + assertTrue("Value of count1 expected 1, got " + count1Val.get(), count1Val.get() == 1); + assertTrue("Value of count2 expected 1, got " + count2Val.get(), count2Val.get() == 1); // Make sure that removing a nonexistent listener from an existent MBean produces ListenerNotFoundException CountListener count3 = new CountListener(); @@ -146,8 +146,8 @@ public static void main(String[] args) throws Exception { mbean.sendNotification(notif); Thread.sleep(200); - assertTrue("New value of count1 == 1", count1Val.get() == 1); - assertTrue("Initial value of count2 == 1", count2Val.get() == 1); + assertTrue("Value of count1 expected 1, got " + count1Val.get(), count1Val.get() == 1); + assertTrue("Value of count2 expected 1, got " + count2Val.get(), count2Val.get() == 1); // wait for the listener cleanup to take place upon processing notifications int countdown = 50; // waiting max. 5 secs diff --git a/test/jdk/javax/management/remote/mandatory/subjectDelegation/SimpleStandard.java b/test/jdk/javax/management/remote/mandatory/subjectDelegation/SimpleStandard.java deleted file mode 100644 index 72415a33cc5..00000000000 --- a/test/jdk/javax/management/remote/mandatory/subjectDelegation/SimpleStandard.java +++ /dev/null @@ -1,184 +0,0 @@ -/* - * Copyright (c) 2003, 2008, 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. - */ - -/** - * Simple definition of a standard MBean, named "SimpleStandard". - * - * The "SimpleStandard" standard MBean shows how to expose attributes and - * operations for management by implementing its corresponding - * "SimpleStandardMBean" management interface. - * - * This MBean has two attributes and one operation exposed - * for management by a JMX agent: - * - the read/write "State" attribute, - * - the read only "NbChanges" attribute, - * - the "reset()" operation. - * - * This object also has one property and one method not exposed - * for management by a JMX agent: - * - the "NbResets" property, - * - the "getNbResets()" method. - */ - -import java.security.AccessControlContext; -import java.security.AccessController; -import java.security.Principal; -import java.util.Set; -import javax.management.AttributeChangeNotification; -import javax.management.NotificationBroadcasterSupport; -import javax.management.remote.JMXPrincipal; -import javax.security.auth.Subject; - -public class SimpleStandard - extends NotificationBroadcasterSupport - implements SimpleStandardMBean { - - /* - * ----------------------------------------------------- - * CONSTRUCTORS - * ----------------------------------------------------- - */ - - public SimpleStandard(String principalName) { - this.principalName = principalName; - } - - /* - * ----------------------------------------------------- - * IMPLEMENTATION OF THE SimpleStandardMBean INTERFACE - * ----------------------------------------------------- - */ - - /** - * Getter: get the "State" attribute of the "SimpleStandard" standard MBean. - * - * @return the current value of the "State" attribute. - */ - public String getState() { - checkSubject("getState"); - return state; - } - - /** - * Setter: set the "State" attribute of the "SimpleStandard" standard MBean. - * - * @param s the new value of the "State" attribute. - */ - public void setState(String s) { - checkSubject("setState"); - state = s; - nbChanges++; - } - - /** - * Getter: get the "NbChanges" attribute of the "SimpleStandard" standard - * MBean. - * - * @return the current value of the "NbChanges" attribute. - */ - public int getNbChanges() { - checkSubject("getNbChanges"); - return nbChanges; - } - - /** - * Operation: reset to their initial values the "State" and "NbChanges" - * attributes of the "SimpleStandard" standard MBean. - */ - public void reset() { - checkSubject("reset"); - AttributeChangeNotification acn = - new AttributeChangeNotification(this, - 0, - 0, - "NbChanges reset", - "NbChanges", - "Integer", - new Integer(nbChanges), - new Integer(0)); - state = "initial state"; - nbChanges = 0; - nbResets++; - sendNotification(acn); - } - - /* - * ----------------------------------------------------- - * METHOD NOT EXPOSED FOR MANAGEMENT BY A JMX AGENT - * ----------------------------------------------------- - */ - - /** - * Return the "NbResets" property. - * This method is not a Getter in the JMX sense because - * it is not exposed in the "SimpleStandardMBean" interface. - * - * @return the current value of the "NbResets" property. - */ - public int getNbResets() { - return nbResets; - } - - /* - * --------------- - * PRIVATE METHODS - * --------------- - */ - - /** - * Check that the principal contained in the Subject is of - * type JMXPrincipal and refers to the principalName identity. - */ - private void checkSubject(String op) { - AccessControlContext acc = AccessController.getContext(); - Subject subject = Subject.getSubject(acc); - Set principals = subject.getPrincipals(); - Principal principal = (Principal) principals.iterator().next(); - if (!(principal instanceof JMXPrincipal)) - throw new SecurityException(op+": Authenticated subject contains " + - "invalid principal type = " + - principal.getClass().getName()); - String identity = principal.getName(); - if (!identity.equals(principalName)) - throw new SecurityException(op+": Authenticated subject contains " + - "invalid principal name = " + identity); - } - - /* - * ----------------------------------------------------- - * ATTRIBUTES ACCESSIBLE FOR MANAGEMENT BY A JMX AGENT - * ----------------------------------------------------- - */ - - private String state = "initial state"; - private int nbChanges = 0; - - /* - * ----------------------------------------------------- - * PROPERTY NOT ACCESSIBLE FOR MANAGEMENT BY A JMX AGENT - * ----------------------------------------------------- - */ - - private int nbResets = 0; - private String principalName; -} diff --git a/test/jdk/javax/management/remote/mandatory/subjectDelegation/SimpleStandardMBean.java b/test/jdk/javax/management/remote/mandatory/subjectDelegation/SimpleStandardMBean.java deleted file mode 100644 index 5b1921ccdbb..00000000000 --- a/test/jdk/javax/management/remote/mandatory/subjectDelegation/SimpleStandardMBean.java +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Copyright (c) 2003, 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. - */ - -/** - * This is the management interface explicitly defined for the - * "SimpleStandard" standard MBean. - * The "SimpleStandard" standard MBean implements this interface - * in order to be manageable through a JMX agent. - * - * The "SimpleStandardMBean" interface shows how to expose for management: - * - a read/write attribute (named "State") through its getter and setter - * methods, - * - a read-only attribute (named "NbChanges") through its getter method, - * - an operation (named "reset"). - */ -public interface SimpleStandardMBean { - - /** - * Getter: set the "State" attribute of the "SimpleStandard" standard - * MBean. - * - * @return the current value of the "State" attribute. - */ - public String getState(); - - /** - * Setter: set the "State" attribute of the "SimpleStandard" standard - * MBean. - * - * @param s the new value of the "State" attribute. - */ - public void setState(String s); - - /** - * Getter: get the "NbChanges" attribute of the "SimpleStandard" standard - * MBean. - * - * @return the current value of the "NbChanges" attribute. - */ - public int getNbChanges(); - - /** - * Operation: reset to their initial values the "State" and "NbChanges" - * attributes of the "SimpleStandard" standard MBean. - */ - public void reset(); -} diff --git a/test/jdk/javax/management/remote/mandatory/subjectDelegation/SubjectDelegation1Test.java b/test/jdk/javax/management/remote/mandatory/subjectDelegation/SubjectDelegation1Test.java deleted file mode 100644 index 31228b5d030..00000000000 --- a/test/jdk/javax/management/remote/mandatory/subjectDelegation/SubjectDelegation1Test.java +++ /dev/null @@ -1,226 +0,0 @@ -/* - * 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 - * 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 6261831 - * @summary Tests the use of the subject delegation feature in the - * RMI connector - * @author Luis-Miguel Alventosa - * @modules java.management.rmi - * java.management/com.sun.jmx.remote.security - * @run clean SubjectDelegation1Test SimpleStandard SimpleStandardMBean - * @run build SubjectDelegation1Test SimpleStandard SimpleStandardMBean - * @run main/othervm -Djava.security.manager=allow SubjectDelegation1Test policy11 ok - * @run main/othervm -Djava.security.manager=allow SubjectDelegation1Test policy12 ko - * @run main/othervm -Djava.security.manager=allow SubjectDelegation1Test policy13 ko - * @run main/othervm -Djava.security.manager=allow SubjectDelegation1Test policy14 ko - * @run main/othervm -Djava.security.manager=allow SubjectDelegation1Test policy15 ok - * @run main/othervm -Djava.security.manager=allow SubjectDelegation1Test policy16 ko - */ - -import com.sun.jmx.remote.security.JMXPluggableAuthenticator; -import java.io.File; -import java.lang.management.ManagementFactory; -import java.rmi.RemoteException; -import java.rmi.registry.LocateRegistry; -import java.rmi.registry.Registry; -import java.util.Collections; -import java.util.HashMap; -import java.util.Properties; -import javax.management.Attribute; -import javax.management.MBeanServer; -import javax.management.MBeanServerConnection; -import javax.management.Notification; -import javax.management.NotificationListener; -import javax.management.ObjectName; -import javax.management.remote.JMXConnector; -import javax.management.remote.JMXConnectorFactory; -import javax.management.remote.JMXConnectorServer; -import javax.management.remote.JMXConnectorServerFactory; -import javax.management.remote.JMXPrincipal; -import javax.management.remote.JMXServiceURL; -import javax.security.auth.Subject; - -public class SubjectDelegation1Test { - - public static void main(String[] args) throws Exception { - String policyFile = args[0]; - String testResult = args[1]; - System.out.println("Policy file = " + policyFile); - System.out.println("Expected test result = " + testResult); - JMXConnectorServer jmxcs = null; - JMXConnector jmxc = null; - try { - // Create an RMI registry - // - System.out.println("Start RMI registry..."); - Registry reg = null; - int port = 5860; - while (port++ < 5880) { - try { - reg = LocateRegistry.createRegistry(port); - System.out.println("RMI registry running on port " + port); - break; - } catch (RemoteException e) { - // Failed to create RMI registry... - System.out.println("Failed to create RMI registry " + - "on port " + port); - } - } - if (reg == null) { - System.exit(1); - } - // Set the default password file - // - final String passwordFile = System.getProperty("test.src") + - File.separator + "jmxremote.password"; - System.out.println("Password file = " + passwordFile); - // Set policy file - // - final String policy = System.getProperty("test.src") + - File.separator + policyFile; - System.out.println("PolicyFile = " + policy); - System.setProperty("java.security.policy", policy); - // Instantiate the MBean server - // - System.out.println("Create the MBean server"); - MBeanServer mbs = ManagementFactory.getPlatformMBeanServer(); - // Register the SimpleStandardMBean - // - System.out.println("Create SimpleStandard MBean"); - SimpleStandard s = new SimpleStandard("delegate"); - mbs.registerMBean(s, new ObjectName("MBeans:type=SimpleStandard")); - // Create Properties containing the username/password entries - // - Properties props = new Properties(); - props.setProperty("jmx.remote.x.password.file", passwordFile); - // Initialize environment map to be passed to the connector server - // - System.out.println("Initialize environment map"); - HashMap env = new HashMap(); - env.put("jmx.remote.authenticator", - new JMXPluggableAuthenticator(props)); - // Create an RMI connector server - // - System.out.println("Create an RMI connector server"); - JMXServiceURL url = - new JMXServiceURL("rmi", null, 0, - "/jndi/rmi://:" + port + "/server" + port); - jmxcs = - JMXConnectorServerFactory.newJMXConnectorServer(url, env, mbs); - jmxcs.start(); - // Create an RMI connector client - // - System.out.println("Create an RMI connector client"); - HashMap cli_env = new HashMap(); - // These credentials must match those in the default password file - // - String[] credentials = new String[] { "monitorRole" , "QED" }; - cli_env.put("jmx.remote.credentials", credentials); - jmxc = JMXConnectorFactory.connect(url, cli_env); - Subject delegationSubject = - new Subject(true, - Collections.singleton(new JMXPrincipal("delegate")), - Collections.EMPTY_SET, - Collections.EMPTY_SET); - MBeanServerConnection mbsc = - jmxc.getMBeanServerConnection(delegationSubject); - // Get domains from MBeanServer - // - System.out.println("Domains:"); - String domains[] = mbsc.getDomains(); - for (int i = 0; i < domains.length; i++) { - System.out.println("\tDomain[" + i + "] = " + domains[i]); - } - // Get MBean count - // - System.out.println("MBean count = " + mbsc.getMBeanCount()); - // Get State attribute - // - String oldState = - (String) mbsc.getAttribute( - new ObjectName("MBeans:type=SimpleStandard"), - "State"); - System.out.println("Old State = \"" + oldState + "\""); - // Set State attribute - // - System.out.println("Set State to \"changed state\""); - mbsc.setAttribute(new ObjectName("MBeans:type=SimpleStandard"), - new Attribute("State", "changed state")); - // Get State attribute - // - String newState = - (String) mbsc.getAttribute( - new ObjectName("MBeans:type=SimpleStandard"), - "State"); - System.out.println("New State = \"" + newState + "\""); - if (!newState.equals("changed state")) { - System.out.println("Invalid State = \"" + newState + "\""); - System.exit(1); - } - // Add notification listener on SimpleStandard MBean - // - System.out.println("Add notification listener..."); - mbsc.addNotificationListener( - new ObjectName("MBeans:type=SimpleStandard"), - new NotificationListener() { - public void handleNotification(Notification notification, - Object handback) { - System.out.println("Received notification: " + - notification); - } - }, - null, - null); - // Unregister SimpleStandard MBean - // - System.out.println("Unregister SimpleStandard MBean..."); - mbsc.unregisterMBean(new ObjectName("MBeans:type=SimpleStandard")); - } catch (SecurityException e) { - if (testResult.equals("ko")) { - System.out.println("Got expected security exception = " + e); - } else { - System.out.println("Got unexpected security exception = " + e); - e.printStackTrace(); - throw e; - } - } catch (Exception e) { - System.out.println("Unexpected exception caught = " + e); - e.printStackTrace(); - throw e; - } finally { - // Close connector client - // - if (jmxc != null) - jmxc.close(); - // Stop connector server - // - if (jmxcs != null) - jmxcs.stop(); - // Say goodbye - // - System.out.println("Bye! Bye!"); - } - } -} diff --git a/test/jdk/javax/management/remote/mandatory/subjectDelegation/SubjectDelegation2Test.java b/test/jdk/javax/management/remote/mandatory/subjectDelegation/SubjectDelegation2Test.java deleted file mode 100644 index 65c8f4b1f5f..00000000000 --- a/test/jdk/javax/management/remote/mandatory/subjectDelegation/SubjectDelegation2Test.java +++ /dev/null @@ -1,218 +0,0 @@ -/* - * Copyright (c) 2005, 2023, 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 6261831 - * @summary Tests the use of the subject delegation feature on the authenticated - * principals within the RMI connector server's creator codebase. - * @author Luis-Miguel Alventosa - * @modules java.management.rmi - * java.management/com.sun.jmx.remote.security - * @run clean SubjectDelegation2Test SimpleStandard SimpleStandardMBean - * @run build SubjectDelegation2Test SimpleStandard SimpleStandardMBean - * @run main/othervm -Djava.security.manager=allow SubjectDelegation2Test policy21 ok - * @run main/othervm -Djava.security.manager=allow SubjectDelegation2Test policy22 ko - * @run main/othervm -Djava.security.manager=allow SubjectDelegation2Test policy23 ko - * @run main/othervm -Djava.security.manager=allow SubjectDelegation2Test policy24 ok - * @run main/othervm -Djava.security.manager=allow SubjectDelegation2Test policy25 ko - */ - -import com.sun.jmx.remote.security.JMXPluggableAuthenticator; -import java.io.File; -import java.lang.management.ManagementFactory; -import java.rmi.RemoteException; -import java.rmi.registry.LocateRegistry; -import java.rmi.registry.Registry; -import java.util.HashMap; -import java.util.Properties; -import javax.management.Attribute; -import javax.management.MBeanServer; -import javax.management.MBeanServerConnection; -import javax.management.Notification; -import javax.management.NotificationListener; -import javax.management.ObjectName; -import javax.management.remote.JMXConnector; -import javax.management.remote.JMXConnectorFactory; -import javax.management.remote.JMXConnectorServer; -import javax.management.remote.JMXConnectorServerFactory; -import javax.management.remote.JMXServiceURL; - -public class SubjectDelegation2Test { - - public static void main(String[] args) throws Exception { - String policyFile = args[0]; - String testResult = args[1]; - System.out.println("Policy file = " + policyFile); - System.out.println("Expected test result = " + testResult); - JMXConnectorServer jmxcs = null; - JMXConnector jmxc = null; - try { - // Create an RMI registry - // - System.out.println("Start RMI registry..."); - Registry reg = null; - int port = 5880; - while (port++ < 5900) { - try { - reg = LocateRegistry.createRegistry(port); - System.out.println("RMI registry running on port " + port); - break; - } catch (RemoteException e) { - // Failed to create RMI registry... - System.out.println("Failed to create RMI registry " + - "on port " + port); - } - } - if (reg == null) { - System.exit(1); - } - // Set the default password file - // - final String passwordFile = System.getProperty("test.src") + - File.separator + "jmxremote.password"; - System.out.println("Password file = " + passwordFile); - // Set policy file - // - final String policy = System.getProperty("test.src") + - File.separator + policyFile; - System.out.println("PolicyFile = " + policy); - System.setProperty("java.security.policy", policy); - // Instantiate the MBean server - // - System.out.println("Create the MBean server"); - MBeanServer mbs = ManagementFactory.getPlatformMBeanServer(); - // Register the SimpleStandardMBean - // - System.out.println("Create SimpleStandard MBean"); - SimpleStandard s = new SimpleStandard("monitorRole"); - mbs.registerMBean(s, new ObjectName("MBeans:type=SimpleStandard")); - // Create Properties containing the username/password entries - // - Properties props = new Properties(); - props.setProperty("jmx.remote.x.password.file", passwordFile); - // Initialize environment map to be passed to the connector server - // - System.out.println("Initialize environment map"); - HashMap env = new HashMap(); - env.put("jmx.remote.authenticator", - new JMXPluggableAuthenticator(props)); - // Set Security Manager - // - System.setSecurityManager(new SecurityManager()); - // Create an RMI connector server - // - System.out.println("Create an RMI connector server"); - JMXServiceURL url = new JMXServiceURL("rmi", null, 0); - - jmxcs = - JMXConnectorServerFactory.newJMXConnectorServer(url, env, mbs); - jmxcs.start(); - // Create an RMI connector client - // - System.out.println("Create an RMI connector client"); - HashMap cli_env = new HashMap(); - // These credentials must match those in the default password file - // - String[] credentials = new String[] { "monitorRole" , "QED" }; - cli_env.put("jmx.remote.credentials", credentials); - jmxc = JMXConnectorFactory.connect(jmxcs.getAddress(), cli_env); - MBeanServerConnection mbsc = jmxc.getMBeanServerConnection(); - // Get domains from MBeanServer - // - System.out.println("Domains:"); - String domains[] = mbsc.getDomains(); - for (int i = 0; i < domains.length; i++) { - System.out.println("\tDomain[" + i + "] = " + domains[i]); - } - // Get MBean count - // - System.out.println("MBean count = " + mbsc.getMBeanCount()); - // Get State attribute - // - String oldState = - (String) mbsc.getAttribute( - new ObjectName("MBeans:type=SimpleStandard"), - "State"); - System.out.println("Old State = \"" + oldState + "\""); - // Set State attribute - // - System.out.println("Set State to \"changed state\""); - mbsc.setAttribute(new ObjectName("MBeans:type=SimpleStandard"), - new Attribute("State", "changed state")); - // Get State attribute - // - String newState = - (String) mbsc.getAttribute( - new ObjectName("MBeans:type=SimpleStandard"), - "State"); - System.out.println("New State = \"" + newState + "\""); - if (!newState.equals("changed state")) { - System.out.println("Invalid State = \"" + newState + "\""); - System.exit(1); - } - // Add notification listener on SimpleStandard MBean - // - System.out.println("Add notification listener..."); - mbsc.addNotificationListener( - new ObjectName("MBeans:type=SimpleStandard"), - new NotificationListener() { - public void handleNotification(Notification notification, - Object handback) { - System.out.println("Received notification: " + - notification); - } - }, - null, - null); - // Unregister SimpleStandard MBean - // - System.out.println("Unregister SimpleStandard MBean..."); - mbsc.unregisterMBean(new ObjectName("MBeans:type=SimpleStandard")); - } catch (SecurityException e) { - if (testResult.equals("ko")) { - System.out.println("Got expected security exception = " + e); - } else { - System.out.println("Got unexpected security exception = " + e); - e.printStackTrace(); - throw e; - } - } catch (Exception e) { - System.out.println("Unexpected exception caught = " + e); - e.printStackTrace(); - throw e; - } finally { - // Close connector client - // - if (jmxc != null) - jmxc.close(); - // Stop connector server - // - if (jmxcs != null) - jmxcs.stop(); - // Say goodbye - // - System.out.println("Bye! Bye!"); - } - } -} diff --git a/test/jdk/javax/management/remote/mandatory/subjectDelegation/SubjectDelegation3Test.java b/test/jdk/javax/management/remote/mandatory/subjectDelegation/SubjectDelegation3Test.java deleted file mode 100644 index 5550b6cfe31..00000000000 --- a/test/jdk/javax/management/remote/mandatory/subjectDelegation/SubjectDelegation3Test.java +++ /dev/null @@ -1,228 +0,0 @@ -/* - * Copyright (c) 2005, 2023, 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 6261831 - * @summary Tests the use of the subject delegation feature on the authenticated - * principals within the RMI connector server's creator codebase with - * subject delegation. - * @author Luis-Miguel Alventosa - * @modules java.management.rmi - * java.management/com.sun.jmx.remote.security - * @run clean SubjectDelegation3Test SimpleStandard SimpleStandardMBean - * @run build SubjectDelegation3Test SimpleStandard SimpleStandardMBean - * @run main/othervm -Djava.security.manager=allow SubjectDelegation3Test policy31 ok - * @run main/othervm -Djava.security.manager=allow SubjectDelegation3Test policy32 ko - * @run main/othervm -Djava.security.manager=allow SubjectDelegation3Test policy33 ko - * @run main/othervm -Djava.security.manager=allow SubjectDelegation3Test policy34 ok - * @run main/othervm -Djava.security.manager=allow SubjectDelegation3Test policy35 ko - */ - -import com.sun.jmx.remote.security.JMXPluggableAuthenticator; -import java.io.File; -import java.lang.management.ManagementFactory; -import java.rmi.RemoteException; -import java.rmi.registry.LocateRegistry; -import java.rmi.registry.Registry; -import java.util.Collections; -import java.util.HashMap; -import java.util.Properties; -import javax.management.Attribute; -import javax.management.MBeanServer; -import javax.management.MBeanServerConnection; -import javax.management.Notification; -import javax.management.NotificationListener; -import javax.management.ObjectName; -import javax.management.remote.JMXConnector; -import javax.management.remote.JMXConnectorFactory; -import javax.management.remote.JMXConnectorServer; -import javax.management.remote.JMXConnectorServerFactory; -import javax.management.remote.JMXPrincipal; -import javax.management.remote.JMXServiceURL; -import javax.security.auth.Subject; - -public class SubjectDelegation3Test { - - public static void main(String[] args) throws Exception { - String policyFile = args[0]; - String testResult = args[1]; - System.out.println("Policy file = " + policyFile); - System.out.println("Expected test result = " + testResult); - JMXConnectorServer jmxcs = null; - JMXConnector jmxc = null; - try { - // Create an RMI registry - // - System.out.println("Start RMI registry..."); - Registry reg = null; - int port = 5900; - while (port++ < 5920) { - try { - reg = LocateRegistry.createRegistry(port); - System.out.println("RMI registry running on port " + port); - break; - } catch (RemoteException e) { - // Failed to create RMI registry... - System.out.println("Failed to create RMI registry " + - "on port " + port); - } - } - if (reg == null) { - System.exit(1); - } - // Set the default password file - // - final String passwordFile = System.getProperty("test.src") + - File.separator + "jmxremote.password"; - System.out.println("Password file = " + passwordFile); - // Set policy file - // - final String policy = System.getProperty("test.src") + - File.separator + policyFile; - System.out.println("PolicyFile = " + policy); - System.setProperty("java.security.policy", policy); - // Instantiate the MBean server - // - System.out.println("Create the MBean server"); - MBeanServer mbs = ManagementFactory.getPlatformMBeanServer(); - // Register the SimpleStandardMBean - // - System.out.println("Create SimpleStandard MBean"); - SimpleStandard s = new SimpleStandard("delegate"); - mbs.registerMBean(s, new ObjectName("MBeans:type=SimpleStandard")); - // Create Properties containing the username/password entries - // - Properties props = new Properties(); - props.setProperty("jmx.remote.x.password.file", passwordFile); - // Initialize environment map to be passed to the connector server - // - System.out.println("Initialize environment map"); - HashMap env = new HashMap(); - env.put("jmx.remote.authenticator", - new JMXPluggableAuthenticator(props)); - // Set Security Manager - // - System.setSecurityManager(new SecurityManager()); - // Create an RMI connector server - // - System.out.println("Create an RMI connector server"); - JMXServiceURL url = - new JMXServiceURL("rmi", null, 0); - jmxcs = - JMXConnectorServerFactory.newJMXConnectorServer(url, env, mbs); - jmxcs.start(); - // Create an RMI connector client - // - System.out.println("Create an RMI connector client"); - HashMap cli_env = new HashMap(); - // These credentials must match those in the default password file - // - String[] credentials = new String[] { "monitorRole" , "QED" }; - cli_env.put("jmx.remote.credentials", credentials); - jmxc = JMXConnectorFactory.connect(jmxcs.getAddress(), cli_env); - Subject delegationSubject = - new Subject(true, - Collections.singleton(new JMXPrincipal("delegate")), - Collections.EMPTY_SET, - Collections.EMPTY_SET); - MBeanServerConnection mbsc = - jmxc.getMBeanServerConnection(delegationSubject); - // Get domains from MBeanServer - // - System.out.println("Domains:"); - String domains[] = mbsc.getDomains(); - for (int i = 0; i < domains.length; i++) { - System.out.println("\tDomain[" + i + "] = " + domains[i]); - } - // Get MBean count - // - System.out.println("MBean count = " + mbsc.getMBeanCount()); - // Get State attribute - // - String oldState = - (String) mbsc.getAttribute( - new ObjectName("MBeans:type=SimpleStandard"), - "State"); - System.out.println("Old State = \"" + oldState + "\""); - // Set State attribute - // - System.out.println("Set State to \"changed state\""); - mbsc.setAttribute(new ObjectName("MBeans:type=SimpleStandard"), - new Attribute("State", "changed state")); - // Get State attribute - // - String newState = - (String) mbsc.getAttribute( - new ObjectName("MBeans:type=SimpleStandard"), - "State"); - System.out.println("New State = \"" + newState + "\""); - if (!newState.equals("changed state")) { - System.out.println("Invalid State = \"" + newState + "\""); - System.exit(1); - } - // Add notification listener on SimpleStandard MBean - // - System.out.println("Add notification listener..."); - mbsc.addNotificationListener( - new ObjectName("MBeans:type=SimpleStandard"), - new NotificationListener() { - public void handleNotification(Notification notification, - Object handback) { - System.out.println("Received notification: " + - notification); - } - }, - null, - null); - // Unregister SimpleStandard MBean - // - System.out.println("Unregister SimpleStandard MBean..."); - mbsc.unregisterMBean(new ObjectName("MBeans:type=SimpleStandard")); - } catch (SecurityException e) { - if (testResult.equals("ko")) { - System.out.println("Got expected security exception = " + e); - } else { - System.out.println("Got unexpected security exception = " + e); - e.printStackTrace(); - throw e; - } - } catch (Exception e) { - System.out.println("Unexpected exception caught = " + e); - e.printStackTrace(); - throw e; - } finally { - // Close connector client - // - if (jmxc != null) - jmxc.close(); - // Stop connector server - // - if (jmxcs != null) - jmxcs.stop(); - // Say goodbye - // - System.out.println("Bye! Bye!"); - } - } -} diff --git a/test/jdk/javax/management/remote/mandatory/subjectDelegation/jmxremote.password b/test/jdk/javax/management/remote/mandatory/subjectDelegation/jmxremote.password deleted file mode 100644 index b29b668159c..00000000000 --- a/test/jdk/javax/management/remote/mandatory/subjectDelegation/jmxremote.password +++ /dev/null @@ -1 +0,0 @@ -monitorRole QED diff --git a/test/jdk/javax/management/remote/mandatory/subjectDelegation/policy11 b/test/jdk/javax/management/remote/mandatory/subjectDelegation/policy11 deleted file mode 100644 index bcd7896ce2e..00000000000 --- a/test/jdk/javax/management/remote/mandatory/subjectDelegation/policy11 +++ /dev/null @@ -1,7 +0,0 @@ -grant { - permission javax.management.remote.SubjectDelegationPermission "javax.management.remote.JMXPrincipal.delegate"; -}; - -grant principal javax.management.remote.JMXPrincipal "monitorRole" { - permission javax.management.remote.SubjectDelegationPermission "javax.management.remote.JMXPrincipal.delegate"; -}; diff --git a/test/jdk/javax/management/remote/mandatory/subjectDelegation/policy12 b/test/jdk/javax/management/remote/mandatory/subjectDelegation/policy12 deleted file mode 100644 index 7b7b547a8cb..00000000000 --- a/test/jdk/javax/management/remote/mandatory/subjectDelegation/policy12 +++ /dev/null @@ -1,6 +0,0 @@ -grant { - permission javax.management.remote.SubjectDelegationPermission "javax.management.remote.JMXPrincipal.delegate"; -}; - -grant principal javax.management.remote.JMXPrincipal "monitorRole" { -}; diff --git a/test/jdk/javax/management/remote/mandatory/subjectDelegation/policy13 b/test/jdk/javax/management/remote/mandatory/subjectDelegation/policy13 deleted file mode 100644 index 6609c33c80c..00000000000 --- a/test/jdk/javax/management/remote/mandatory/subjectDelegation/policy13 +++ /dev/null @@ -1,6 +0,0 @@ -grant { -}; - -grant principal javax.management.remote.JMXPrincipal "monitorRole" { - permission javax.management.remote.SubjectDelegationPermission "javax.management.remote.JMXPrincipal.delegate"; -}; diff --git a/test/jdk/javax/management/remote/mandatory/subjectDelegation/policy14 b/test/jdk/javax/management/remote/mandatory/subjectDelegation/policy14 deleted file mode 100644 index 02d1525f14f..00000000000 --- a/test/jdk/javax/management/remote/mandatory/subjectDelegation/policy14 +++ /dev/null @@ -1,5 +0,0 @@ -grant { -}; - -grant principal javax.management.remote.JMXPrincipal "monitorRole" { -}; diff --git a/test/jdk/javax/management/remote/mandatory/subjectDelegation/policy15 b/test/jdk/javax/management/remote/mandatory/subjectDelegation/policy15 deleted file mode 100644 index efdb46a9a17..00000000000 --- a/test/jdk/javax/management/remote/mandatory/subjectDelegation/policy15 +++ /dev/null @@ -1,7 +0,0 @@ -grant { - permission javax.management.remote.SubjectDelegationPermission "javax.management.remote.JMXPrincipal.monitorRole"; -}; - -grant principal javax.management.remote.JMXPrincipal "monitorRole" { - permission javax.management.remote.SubjectDelegationPermission "javax.management.remote.JMXPrincipal.delegate"; -}; diff --git a/test/jdk/javax/management/remote/mandatory/subjectDelegation/policy16 b/test/jdk/javax/management/remote/mandatory/subjectDelegation/policy16 deleted file mode 100644 index 65bd1f9a275..00000000000 --- a/test/jdk/javax/management/remote/mandatory/subjectDelegation/policy16 +++ /dev/null @@ -1,6 +0,0 @@ -grant { - permission javax.management.remote.SubjectDelegationPermission "javax.management.remote.JMXPrincipal.monitorRole"; -}; - -grant principal javax.management.remote.JMXPrincipal "monitorRole" { -}; diff --git a/test/jdk/javax/management/remote/mandatory/subjectDelegation/policy21 b/test/jdk/javax/management/remote/mandatory/subjectDelegation/policy21 deleted file mode 100644 index 32756230e7c..00000000000 --- a/test/jdk/javax/management/remote/mandatory/subjectDelegation/policy21 +++ /dev/null @@ -1,25 +0,0 @@ -grant { - permission javax.security.auth.AuthPermission "createLoginContext.JMXPluggableAuthenticator"; - permission java.net.SocketPermission "*:*", "accept,connect,listen,resolve"; - permission java.security.SecurityPermission "createAccessControlContext"; - permission java.lang.RuntimePermission "*"; - permission javax.management.MBeanPermission "*", "getDomains"; - permission javax.management.MBeanPermission "SimpleStandard#State[MBeans:type=SimpleStandard]", "getAttribute"; - permission javax.security.auth.AuthPermission "getSubject"; - permission javax.management.MBeanPermission "SimpleStandard#State[MBeans:type=SimpleStandard]", "setAttribute"; - permission javax.management.MBeanPermission "SimpleStandard#-[MBeans:type=SimpleStandard]", "addNotificationListener"; - permission javax.management.MBeanPermission "javax.management.MBeanServerDelegate#-[JMImplementation:type=MBeanServerDelegate]", "addNotificationListener"; - permission javax.management.MBeanPermission "javax.management.MBeanServerDelegate#-[JMImplementation:type=MBeanServerDelegate]", "removeNotificationListener"; - permission javax.management.MBeanPermission "SimpleStandard#-[MBeans:type=SimpleStandard]", "unregisterMBean"; -}; - -grant principal javax.management.remote.JMXPrincipal "monitorRole" { - permission javax.management.MBeanPermission "*", "getDomains"; - permission javax.management.MBeanPermission "SimpleStandard#State[MBeans:type=SimpleStandard]", "getAttribute"; - permission javax.security.auth.AuthPermission "getSubject"; - permission javax.management.MBeanPermission "SimpleStandard#State[MBeans:type=SimpleStandard]", "setAttribute"; - permission javax.management.MBeanPermission "SimpleStandard#-[MBeans:type=SimpleStandard]", "addNotificationListener"; - permission javax.management.MBeanPermission "javax.management.MBeanServerDelegate#-[JMImplementation:type=MBeanServerDelegate]", "addNotificationListener"; - permission javax.management.MBeanPermission "javax.management.MBeanServerDelegate#-[JMImplementation:type=MBeanServerDelegate]", "removeNotificationListener"; - permission javax.management.MBeanPermission "SimpleStandard#-[MBeans:type=SimpleStandard]", "unregisterMBean"; -}; diff --git a/test/jdk/javax/management/remote/mandatory/subjectDelegation/policy22 b/test/jdk/javax/management/remote/mandatory/subjectDelegation/policy22 deleted file mode 100644 index cd1bbc2bb4f..00000000000 --- a/test/jdk/javax/management/remote/mandatory/subjectDelegation/policy22 +++ /dev/null @@ -1,25 +0,0 @@ -grant { - permission javax.security.auth.AuthPermission "createLoginContext.JMXPluggableAuthenticator"; - permission java.net.SocketPermission "*:*", "accept,connect,listen,resolve"; - permission java.lang.RuntimePermission "*"; - permission java.security.SecurityPermission "createAccessControlContext"; -// permission javax.management.MBeanPermission "*", "getDomains"; - permission javax.management.MBeanPermission "SimpleStandard#State[MBeans:type=SimpleStandard]", "getAttribute"; - permission javax.security.auth.AuthPermission "getSubject"; - permission javax.management.MBeanPermission "SimpleStandard#State[MBeans:type=SimpleStandard]", "setAttribute"; - permission javax.management.MBeanPermission "SimpleStandard#-[MBeans:type=SimpleStandard]", "addNotificationListener"; - permission javax.management.MBeanPermission "javax.management.MBeanServerDelegate#-[JMImplementation:type=MBeanServerDelegate]", "addNotificationListener"; - permission javax.management.MBeanPermission "javax.management.MBeanServerDelegate#-[JMImplementation:type=MBeanServerDelegate]", "removeNotificationListener"; - permission javax.management.MBeanPermission "SimpleStandard#-[MBeans:type=SimpleStandard]", "unregisterMBean"; -}; - -grant principal javax.management.remote.JMXPrincipal "monitorRole" { - permission javax.management.MBeanPermission "*", "getDomains"; - permission javax.management.MBeanPermission "SimpleStandard#State[MBeans:type=SimpleStandard]", "getAttribute"; - permission javax.security.auth.AuthPermission "getSubject"; - permission javax.management.MBeanPermission "SimpleStandard#State[MBeans:type=SimpleStandard]", "setAttribute"; - permission javax.management.MBeanPermission "SimpleStandard#-[MBeans:type=SimpleStandard]", "addNotificationListener"; - permission javax.management.MBeanPermission "javax.management.MBeanServerDelegate#-[JMImplementation:type=MBeanServerDelegate]", "addNotificationListener"; - permission javax.management.MBeanPermission "javax.management.MBeanServerDelegate#-[JMImplementation:type=MBeanServerDelegate]", "removeNotificationListener"; - permission javax.management.MBeanPermission "SimpleStandard#-[MBeans:type=SimpleStandard]", "unregisterMBean"; -}; diff --git a/test/jdk/javax/management/remote/mandatory/subjectDelegation/policy23 b/test/jdk/javax/management/remote/mandatory/subjectDelegation/policy23 deleted file mode 100644 index 47b3cc194ee..00000000000 --- a/test/jdk/javax/management/remote/mandatory/subjectDelegation/policy23 +++ /dev/null @@ -1,25 +0,0 @@ -grant { - permission javax.security.auth.AuthPermission "createLoginContext.JMXPluggableAuthenticator"; - permission java.net.SocketPermission "*:*", "accept,connect,listen,resolve"; - permission java.lang.RuntimePermission "*"; - permission java.security.SecurityPermission "createAccessControlContext"; - permission javax.management.MBeanPermission "*", "getDomains"; - permission javax.management.MBeanPermission "SimpleStandard#State[MBeans:type=SimpleStandard]", "getAttribute"; - permission javax.security.auth.AuthPermission "getSubject"; - permission javax.management.MBeanPermission "SimpleStandard#State[MBeans:type=SimpleStandard]", "setAttribute"; - permission javax.management.MBeanPermission "SimpleStandard#-[MBeans:type=SimpleStandard]", "addNotificationListener"; - permission javax.management.MBeanPermission "javax.management.MBeanServerDelegate#-[JMImplementation:type=MBeanServerDelegate]", "addNotificationListener"; - permission javax.management.MBeanPermission "javax.management.MBeanServerDelegate#-[JMImplementation:type=MBeanServerDelegate]", "removeNotificationListener"; - permission javax.management.MBeanPermission "SimpleStandard#-[MBeans:type=SimpleStandard]", "unregisterMBean"; -}; - -grant principal javax.management.remote.JMXPrincipal "monitorRole" { -// permission javax.management.MBeanPermission "*", "getDomains"; - permission javax.management.MBeanPermission "SimpleStandard#State[MBeans:type=SimpleStandard]", "getAttribute"; - permission javax.security.auth.AuthPermission "getSubject"; - permission javax.management.MBeanPermission "SimpleStandard#State[MBeans:type=SimpleStandard]", "setAttribute"; - permission javax.management.MBeanPermission "SimpleStandard#-[MBeans:type=SimpleStandard]", "addNotificationListener"; - permission javax.management.MBeanPermission "javax.management.MBeanServerDelegate#-[JMImplementation:type=MBeanServerDelegate]", "addNotificationListener"; - permission javax.management.MBeanPermission "javax.management.MBeanServerDelegate#-[JMImplementation:type=MBeanServerDelegate]", "removeNotificationListener"; - permission javax.management.MBeanPermission "SimpleStandard#-[MBeans:type=SimpleStandard]", "unregisterMBean"; -}; diff --git a/test/jdk/javax/management/remote/mandatory/subjectDelegation/policy24 b/test/jdk/javax/management/remote/mandatory/subjectDelegation/policy24 deleted file mode 100644 index 228a1c0e437..00000000000 --- a/test/jdk/javax/management/remote/mandatory/subjectDelegation/policy24 +++ /dev/null @@ -1,18 +0,0 @@ -grant { - permission javax.security.auth.AuthPermission "createLoginContext.JMXPluggableAuthenticator"; - permission java.lang.RuntimePermission "*"; - permission java.net.SocketPermission "*:*", "accept,connect,listen,resolve"; - permission java.security.SecurityPermission "createAccessControlContext"; - permission javax.management.remote.SubjectDelegationPermission "javax.management.remote.JMXPrincipal.monitorRole"; -}; - -grant principal javax.management.remote.JMXPrincipal "monitorRole" { - permission javax.management.MBeanPermission "*", "getDomains"; - permission javax.management.MBeanPermission "SimpleStandard#State[MBeans:type=SimpleStandard]", "getAttribute"; - permission javax.security.auth.AuthPermission "getSubject"; - permission javax.management.MBeanPermission "SimpleStandard#State[MBeans:type=SimpleStandard]", "setAttribute"; - permission javax.management.MBeanPermission "SimpleStandard#-[MBeans:type=SimpleStandard]", "addNotificationListener"; - permission javax.management.MBeanPermission "javax.management.MBeanServerDelegate#-[JMImplementation:type=MBeanServerDelegate]", "addNotificationListener"; - permission javax.management.MBeanPermission "javax.management.MBeanServerDelegate#-[JMImplementation:type=MBeanServerDelegate]", "removeNotificationListener"; - permission javax.management.MBeanPermission "SimpleStandard#-[MBeans:type=SimpleStandard]", "unregisterMBean"; -}; diff --git a/test/jdk/javax/management/remote/mandatory/subjectDelegation/policy25 b/test/jdk/javax/management/remote/mandatory/subjectDelegation/policy25 deleted file mode 100644 index ed20121656b..00000000000 --- a/test/jdk/javax/management/remote/mandatory/subjectDelegation/policy25 +++ /dev/null @@ -1,18 +0,0 @@ -grant { - permission javax.security.auth.AuthPermission "createLoginContext.JMXPluggableAuthenticator"; - permission java.lang.RuntimePermission "*"; - permission java.net.SocketPermission "*:*", "accept,connect,listen,resolve"; - permission java.security.SecurityPermission "createAccessControlContext"; - permission javax.management.remote.SubjectDelegationPermission "javax.management.remote.JMXPrincipal.monitorRole"; -}; - -grant principal javax.management.remote.JMXPrincipal "monitorRole" { -// permission javax.management.MBeanPermission "*", "getDomains"; - permission javax.management.MBeanPermission "SimpleStandard#State[MBeans:type=SimpleStandard]", "getAttribute"; - permission javax.security.auth.AuthPermission "getSubject"; - permission javax.management.MBeanPermission "SimpleStandard#State[MBeans:type=SimpleStandard]", "setAttribute"; - permission javax.management.MBeanPermission "SimpleStandard#-[MBeans:type=SimpleStandard]", "addNotificationListener"; - permission javax.management.MBeanPermission "javax.management.MBeanServerDelegate#-[JMImplementation:type=MBeanServerDelegate]", "addNotificationListener"; - permission javax.management.MBeanPermission "javax.management.MBeanServerDelegate#-[JMImplementation:type=MBeanServerDelegate]", "removeNotificationListener"; - permission javax.management.MBeanPermission "SimpleStandard#-[MBeans:type=SimpleStandard]", "unregisterMBean"; -}; diff --git a/test/jdk/javax/management/remote/mandatory/subjectDelegation/policy31 b/test/jdk/javax/management/remote/mandatory/subjectDelegation/policy31 deleted file mode 100644 index 0f087192484..00000000000 --- a/test/jdk/javax/management/remote/mandatory/subjectDelegation/policy31 +++ /dev/null @@ -1,30 +0,0 @@ -grant { - permission javax.security.auth.AuthPermission "createLoginContext.JMXPluggableAuthenticator"; - permission java.net.SocketPermission "*:*", "accept,connect,listen,resolve"; - permission java.lang.RuntimePermission "*"; - permission java.security.SecurityPermission "createAccessControlContext"; - permission javax.management.MBeanPermission "*", "getDomains"; - permission javax.management.MBeanPermission "SimpleStandard#State[MBeans:type=SimpleStandard]", "getAttribute"; - permission javax.security.auth.AuthPermission "getSubject"; - permission javax.management.MBeanPermission "SimpleStandard#State[MBeans:type=SimpleStandard]", "setAttribute"; - permission javax.management.MBeanPermission "SimpleStandard#-[MBeans:type=SimpleStandard]", "addNotificationListener"; - permission javax.management.MBeanPermission "javax.management.MBeanServerDelegate#-[JMImplementation:type=MBeanServerDelegate]", "addNotificationListener"; - permission javax.management.MBeanPermission "javax.management.MBeanServerDelegate#-[JMImplementation:type=MBeanServerDelegate]", "removeNotificationListener"; - permission javax.management.MBeanPermission "SimpleStandard#-[MBeans:type=SimpleStandard]", "unregisterMBean"; - permission javax.management.remote.SubjectDelegationPermission "javax.management.remote.JMXPrincipal.delegate"; -}; - -grant principal javax.management.remote.JMXPrincipal "monitorRole" { - permission javax.management.remote.SubjectDelegationPermission "javax.management.remote.JMXPrincipal.delegate"; -}; - -grant principal javax.management.remote.JMXPrincipal "delegate" { - permission javax.management.MBeanPermission "*", "getDomains"; - permission javax.management.MBeanPermission "SimpleStandard#State[MBeans:type=SimpleStandard]", "getAttribute"; - permission javax.security.auth.AuthPermission "getSubject"; - permission javax.management.MBeanPermission "SimpleStandard#State[MBeans:type=SimpleStandard]", "setAttribute"; - permission javax.management.MBeanPermission "SimpleStandard#-[MBeans:type=SimpleStandard]", "addNotificationListener"; - permission javax.management.MBeanPermission "javax.management.MBeanServerDelegate#-[JMImplementation:type=MBeanServerDelegate]", "addNotificationListener"; - permission javax.management.MBeanPermission "javax.management.MBeanServerDelegate#-[JMImplementation:type=MBeanServerDelegate]", "removeNotificationListener"; - permission javax.management.MBeanPermission "SimpleStandard#-[MBeans:type=SimpleStandard]", "unregisterMBean"; -}; diff --git a/test/jdk/javax/management/remote/mandatory/subjectDelegation/policy32 b/test/jdk/javax/management/remote/mandatory/subjectDelegation/policy32 deleted file mode 100644 index 23dcb7d762a..00000000000 --- a/test/jdk/javax/management/remote/mandatory/subjectDelegation/policy32 +++ /dev/null @@ -1,30 +0,0 @@ -grant { - permission javax.security.auth.AuthPermission "createLoginContext.JMXPluggableAuthenticator"; - permission java.net.SocketPermission "*:*", "accept,connect,listen,resolve"; - permission java.lang.RuntimePermission "*"; - permission java.security.SecurityPermission "createAccessControlContext"; -// permission javax.management.MBeanPermission "*", "getDomains"; - permission javax.management.MBeanPermission "SimpleStandard#State[MBeans:type=SimpleStandard]", "getAttribute"; - permission javax.security.auth.AuthPermission "getSubject"; - permission javax.management.MBeanPermission "SimpleStandard#State[MBeans:type=SimpleStandard]", "setAttribute"; - permission javax.management.MBeanPermission "SimpleStandard#-[MBeans:type=SimpleStandard]", "addNotificationListener"; - permission javax.management.MBeanPermission "javax.management.MBeanServerDelegate#-[JMImplementation:type=MBeanServerDelegate]", "addNotificationListener"; - permission javax.management.MBeanPermission "javax.management.MBeanServerDelegate#-[JMImplementation:type=MBeanServerDelegate]", "removeNotificationListener"; - permission javax.management.MBeanPermission "SimpleStandard#-[MBeans:type=SimpleStandard]", "unregisterMBean"; - permission javax.management.remote.SubjectDelegationPermission "javax.management.remote.JMXPrincipal.delegate"; -}; - -grant principal javax.management.remote.JMXPrincipal "monitorRole" { - permission javax.management.remote.SubjectDelegationPermission "javax.management.remote.JMXPrincipal.delegate"; -}; - -grant principal javax.management.remote.JMXPrincipal "delegate" { - permission javax.management.MBeanPermission "*", "getDomains"; - permission javax.management.MBeanPermission "SimpleStandard#State[MBeans:type=SimpleStandard]", "getAttribute"; - permission javax.security.auth.AuthPermission "getSubject"; - permission javax.management.MBeanPermission "SimpleStandard#State[MBeans:type=SimpleStandard]", "setAttribute"; - permission javax.management.MBeanPermission "SimpleStandard#-[MBeans:type=SimpleStandard]", "addNotificationListener"; - permission javax.management.MBeanPermission "javax.management.MBeanServerDelegate#-[JMImplementation:type=MBeanServerDelegate]", "addNotificationListener"; - permission javax.management.MBeanPermission "javax.management.MBeanServerDelegate#-[JMImplementation:type=MBeanServerDelegate]", "removeNotificationListener"; - permission javax.management.MBeanPermission "SimpleStandard#-[MBeans:type=SimpleStandard]", "unregisterMBean"; -}; diff --git a/test/jdk/javax/management/remote/mandatory/subjectDelegation/policy33 b/test/jdk/javax/management/remote/mandatory/subjectDelegation/policy33 deleted file mode 100644 index 67f33449476..00000000000 --- a/test/jdk/javax/management/remote/mandatory/subjectDelegation/policy33 +++ /dev/null @@ -1,30 +0,0 @@ -grant { - permission javax.security.auth.AuthPermission "createLoginContext.JMXPluggableAuthenticator"; - permission java.net.SocketPermission "*:*", "accept,connect,listen,resolve"; - permission java.lang.RuntimePermission "*"; - permission java.security.SecurityPermission "createAccessControlContext"; - permission javax.management.MBeanPermission "*", "getDomains"; - permission javax.management.MBeanPermission "SimpleStandard#State[MBeans:type=SimpleStandard]", "getAttribute"; - permission javax.security.auth.AuthPermission "getSubject"; - permission javax.management.MBeanPermission "SimpleStandard#State[MBeans:type=SimpleStandard]", "setAttribute"; - permission javax.management.MBeanPermission "SimpleStandard#-[MBeans:type=SimpleStandard]", "addNotificationListener"; - permission javax.management.MBeanPermission "javax.management.MBeanServerDelegate#-[JMImplementation:type=MBeanServerDelegate]", "addNotificationListener"; - permission javax.management.MBeanPermission "javax.management.MBeanServerDelegate#-[JMImplementation:type=MBeanServerDelegate]", "removeNotificationListener"; - permission javax.management.MBeanPermission "SimpleStandard#-[MBeans:type=SimpleStandard]", "unregisterMBean"; - permission javax.management.remote.SubjectDelegationPermission "javax.management.remote.JMXPrincipal.delegate"; -}; - -grant principal javax.management.remote.JMXPrincipal "monitorRole" { - permission javax.management.remote.SubjectDelegationPermission "javax.management.remote.JMXPrincipal.delegate"; -}; - -grant principal javax.management.remote.JMXPrincipal "delegate" { -// permission javax.management.MBeanPermission "*", "getDomains"; - permission javax.management.MBeanPermission "SimpleStandard#State[MBeans:type=SimpleStandard]", "getAttribute"; - permission javax.security.auth.AuthPermission "getSubject"; - permission javax.management.MBeanPermission "SimpleStandard#State[MBeans:type=SimpleStandard]", "setAttribute"; - permission javax.management.MBeanPermission "SimpleStandard#-[MBeans:type=SimpleStandard]", "addNotificationListener"; - permission javax.management.MBeanPermission "javax.management.MBeanServerDelegate#-[JMImplementation:type=MBeanServerDelegate]", "addNotificationListener"; - permission javax.management.MBeanPermission "javax.management.MBeanServerDelegate#-[JMImplementation:type=MBeanServerDelegate]", "removeNotificationListener"; - permission javax.management.MBeanPermission "SimpleStandard#-[MBeans:type=SimpleStandard]", "unregisterMBean"; -}; diff --git a/test/jdk/javax/management/remote/mandatory/subjectDelegation/policy34 b/test/jdk/javax/management/remote/mandatory/subjectDelegation/policy34 deleted file mode 100644 index ece5ab98cff..00000000000 --- a/test/jdk/javax/management/remote/mandatory/subjectDelegation/policy34 +++ /dev/null @@ -1,22 +0,0 @@ -grant { - permission javax.security.auth.AuthPermission "createLoginContext.JMXPluggableAuthenticator"; - permission java.lang.RuntimePermission "*"; - permission java.net.SocketPermission "*:*", "accept,connect,listen,resolve"; - permission java.security.SecurityPermission "createAccessControlContext"; - permission javax.management.remote.SubjectDelegationPermission "javax.management.remote.JMXPrincipal.monitorRole"; -}; - -grant principal javax.management.remote.JMXPrincipal "monitorRole" { - permission javax.management.remote.SubjectDelegationPermission "javax.management.remote.JMXPrincipal.delegate"; -}; - -grant principal javax.management.remote.JMXPrincipal "delegate" { - permission javax.management.MBeanPermission "*", "getDomains"; - permission javax.management.MBeanPermission "SimpleStandard#State[MBeans:type=SimpleStandard]", "getAttribute"; - permission javax.security.auth.AuthPermission "getSubject"; - permission javax.management.MBeanPermission "SimpleStandard#State[MBeans:type=SimpleStandard]", "setAttribute"; - permission javax.management.MBeanPermission "SimpleStandard#-[MBeans:type=SimpleStandard]", "addNotificationListener"; - permission javax.management.MBeanPermission "javax.management.MBeanServerDelegate#-[JMImplementation:type=MBeanServerDelegate]", "addNotificationListener"; - permission javax.management.MBeanPermission "javax.management.MBeanServerDelegate#-[JMImplementation:type=MBeanServerDelegate]", "removeNotificationListener"; - permission javax.management.MBeanPermission "SimpleStandard#-[MBeans:type=SimpleStandard]", "unregisterMBean"; -}; diff --git a/test/jdk/javax/management/remote/mandatory/subjectDelegation/policy35 b/test/jdk/javax/management/remote/mandatory/subjectDelegation/policy35 deleted file mode 100644 index 0c0dcd39811..00000000000 --- a/test/jdk/javax/management/remote/mandatory/subjectDelegation/policy35 +++ /dev/null @@ -1,22 +0,0 @@ -grant { - permission javax.security.auth.AuthPermission "createLoginContext.JMXPluggableAuthenticator"; - permission java.lang.RuntimePermission "*"; - permission java.net.SocketPermission "*:*", "accept,connect,listen,resolve"; - permission java.security.SecurityPermission "createAccessControlContext"; - permission javax.management.remote.SubjectDelegationPermission "javax.management.remote.JMXPrincipal.monitorRole"; -}; - -grant principal javax.management.remote.JMXPrincipal "monitorRole" { - permission javax.management.remote.SubjectDelegationPermission "javax.management.remote.JMXPrincipal.delegate"; -}; - -grant principal javax.management.remote.JMXPrincipal "delegate" { -// permission javax.management.MBeanPermission "*", "getDomains"; - permission javax.management.MBeanPermission "SimpleStandard#State[MBeans:type=SimpleStandard]", "getAttribute"; - permission javax.security.auth.AuthPermission "getSubject"; - permission javax.management.MBeanPermission "SimpleStandard#State[MBeans:type=SimpleStandard]", "setAttribute"; - permission javax.management.MBeanPermission "SimpleStandard#-[MBeans:type=SimpleStandard]", "addNotificationListener"; - permission javax.management.MBeanPermission "javax.management.MBeanServerDelegate#-[JMImplementation:type=MBeanServerDelegate]", "addNotificationListener"; - permission javax.management.MBeanPermission "javax.management.MBeanServerDelegate#-[JMImplementation:type=MBeanServerDelegate]", "removeNotificationListener"; - permission javax.management.MBeanPermission "SimpleStandard#-[MBeans:type=SimpleStandard]", "unregisterMBean"; -}; diff --git a/test/jdk/javax/swing/JFileChooser/FileSystemView/Win32FolderSort.java b/test/jdk/javax/swing/JFileChooser/FileSystemView/Win32FolderSort.java new file mode 100644 index 00000000000..7ed5e0f1705 --- /dev/null +++ b/test/jdk/javax/swing/JFileChooser/FileSystemView/Win32FolderSort.java @@ -0,0 +1,158 @@ +/* + * 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.File; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +/* + * @test + * @bug 8305072 + * @requires (os.family == "windows") + * @modules java.desktop/sun.awt.shell + * @summary Verifies consistency of Win32ShellFolder2.compareTo + * @run main/othervm --add-opens java.desktop/sun.awt.shell=ALL-UNNAMED Win32FolderSort + */ +public class Win32FolderSort { + public static void main(String[] args) throws Exception { + Class folderManager = Class.forName("sun.awt.shell.Win32ShellFolderManager2"); + Class folder = Class.forName("sun.awt.shell.Win32ShellFolder2"); + + Method getDesktop = folderManager.getDeclaredMethod("getDesktop"); + getDesktop.setAccessible(true); + Method getPersonal = folderManager.getDeclaredMethod("getPersonal"); + getPersonal.setAccessible(true); + + Method createShellFolder = folderManager.getDeclaredMethod("createShellFolder", folder, File.class); + createShellFolder.setAccessible(true); + + Method isFileSystem = folder.getMethod("isFileSystem"); + isFileSystem.setAccessible(true); + Method isSpecial = folder.getMethod("isSpecial"); + isSpecial.setAccessible(true); + Method getChildByPath = folder.getDeclaredMethod("getChildByPath", String.class); + getChildByPath.setAccessible(true); + + File desktop = (File) getDesktop.invoke(null); + File personal = (File) getPersonal.invoke(null); + if (!((Boolean) isSpecial.invoke(personal))) { + throw new RuntimeException("personal is not special"); + } + File fakePersonal = (File) getChildByPath.invoke(desktop, personal.getPath()); + if (fakePersonal == null) { + fakePersonal = (File) createShellFolder.invoke(null, desktop, + new File(personal.getPath())); + } + if ((Boolean) isSpecial.invoke(fakePersonal)) { + throw new RuntimeException("fakePersonal is special"); + } + File homeDir = (File) createShellFolder.invoke(null, desktop, + new File(System.getProperty("user.home"))); + + File[] files = {fakePersonal, personal, homeDir}; + for (File f : files) { + if (!((Boolean) isFileSystem.invoke(f))) { + throw new RuntimeException(f + " is not on file system"); + } + } + + List errors = new ArrayList<>(2); + for (File f1 : files) { + for (File f2 : files) { + for (File f3 : files) { + String result = verifyCompareTo(f1, f2, f3); + if (result != null) { + String error = result + "\nwhere" + + "\n a = " + formatFile(f1, isSpecial) + + "\n b = " + formatFile(f2, isSpecial) + + "\n c = " + formatFile(f3, isSpecial); + errors.add(error); + } + } + } + } + + + System.out.println("Unsorted:"); + for (File f : files) { + System.out.println(formatFile(f, isSpecial)); + } + System.out.println(); + + Arrays.sort(files); + System.out.println("Sorted:"); + for (File f : files) { + System.out.println(formatFile(f, isSpecial)); + } + + + if (!errors.isEmpty()) { + System.err.println("Implementation of Win32ShellFolder2.compareTo is inconsistent:"); + errors.forEach(System.err::println); + throw new RuntimeException("Inconsistencies found: " + errors.size() + + " - " + errors.get(0)); + } + } + + /** + * Verifies consistency of {@code Comparable} implementation. + * + * @param a the first object + * @param b the second object + * @param c the third object + * @return error message if inconsistency is found, + * or {@code null } otherwise + */ + private static String verifyCompareTo(File a, File b, File c) { + // a < b & b < c => a < c + if (a.compareTo(b) < 0 && b.compareTo(c) < 0) { + if (a.compareTo(c) >= 0) { + return "a < b & b < c but a >= c"; + } + } + + // a > b & b > c => a > c + if (a.compareTo(b) > 0 && b.compareTo(c) > 0) { + if (a.compareTo(c) <= 0) { + return "a > b & b > c but a <= c"; + } + } + + // a = b & b = c => a = c + if (a.compareTo(b) == 0 && b.compareTo(c) == 0) { + if (a.compareTo(c) != 0) { + return "a = b & b = c but a != c"; + } + } + + return null; + } + + private static String formatFile(File f, Method isSpecial) + throws InvocationTargetException, IllegalAccessException { + return f + "(" + isSpecial.invoke(f) + ")"; + } +} diff --git a/test/jdk/javax/swing/plaf/basic/BasicDirectoryModel/ConcurrentModification.java b/test/jdk/javax/swing/plaf/basic/BasicDirectoryModel/ConcurrentModification.java new file mode 100644 index 00000000000..0c23ee23b5b --- /dev/null +++ b/test/jdk/javax/swing/plaf/basic/BasicDirectoryModel/ConcurrentModification.java @@ -0,0 +1,273 @@ +/* + * 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.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.ArrayList; +import java.util.List; +import java.util.Timer; +import java.util.TimerTask; +import java.util.concurrent.BrokenBarrierException; +import java.util.concurrent.CyclicBarrier; +import java.util.concurrent.atomic.AtomicReference; +import java.util.stream.IntStream; +import java.util.stream.LongStream; + +import javax.swing.JFileChooser; + +/* + * @test + * @bug 8323670 8307091 8240690 + * @requires os.family == "mac" | os.family == "linux" + * @summary Verifies thread-safety of BasicDirectoryModel (JFileChooser) + * @run main/othervm -Djava.awt.headless=true ConcurrentModification + */ +public final class ConcurrentModification extends ThreadGroup { + /** Initial number of files. */ + private static final long NUMBER_OF_FILES = 50; + /** Maximum number of files created on a timer tick. */ + private static final long LIMIT_FILES = 10; + + /** Timer period (delay) for creating new files. */ + private static final long TIMER_PERIOD = 250; + + /** + * Number of threads running {@code fileChooser.rescanCurrentDirectory()}. + */ + private static final int NUMBER_OF_THREADS = 5; + /** Number of repeated calls to {@code rescanCurrentDirectory}. */ + private static final int NUMBER_OF_REPEATS = 2_000; + /** Maximum amount a thread waits before initiating rescan. */ + private static final long LIMIT_SLEEP = 100; + + + /** The barrier to start all the scanner threads simultaneously. */ + private static final CyclicBarrier start = new CyclicBarrier(NUMBER_OF_THREADS); + /** The barrier to wait for all the scanner threads to complete, plus main thread. */ + private static final CyclicBarrier end = new CyclicBarrier(NUMBER_OF_THREADS + 1); + + /** List of scanner threads. */ + private static final List threads = new ArrayList<>(NUMBER_OF_THREADS); + + /** + * Stores an exception caught by any of the threads. + * If more exceptions are caught, they're added as suppressed exceptions. + */ + private static final AtomicReference exception = + new AtomicReference<>(); + + /** + * Stores an {@code IOException} thrown while removing the files. + */ + private static final AtomicReference ioException = + new AtomicReference<>(); + + + public static void main(String[] args) throws Throwable { + try { + // Start the test in its own thread group to catch and handle + // all thrown exceptions, in particular in + // BasicDirectoryModel.FilesLoader which is created by Swing. + ThreadGroup threadGroup = new ConcurrentModification(); + Thread runner = new Thread(threadGroup, + ConcurrentModification::wrapper, + "Test Runner"); + runner.start(); + runner.join(); + } catch (Throwable throwable) { + handleException(throwable); + } + + if (ioException.get() != null) { + System.err.println("An error occurred while removing files:"); + ioException.get().printStackTrace(); + } + + if (exception.get() != null) { + throw exception.get(); + } + } + + private static void wrapper() { + final long timeStart = System.currentTimeMillis(); + try { + runTest(timeStart); + } catch (Throwable throwable) { + handleException(throwable); + } finally { + System.out.printf("Duration: %,d\n", + (System.currentTimeMillis() - timeStart)); + } + } + + private static void runTest(final long timeStart) throws Throwable { + final Path temp = Files.createDirectory(Paths.get("fileChooser-concurrency-" + timeStart)); + + final Timer timer = new Timer("File creator"); + + try { + createFiles(temp); + + final JFileChooser fc = new JFileChooser(temp.toFile()); + + IntStream.range(0, NUMBER_OF_THREADS) + .forEach(i -> { + Thread thread = new Thread(new Scanner(fc)); + threads.add(thread); + thread.start(); + }); + + timer.scheduleAtFixedRate(new CreateFilesTimerTask(temp), + 0, TIMER_PERIOD); + + end.await(); + } catch (Throwable e) { + threads.forEach(Thread::interrupt); + throw e; + } finally { + timer.cancel(); + + deleteFiles(temp); + deleteFile(temp); + } + } + + + private ConcurrentModification() { + super("bdmConcurrency"); + } + + @Override + public void uncaughtException(Thread t, Throwable e) { + handleException(t, e); + } + + private static void handleException(Throwable throwable) { + handleException(Thread.currentThread(), throwable); + } + + private static void handleException(final Thread thread, + final Throwable throwable) { + System.err.println("Exception in " + thread.getName() + ": " + + throwable.getClass() + + (throwable.getMessage() != null + ? ": " + throwable.getMessage() + : "")); + if (!exception.compareAndSet(null, throwable)) { + exception.get().addSuppressed(throwable); + } + threads.stream() + .filter(t -> t != thread) + .forEach(Thread::interrupt); + } + + + private record Scanner(JFileChooser fileChooser) + implements Runnable { + + @Override + public void run() { + try { + start.await(); + + int counter = 0; + try { + do { + fileChooser.rescanCurrentDirectory(); + Thread.sleep((long) (Math.random() * LIMIT_SLEEP)); + } while (++counter < NUMBER_OF_REPEATS + && !Thread.interrupted()); + } catch (InterruptedException e) { + // Just exit the loop + } + } catch (Throwable throwable) { + handleException(throwable); + } finally { + try { + end.await(); + } catch (InterruptedException | BrokenBarrierException e) { + handleException(e); + } + } + } + } + + private static void createFiles(final Path parent) { + createFiles(parent, 0, NUMBER_OF_FILES); + } + + private static void createFiles(final Path parent, + final long start, + final long end) { + LongStream.range(start, end) + .forEach(n -> createFile(parent.resolve(n + ".file"))); + } + + private static void createFile(final Path file) { + try { + Files.createFile(file); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + private static void deleteFiles(final Path parent) throws IOException { + try (var stream = Files.walk(parent)) { + stream.filter(p -> p != parent) + .forEach(ConcurrentModification::deleteFile); + } + } + + private static void deleteFile(final Path file) { + try { + Files.delete(file); + } catch (IOException e) { + if (!ioException.compareAndSet(null, e)) { + ioException.get().addSuppressed(e); + } + } + } + + private static final class CreateFilesTimerTask extends TimerTask { + private final Path temp; + private long no; + + public CreateFilesTimerTask(Path temp) { + this.temp = temp; + no = NUMBER_OF_FILES; + } + + @Override + public void run() { + try { + long count = (long) (Math.random() * LIMIT_FILES); + createFiles(temp, no, no + count); + no += count; + } catch (Throwable t) { + handleException(t); + } + } + } +} diff --git a/test/jdk/jdk/classfile/ClassPrinterTest.java b/test/jdk/jdk/classfile/ClassPrinterTest.java index b75beee4f88..6400dc4f5df 100644 --- a/test/jdk/jdk/classfile/ClassPrinterTest.java +++ b/test/jdk/jdk/classfile/ClassPrinterTest.java @@ -35,6 +35,9 @@ import java.lang.classfile.*; import java.lang.classfile.attribute.*; import java.lang.classfile.components.ClassPrinter; +import java.lang.constant.DirectMethodHandleDesc; +import java.lang.constant.DynamicCallSiteDesc; +import java.lang.constant.MethodHandleDesc; import org.junit.jupiter.api.Test; import static org.junit.jupiter.api.Assertions.*; @@ -98,6 +101,12 @@ ClassModel getClassModel() { TypeAnnotation.of(TypeAnnotation.TargetInfo.ofField(), List.of(TypeAnnotation.TypePathComponent.WILDCARD), ClassDesc.of("Boo"), List.of()))); + tryb.invokedynamic(DynamicCallSiteDesc.of( + MethodHandleDesc.ofMethod(DirectMethodHandleDesc.Kind.STATIC, ClassDesc.of("Phoo"), "phee", MethodTypeDesc.of(ClassDesc.of("Boo"))), + "intfMethod", + MethodTypeDesc.of(ClassDesc.of("Boo")), + "bootstrap argument 1", + "bootstrap argument 2")); tryb.return_(); }, catchb -> catchb.catching(ClassDesc.of("Phee"), cb -> { cb.lineNumber(4); @@ -121,7 +130,7 @@ - class name: Foo flags: [PUBLIC] superclass: Boo interfaces: [Phee, Phoo] - attributes: [SourceFile, InnerClasses, EnclosingMethod, Synthetic, Signature, Deprecated, NestHost, NestMembers, Record, RuntimeInvisibleAnnotations, PermittedSubclasses] + attributes: [SourceFile, InnerClasses, EnclosingMethod, Synthetic, Signature, Deprecated, NestHost, NestMembers, Record, RuntimeInvisibleAnnotations, PermittedSubclasses, BootstrapMethods] constant pool: 1: {tag: Utf8, value: Foo} 2: {tag: Class, class name index: 1, class internal name: Foo} @@ -133,68 +142,81 @@ - class name: Foo 8: {tag: Utf8, value: (ZLjava/lang/Throwable;)Ljava/lang/Void;} 9: {tag: Utf8, value: variable} 10: {tag: Utf8, value: LPhoo;} - 11: {tag: Utf8, value: Phee} - 12: {tag: Class, class name index: 11, class internal name: Phee} - 13: {tag: Utf8, value: Phoo} - 14: {tag: Class, class name index: 13, class internal name: Phoo} - 15: {tag: Utf8, value: RuntimeVisibleAnnotations} - 16: {tag: Utf8, value: flfl} - 17: {tag: Float, value: 0.0} - 18: {tag: Utf8, value: frfl} - 19: {tag: Float, value: 1.0} - 20: {tag: Utf8, value: AnnotationDefault} - 21: {tag: Integer, value: 1} - 22: {tag: Integer, value: 12} - 23: {tag: Integer, value: 99} - 24: {tag: Utf8, value: LPhee;} - 25: {tag: Double, value: 1.3} - 27: {tag: Utf8, value: LBoo;} - 28: {tag: Utf8, value: BOO} - 29: {tag: Float, value: 3.7} - 30: {tag: Integer, value: 33} - 31: {tag: Long, value: 3333} - 33: {tag: Integer, value: 25} - 34: {tag: Utf8, value: param} - 35: {tag: Integer, value: 3} - 36: {tag: Utf8, value: RuntimeVisibleParameterAnnotations} - 37: {tag: Float, value: 22.0} - 38: {tag: Float, value: 11.0} - 39: {tag: Utf8, value: RuntimeInvisibleParameterAnnotations} - 40: {tag: Float, value: '-22.0'} - 41: {tag: Float, value: '-11.0'} - 42: {tag: Utf8, value: Exceptions} - 43: {tag: Utf8, value: Bee} - 44: {tag: Class, class name index: 43, class internal name: Bee} - 45: {tag: Utf8, value: Code} - 46: {tag: Utf8, value: RuntimeInvisibleTypeAnnotations} - 47: {tag: Utf8, value: RuntimeVisibleTypeAnnotations} - 48: {tag: Utf8, value: LFee;} - 49: {tag: Utf8, value: yes} - 50: {tag: Integer, value: 0} - 51: {tag: Utf8, value: LocalVariableTable} - 52: {tag: Utf8, value: LocalVariableTypeTable} - 53: {tag: Utf8, value: LineNumberTable} - 54: {tag: Utf8, value: StackMapTable} - 55: {tag: Utf8, value: SourceFile} - 56: {tag: Utf8, value: Foo.java} - 57: {tag: Utf8, value: InnerClasses} - 58: {tag: Utf8, value: InnerName} - 59: {tag: Utf8, value: EnclosingMethod} - 60: {tag: Utf8, value: enclosingMethod} - 61: {tag: Utf8, value: (Ljava/util/Collection;)Ljava/lang/Double;} - 62: {tag: NameAndType, name index: 60, type index: 61, name: enclosingMethod, type: (Ljava/util/Collection;)Ljava/lang/Double;} - 63: {tag: Utf8, value: Synthetic} - 64: {tag: Utf8, value: Signature} - 65: {tag: Utf8, value: LBoo;LPhee;LPhoo;} - 66: {tag: Utf8, value: Deprecated} - 67: {tag: Utf8, value: NestHost} - 68: {tag: Utf8, value: NestMembers} - 69: {tag: Utf8, value: Record} - 70: {tag: Utf8, value: fee} - 71: {tag: Utf8, value: RuntimeInvisibleAnnotations} - 72: {tag: Float, value: 2.0} - 73: {tag: Float, value: 3.0} - 74: {tag: Utf8, value: PermittedSubclasses} + 11: {tag: Utf8, value: Phoo} + 12: {tag: Class, class name index: 11, class internal name: Phoo} + 13: {tag: Utf8, value: phee} + 14: {tag: Utf8, value: ()LBoo;} + 15: {tag: NameAndType, name index: 13, type index: 14, name: phee, type: ()LBoo;} + 16: {tag: Methodref, owner index: 12, name and type index: 15, owner: Phoo, name: phee, type: ()LBoo;} + 17: {tag: MethodHandle, reference kind: STATIC, reference index: 16, owner: Phoo, name: phee, type: ()LBoo;} + 18: {tag: Utf8, value: bootstrap argument 1} + 19: {tag: String, value index: 18, value: bootstrap argument 1} + 20: {tag: Utf8, value: bootstrap argument 2} + 21: {tag: String, value index: 20, value: bootstrap argument 2} + 22: {tag: Utf8, value: intfMethod} + 23: {tag: NameAndType, name index: 22, type index: 14, name: intfMethod, type: ()LBoo;} + 24: {tag: InvokeDynamic, bootstrap method handle index: 17, bootstrap method arguments indexes: [19, 21], name and type index: 23, name: intfMethod, type: ()LBoo;} + 25: {tag: Utf8, value: Phee} + 26: {tag: Class, class name index: 25, class internal name: Phee} + 27: {tag: Utf8, value: RuntimeVisibleAnnotations} + 28: {tag: Utf8, value: flfl} + 29: {tag: Float, value: 0.0} + 30: {tag: Utf8, value: frfl} + 31: {tag: Float, value: 1.0} + 32: {tag: Utf8, value: AnnotationDefault} + 33: {tag: Integer, value: 1} + 34: {tag: Integer, value: 12} + 35: {tag: Integer, value: 99} + 36: {tag: Utf8, value: LPhee;} + 37: {tag: Double, value: 1.3} + 39: {tag: Utf8, value: LBoo;} + 40: {tag: Utf8, value: BOO} + 41: {tag: Float, value: 3.7} + 42: {tag: Integer, value: 33} + 43: {tag: Long, value: 3333} + 45: {tag: Integer, value: 25} + 46: {tag: Utf8, value: param} + 47: {tag: Integer, value: 3} + 48: {tag: Utf8, value: RuntimeVisibleParameterAnnotations} + 49: {tag: Float, value: 22.0} + 50: {tag: Float, value: 11.0} + 51: {tag: Utf8, value: RuntimeInvisibleParameterAnnotations} + 52: {tag: Float, value: '-22.0'} + 53: {tag: Float, value: '-11.0'} + 54: {tag: Utf8, value: Exceptions} + 55: {tag: Utf8, value: Bee} + 56: {tag: Class, class name index: 55, class internal name: Bee} + 57: {tag: Utf8, value: Code} + 58: {tag: Utf8, value: RuntimeInvisibleTypeAnnotations} + 59: {tag: Utf8, value: RuntimeVisibleTypeAnnotations} + 60: {tag: Utf8, value: LFee;} + 61: {tag: Utf8, value: yes} + 62: {tag: Integer, value: 0} + 63: {tag: Utf8, value: LocalVariableTable} + 64: {tag: Utf8, value: LocalVariableTypeTable} + 65: {tag: Utf8, value: LineNumberTable} + 66: {tag: Utf8, value: StackMapTable} + 67: {tag: Utf8, value: SourceFile} + 68: {tag: Utf8, value: Foo.java} + 69: {tag: Utf8, value: InnerClasses} + 70: {tag: Utf8, value: InnerName} + 71: {tag: Utf8, value: EnclosingMethod} + 72: {tag: Utf8, value: enclosingMethod} + 73: {tag: Utf8, value: (Ljava/util/Collection;)Ljava/lang/Double;} + 74: {tag: NameAndType, name index: 72, type index: 73, name: enclosingMethod, type: (Ljava/util/Collection;)Ljava/lang/Double;} + 75: {tag: Utf8, value: Synthetic} + 76: {tag: Utf8, value: Signature} + 77: {tag: Utf8, value: LBoo;LPhee;LPhoo;} + 78: {tag: Utf8, value: Deprecated} + 79: {tag: Utf8, value: NestHost} + 80: {tag: Utf8, value: NestMembers} + 81: {tag: Utf8, value: Record} + 82: {tag: Utf8, value: fee} + 83: {tag: Utf8, value: RuntimeInvisibleAnnotations} + 84: {tag: Float, value: 2.0} + 85: {tag: Float, value: 3.0} + 86: {tag: Utf8, value: PermittedSubclasses} + 87: {tag: Utf8, value: BootstrapMethods} source file: Foo.java inner classes: - {inner class: Phee, outer class: Phoo, inner name: InnerName, flags: [PROTECTED]} @@ -213,6 +235,8 @@ record components: invisible annotations: - {annotation class: LPhoo;, values: [{name: flfl, value: {float: 2.0}}, {name: frfl, value: {float: 3.0}}]} permitted subclasses: [Boo, Phoo] + bootstrap methods: + - {index: 0, kind: STATIC, owner: Phoo, name: phee, args: [bootstrap argument 1, bootstrap argument 2]} fields: - field name: f flags: [PRIVATE] @@ -236,35 +260,36 @@ record components: max locals: 3 attributes: [RuntimeInvisibleTypeAnnotations, RuntimeVisibleTypeAnnotations, LocalVariableTable, LocalVariableTypeTable, LineNumberTable, StackMapTable] local variables: - - {start: 0, end: 7, slot: 2, name: variable, type: LPhoo;} + - {start: 0, end: 12, slot: 2, name: variable, type: LPhoo;} local variable types: - - {start: 0, end: 7, slot: 2, name: variable, signature: LPhoo;} + - {start: 0, end: 12, slot: 2, name: variable, signature: LPhoo;} line numbers: - {start: 0, line number: 1} - {start: 1, line number: 2} - {start: 6, line number: 3} - - {start: 7, line number: 4} + - {start: 12, line number: 4} stack map frames: 6: {locals: [Foo, int, java/lang/Throwable], stack: []} - 7: {locals: [Foo, int, java/lang/Throwable], stack: [Phee]} + 12: {locals: [Foo, int, java/lang/Throwable], stack: [Phee]} invisible type annotations: - {annotation class: LBoo;, target info: FIELD, values: []} visible type annotations: - {annotation class: LFee;, target info: FIELD, values: [{name: yes, value: {boolean: false}}]} //stack map frame @0: {locals: [Foo, int, java/lang/Throwable], stack: []} - //try block 1 start: {start: 0, end: 7, handler: 7, catch type: Phee} + //try block 1 start: {start: 0, end: 12, handler: 12, catch type: Phee} 0: {opcode: ILOAD_1, slot: 1} 1: {opcode: IFEQ, target: 6} 4: {opcode: ALOAD_2, slot: 2, type: LPhoo;, variable name: variable} 5: {opcode: ATHROW} //stack map frame @6: {locals: [Foo, int, java/lang/Throwable], stack: []} - 6: {opcode: RETURN} - //stack map frame @7: {locals: [Foo, int, java/lang/Throwable], stack: [Phee]} - //try block 1 end: {start: 0, end: 7, handler: 7, catch type: Phee} - //exception handler 1 start: {start: 0, end: 7, handler: 7, catch type: Phee} - 7: {opcode: ATHROW} + 6: {opcode: INVOKEDYNAMIC, name: intfMethod, descriptor: ()LBoo;, bootstrap method: STATIC Phoo::phee, arguments: [bootstrap argument 1, bootstrap argument 2]} + 11: {opcode: RETURN} + //stack map frame @12: {locals: [Foo, int, java/lang/Throwable], stack: [Phee]} + //try block 1 end: {start: 0, end: 12, handler: 12, catch type: Phee} + //exception handler 1 start: {start: 0, end: 12, handler: 12, catch type: Phee} + 12: {opcode: ATHROW} exception handlers: - handler 1: {start: 0, end: 7, handler: 7, type: Phee} + handler 1: {start: 0, end: 12, handler: 12, type: Phee} """); } @@ -279,10 +304,12 @@ - class name: Foo flags: [PUBLIC] superclass: Boo interfaces: [Phee, Phoo] - attributes: [SourceFile, InnerClasses, EnclosingMethod, Synthetic, Signature, Deprecated, NestHost, NestMembers, Record, RuntimeInvisibleAnnotations, PermittedSubclasses] + attributes: [SourceFile, InnerClasses, EnclosingMethod, Synthetic, Signature, Deprecated, NestHost, NestMembers, Record, RuntimeInvisibleAnnotations, PermittedSubclasses, BootstrapMethods] nest host: Phee nest members: [Phoo, Boo, Bee] permitted subclasses: [Boo, Phoo] + bootstrap methods: + - {index: 0, kind: STATIC, owner: Phoo, name: phee, args: [bootstrap argument 1, bootstrap argument 2]} fields: - field name: f flags: [PRIVATE] @@ -299,21 +326,22 @@ - class name: Foo attributes: [RuntimeInvisibleTypeAnnotations, RuntimeVisibleTypeAnnotations, LocalVariableTable, LocalVariableTypeTable, LineNumberTable, StackMapTable] stack map frames: 6: {locals: [Foo, int, java/lang/Throwable], stack: []} - 7: {locals: [Foo, int, java/lang/Throwable], stack: [Phee]} + 12: {locals: [Foo, int, java/lang/Throwable], stack: [Phee]} //stack map frame @0: {locals: [Foo, int, java/lang/Throwable], stack: []} - //try block 1 start: {start: 0, end: 7, handler: 7, catch type: Phee} + //try block 1 start: {start: 0, end: 12, handler: 12, catch type: Phee} 0: {opcode: ILOAD_1, slot: 1} 1: {opcode: IFEQ, target: 6} 4: {opcode: ALOAD_2, slot: 2} 5: {opcode: ATHROW} //stack map frame @6: {locals: [Foo, int, java/lang/Throwable], stack: []} - 6: {opcode: RETURN} - //stack map frame @7: {locals: [Foo, int, java/lang/Throwable], stack: [Phee]} - //try block 1 end: {start: 0, end: 7, handler: 7, catch type: Phee} - //exception handler 1 start: {start: 0, end: 7, handler: 7, catch type: Phee} - 7: {opcode: ATHROW} + 6: {opcode: INVOKEDYNAMIC, name: intfMethod, descriptor: ()LBoo;, bootstrap method: STATIC Phoo::phee, arguments: [bootstrap argument 1, bootstrap argument 2]} + 11: {opcode: RETURN} + //stack map frame @12: {locals: [Foo, int, java/lang/Throwable], stack: [Phee]} + //try block 1 end: {start: 0, end: 12, handler: 12, catch type: Phee} + //exception handler 1 start: {start: 0, end: 12, handler: 12, catch type: Phee} + 12: {opcode: ATHROW} exception handlers: - handler 1: {start: 0, end: 7, handler: 7, type: Phee} + handler 1: {start: 0, end: 12, handler: 12, type: Phee} """); } @@ -328,7 +356,7 @@ - class name: Foo flags: [PUBLIC] superclass: Boo interfaces: [Phee, Phoo] - attributes: [SourceFile, InnerClasses, EnclosingMethod, Synthetic, Signature, Deprecated, NestHost, NestMembers, Record, RuntimeInvisibleAnnotations, PermittedSubclasses] + attributes: [SourceFile, InnerClasses, EnclosingMethod, Synthetic, Signature, Deprecated, NestHost, NestMembers, Record, RuntimeInvisibleAnnotations, PermittedSubclasses, BootstrapMethods] fields: - field name: f flags: [PRIVATE] @@ -353,7 +381,7 @@ void testPrintJsonTraceAll() throws IOException { "flags": ["PUBLIC"], "superclass": "Boo", "interfaces": ["Phee", "Phoo"], - "attributes": ["SourceFile", "InnerClasses", "EnclosingMethod", "Synthetic", "Signature", "Deprecated", "NestHost", "NestMembers", "Record", "RuntimeInvisibleAnnotations", "PermittedSubclasses"], + "attributes": ["SourceFile", "InnerClasses", "EnclosingMethod", "Synthetic", "Signature", "Deprecated", "NestHost", "NestMembers", "Record", "RuntimeInvisibleAnnotations", "PermittedSubclasses", "BootstrapMethods"], "constant pool": { "1": {"tag": "Utf8", "value": "Foo"}, "2": {"tag": "Class", "class name index": 1, "class internal name": "Foo"}, @@ -365,68 +393,81 @@ void testPrintJsonTraceAll() throws IOException { "8": {"tag": "Utf8", "value": "(ZLjava/lang/Throwable;)Ljava/lang/Void;"}, "9": {"tag": "Utf8", "value": "variable"}, "10": {"tag": "Utf8", "value": "LPhoo;"}, - "11": {"tag": "Utf8", "value": "Phee"}, - "12": {"tag": "Class", "class name index": 11, "class internal name": "Phee"}, - "13": {"tag": "Utf8", "value": "Phoo"}, - "14": {"tag": "Class", "class name index": 13, "class internal name": "Phoo"}, - "15": {"tag": "Utf8", "value": "RuntimeVisibleAnnotations"}, - "16": {"tag": "Utf8", "value": "flfl"}, - "17": {"tag": "Float", "value": "0.0"}, - "18": {"tag": "Utf8", "value": "frfl"}, - "19": {"tag": "Float", "value": "1.0"}, - "20": {"tag": "Utf8", "value": "AnnotationDefault"}, - "21": {"tag": "Integer", "value": "1"}, - "22": {"tag": "Integer", "value": "12"}, - "23": {"tag": "Integer", "value": "99"}, - "24": {"tag": "Utf8", "value": "LPhee;"}, - "25": {"tag": "Double", "value": "1.3"}, - "27": {"tag": "Utf8", "value": "LBoo;"}, - "28": {"tag": "Utf8", "value": "BOO"}, - "29": {"tag": "Float", "value": "3.7"}, - "30": {"tag": "Integer", "value": "33"}, - "31": {"tag": "Long", "value": "3333"}, - "33": {"tag": "Integer", "value": "25"}, - "34": {"tag": "Utf8", "value": "param"}, - "35": {"tag": "Integer", "value": "3"}, - "36": {"tag": "Utf8", "value": "RuntimeVisibleParameterAnnotations"}, - "37": {"tag": "Float", "value": "22.0"}, - "38": {"tag": "Float", "value": "11.0"}, - "39": {"tag": "Utf8", "value": "RuntimeInvisibleParameterAnnotations"}, - "40": {"tag": "Float", "value": "-22.0"}, - "41": {"tag": "Float", "value": "-11.0"}, - "42": {"tag": "Utf8", "value": "Exceptions"}, - "43": {"tag": "Utf8", "value": "Bee"}, - "44": {"tag": "Class", "class name index": 43, "class internal name": "Bee"}, - "45": {"tag": "Utf8", "value": "Code"}, - "46": {"tag": "Utf8", "value": "RuntimeInvisibleTypeAnnotations"}, - "47": {"tag": "Utf8", "value": "RuntimeVisibleTypeAnnotations"}, - "48": {"tag": "Utf8", "value": "LFee;"}, - "49": {"tag": "Utf8", "value": "yes"}, - "50": {"tag": "Integer", "value": "0"}, - "51": {"tag": "Utf8", "value": "LocalVariableTable"}, - "52": {"tag": "Utf8", "value": "LocalVariableTypeTable"}, - "53": {"tag": "Utf8", "value": "LineNumberTable"}, - "54": {"tag": "Utf8", "value": "StackMapTable"}, - "55": {"tag": "Utf8", "value": "SourceFile"}, - "56": {"tag": "Utf8", "value": "Foo.java"}, - "57": {"tag": "Utf8", "value": "InnerClasses"}, - "58": {"tag": "Utf8", "value": "InnerName"}, - "59": {"tag": "Utf8", "value": "EnclosingMethod"}, - "60": {"tag": "Utf8", "value": "enclosingMethod"}, - "61": {"tag": "Utf8", "value": "(Ljava/util/Collection;)Ljava/lang/Double;"}, - "62": {"tag": "NameAndType", "name index": 60, "type index": 61, "name": "enclosingMethod", "type": "(Ljava/util/Collection;)Ljava/lang/Double;"}, - "63": {"tag": "Utf8", "value": "Synthetic"}, - "64": {"tag": "Utf8", "value": "Signature"}, - "65": {"tag": "Utf8", "value": "LBoo;LPhee;LPhoo;"}, - "66": {"tag": "Utf8", "value": "Deprecated"}, - "67": {"tag": "Utf8", "value": "NestHost"}, - "68": {"tag": "Utf8", "value": "NestMembers"}, - "69": {"tag": "Utf8", "value": "Record"}, - "70": {"tag": "Utf8", "value": "fee"}, - "71": {"tag": "Utf8", "value": "RuntimeInvisibleAnnotations"}, - "72": {"tag": "Float", "value": "2.0"}, - "73": {"tag": "Float", "value": "3.0"}, - "74": {"tag": "Utf8", "value": "PermittedSubclasses"}}, + "11": {"tag": "Utf8", "value": "Phoo"}, + "12": {"tag": "Class", "class name index": 11, "class internal name": "Phoo"}, + "13": {"tag": "Utf8", "value": "phee"}, + "14": {"tag": "Utf8", "value": "()LBoo;"}, + "15": {"tag": "NameAndType", "name index": 13, "type index": 14, "name": "phee", "type": "()LBoo;"}, + "16": {"tag": "Methodref", "owner index": 12, "name and type index": 15, "owner": "Phoo", "name": "phee", "type": "()LBoo;"}, + "17": {"tag": "MethodHandle", "reference kind": "STATIC", "reference index": 16, "owner": "Phoo", "name": "phee", "type": "()LBoo;"}, + "18": {"tag": "Utf8", "value": "bootstrap argument 1"}, + "19": {"tag": "String", "value index": 18, "value": "bootstrap argument 1"}, + "20": {"tag": "Utf8", "value": "bootstrap argument 2"}, + "21": {"tag": "String", "value index": 20, "value": "bootstrap argument 2"}, + "22": {"tag": "Utf8", "value": "intfMethod"}, + "23": {"tag": "NameAndType", "name index": 22, "type index": 14, "name": "intfMethod", "type": "()LBoo;"}, + "24": {"tag": "InvokeDynamic", "bootstrap method handle index": 17, "bootstrap method arguments indexes": [19, 21], "name and type index": 23, "name": "intfMethod", "type": "()LBoo;"}, + "25": {"tag": "Utf8", "value": "Phee"}, + "26": {"tag": "Class", "class name index": 25, "class internal name": "Phee"}, + "27": {"tag": "Utf8", "value": "RuntimeVisibleAnnotations"}, + "28": {"tag": "Utf8", "value": "flfl"}, + "29": {"tag": "Float", "value": "0.0"}, + "30": {"tag": "Utf8", "value": "frfl"}, + "31": {"tag": "Float", "value": "1.0"}, + "32": {"tag": "Utf8", "value": "AnnotationDefault"}, + "33": {"tag": "Integer", "value": "1"}, + "34": {"tag": "Integer", "value": "12"}, + "35": {"tag": "Integer", "value": "99"}, + "36": {"tag": "Utf8", "value": "LPhee;"}, + "37": {"tag": "Double", "value": "1.3"}, + "39": {"tag": "Utf8", "value": "LBoo;"}, + "40": {"tag": "Utf8", "value": "BOO"}, + "41": {"tag": "Float", "value": "3.7"}, + "42": {"tag": "Integer", "value": "33"}, + "43": {"tag": "Long", "value": "3333"}, + "45": {"tag": "Integer", "value": "25"}, + "46": {"tag": "Utf8", "value": "param"}, + "47": {"tag": "Integer", "value": "3"}, + "48": {"tag": "Utf8", "value": "RuntimeVisibleParameterAnnotations"}, + "49": {"tag": "Float", "value": "22.0"}, + "50": {"tag": "Float", "value": "11.0"}, + "51": {"tag": "Utf8", "value": "RuntimeInvisibleParameterAnnotations"}, + "52": {"tag": "Float", "value": "-22.0"}, + "53": {"tag": "Float", "value": "-11.0"}, + "54": {"tag": "Utf8", "value": "Exceptions"}, + "55": {"tag": "Utf8", "value": "Bee"}, + "56": {"tag": "Class", "class name index": 55, "class internal name": "Bee"}, + "57": {"tag": "Utf8", "value": "Code"}, + "58": {"tag": "Utf8", "value": "RuntimeInvisibleTypeAnnotations"}, + "59": {"tag": "Utf8", "value": "RuntimeVisibleTypeAnnotations"}, + "60": {"tag": "Utf8", "value": "LFee;"}, + "61": {"tag": "Utf8", "value": "yes"}, + "62": {"tag": "Integer", "value": "0"}, + "63": {"tag": "Utf8", "value": "LocalVariableTable"}, + "64": {"tag": "Utf8", "value": "LocalVariableTypeTable"}, + "65": {"tag": "Utf8", "value": "LineNumberTable"}, + "66": {"tag": "Utf8", "value": "StackMapTable"}, + "67": {"tag": "Utf8", "value": "SourceFile"}, + "68": {"tag": "Utf8", "value": "Foo.java"}, + "69": {"tag": "Utf8", "value": "InnerClasses"}, + "70": {"tag": "Utf8", "value": "InnerName"}, + "71": {"tag": "Utf8", "value": "EnclosingMethod"}, + "72": {"tag": "Utf8", "value": "enclosingMethod"}, + "73": {"tag": "Utf8", "value": "(Ljava/util/Collection;)Ljava/lang/Double;"}, + "74": {"tag": "NameAndType", "name index": 72, "type index": 73, "name": "enclosingMethod", "type": "(Ljava/util/Collection;)Ljava/lang/Double;"}, + "75": {"tag": "Utf8", "value": "Synthetic"}, + "76": {"tag": "Utf8", "value": "Signature"}, + "77": {"tag": "Utf8", "value": "LBoo;LPhee;LPhoo;"}, + "78": {"tag": "Utf8", "value": "Deprecated"}, + "79": {"tag": "Utf8", "value": "NestHost"}, + "80": {"tag": "Utf8", "value": "NestMembers"}, + "81": {"tag": "Utf8", "value": "Record"}, + "82": {"tag": "Utf8", "value": "fee"}, + "83": {"tag": "Utf8", "value": "RuntimeInvisibleAnnotations"}, + "84": {"tag": "Float", "value": "2.0"}, + "85": {"tag": "Float", "value": "3.0"}, + "86": {"tag": "Utf8", "value": "PermittedSubclasses"}, + "87": {"tag": "Utf8", "value": "BootstrapMethods"}}, "source file": "Foo.java", "inner classes": [ {"inner class": "Phee", "outer class": "Phoo", "inner name": "InnerName", "flags": ["PROTECTED"]}, @@ -445,6 +486,8 @@ void testPrintJsonTraceAll() throws IOException { "invisible annotations": [ {"annotation class": "LPhoo;", "values": [{"name": "flfl", "value": {"float": "2.0"}}, {"name": "frfl", "value": {"float": "3.0"}}]}], "permitted subclasses": ["Boo", "Phoo"], + "bootstrap methods": [ + {"index": 0, "kind": "STATIC", "owner": "Phoo", "name": "phee", "args": ["bootstrap argument 1", "bootstrap argument 2"]}], "fields": [ { "field name": "f", "flags": ["PRIVATE"], @@ -468,35 +511,36 @@ void testPrintJsonTraceAll() throws IOException { "max locals": 3, "attributes": ["RuntimeInvisibleTypeAnnotations", "RuntimeVisibleTypeAnnotations", "LocalVariableTable", "LocalVariableTypeTable", "LineNumberTable", "StackMapTable"], "local variables": [ - {"start": 0, "end": 7, "slot": 2, "name": "variable", "type": "LPhoo;"}], + {"start": 0, "end": 12, "slot": 2, "name": "variable", "type": "LPhoo;"}], "local variable types": [ - {"start": 0, "end": 7, "slot": 2, "name": "variable", "signature": "LPhoo;"}], + {"start": 0, "end": 12, "slot": 2, "name": "variable", "signature": "LPhoo;"}], "line numbers": [ {"start": 0, "line number": 1}, {"start": 1, "line number": 2}, {"start": 6, "line number": 3}, - {"start": 7, "line number": 4}], + {"start": 12, "line number": 4}], "stack map frames": { "6": {"locals": ["Foo", "int", "java/lang/Throwable"], "stack": []}, - "7": {"locals": ["Foo", "int", "java/lang/Throwable"], "stack": ["Phee"]}}, + "12": {"locals": ["Foo", "int", "java/lang/Throwable"], "stack": ["Phee"]}}, "invisible type annotations": [ {"annotation class": "LBoo;", "target info": "FIELD", "values": []}], "visible type annotations": [ {"annotation class": "LFee;", "target info": "FIELD", "values": [{"name": "yes", "value": {"boolean": "false"}}]}], "//stack map frame @0": {"locals": ["Foo", "int", "java/lang/Throwable"], "stack": []}, - "//try block 1 start": {"start": 0, "end": 7, "handler": 7, "catch type": "Phee"}, + "//try block 1 start": {"start": 0, "end": 12, "handler": 12, "catch type": "Phee"}, "0": {"opcode": "ILOAD_1", "slot": 1}, "1": {"opcode": "IFEQ", "target": 6}, "4": {"opcode": "ALOAD_2", "slot": 2, "type": "LPhoo;", "variable name": "variable"}, "5": {"opcode": "ATHROW"}, "//stack map frame @6": {"locals": ["Foo", "int", "java/lang/Throwable"], "stack": []}, - "6": {"opcode": "RETURN"}, - "//stack map frame @7": {"locals": ["Foo", "int", "java/lang/Throwable"], "stack": ["Phee"]}, - "//try block 1 end": {"start": 0, "end": 7, "handler": 7, "catch type": "Phee"}, - "//exception handler 1 start": {"start": 0, "end": 7, "handler": 7, "catch type": "Phee"}, - "7": {"opcode": "ATHROW"}, + "6": {"opcode": "INVOKEDYNAMIC", "name": "intfMethod", "descriptor": "()LBoo;", "bootstrap method": "STATIC Phoo::phee", "arguments": ["bootstrap argument 1", "bootstrap argument 2"]}, + "11": {"opcode": "RETURN"}, + "//stack map frame @12": {"locals": ["Foo", "int", "java/lang/Throwable"], "stack": ["Phee"]}, + "//try block 1 end": {"start": 0, "end": 12, "handler": 12, "catch type": "Phee"}, + "//exception handler 1 start": {"start": 0, "end": 12, "handler": 12, "catch type": "Phee"}, + "12": {"opcode": "ATHROW"}, "exception handlers": { - "handler 1": {"start": 0, "end": 7, "handler": 7, "type": "Phee"}}}}]} + "handler 1": {"start": 0, "end": 12, "handler": 12, "type": "Phee"}}}}]} """); } @@ -511,10 +555,12 @@ void testPrintJsonCriticalAttributes() throws IOException { "flags": ["PUBLIC"], "superclass": "Boo", "interfaces": ["Phee", "Phoo"], - "attributes": ["SourceFile", "InnerClasses", "EnclosingMethod", "Synthetic", "Signature", "Deprecated", "NestHost", "NestMembers", "Record", "RuntimeInvisibleAnnotations", "PermittedSubclasses"], + "attributes": ["SourceFile", "InnerClasses", "EnclosingMethod", "Synthetic", "Signature", "Deprecated", "NestHost", "NestMembers", "Record", "RuntimeInvisibleAnnotations", "PermittedSubclasses", "BootstrapMethods"], "nest host": "Phee", "nest members": ["Phoo", "Boo", "Bee"], "permitted subclasses": ["Boo", "Phoo"], + "bootstrap methods": [ + {"index": 0, "kind": "STATIC", "owner": "Phoo", "name": "phee", "args": ["bootstrap argument 1", "bootstrap argument 2"]}], "fields": [ { "field name": "f", "flags": ["PRIVATE"], @@ -531,21 +577,22 @@ void testPrintJsonCriticalAttributes() throws IOException { "attributes": ["RuntimeInvisibleTypeAnnotations", "RuntimeVisibleTypeAnnotations", "LocalVariableTable", "LocalVariableTypeTable", "LineNumberTable", "StackMapTable"], "stack map frames": { "6": {"locals": ["Foo", "int", "java/lang/Throwable"], "stack": []}, - "7": {"locals": ["Foo", "int", "java/lang/Throwable"], "stack": ["Phee"]}}, + "12": {"locals": ["Foo", "int", "java/lang/Throwable"], "stack": ["Phee"]}}, "//stack map frame @0": {"locals": ["Foo", "int", "java/lang/Throwable"], "stack": []}, - "//try block 1 start": {"start": 0, "end": 7, "handler": 7, "catch type": "Phee"}, + "//try block 1 start": {"start": 0, "end": 12, "handler": 12, "catch type": "Phee"}, "0": {"opcode": "ILOAD_1", "slot": 1}, "1": {"opcode": "IFEQ", "target": 6}, "4": {"opcode": "ALOAD_2", "slot": 2}, "5": {"opcode": "ATHROW"}, "//stack map frame @6": {"locals": ["Foo", "int", "java/lang/Throwable"], "stack": []}, - "6": {"opcode": "RETURN"}, - "//stack map frame @7": {"locals": ["Foo", "int", "java/lang/Throwable"], "stack": ["Phee"]}, - "//try block 1 end": {"start": 0, "end": 7, "handler": 7, "catch type": "Phee"}, - "//exception handler 1 start": {"start": 0, "end": 7, "handler": 7, "catch type": "Phee"}, - "7": {"opcode": "ATHROW"}, + "6": {"opcode": "INVOKEDYNAMIC", "name": "intfMethod", "descriptor": "()LBoo;", "bootstrap method": "STATIC Phoo::phee", "arguments": ["bootstrap argument 1", "bootstrap argument 2"]}, + "11": {"opcode": "RETURN"}, + "//stack map frame @12": {"locals": ["Foo", "int", "java/lang/Throwable"], "stack": ["Phee"]}, + "//try block 1 end": {"start": 0, "end": 12, "handler": 12, "catch type": "Phee"}, + "//exception handler 1 start": {"start": 0, "end": 12, "handler": 12, "catch type": "Phee"}, + "12": {"opcode": "ATHROW"}, "exception handlers": { - "handler 1": {"start": 0, "end": 7, "handler": 7, "type": "Phee"}}}}]} + "handler 1": {"start": 0, "end": 12, "handler": 12, "type": "Phee"}}}}]} """); } @@ -560,7 +607,7 @@ void testPrintJsonMembersOnly() throws IOException { "flags": ["PUBLIC"], "superclass": "Boo", "interfaces": ["Phee", "Phoo"], - "attributes": ["SourceFile", "InnerClasses", "EnclosingMethod", "Synthetic", "Signature", "Deprecated", "NestHost", "NestMembers", "Record", "RuntimeInvisibleAnnotations", "PermittedSubclasses"], + "attributes": ["SourceFile", "InnerClasses", "EnclosingMethod", "Synthetic", "Signature", "Deprecated", "NestHost", "NestMembers", "Record", "RuntimeInvisibleAnnotations", "PermittedSubclasses", "BootstrapMethods"], "fields": [ { "field name": "f", "flags": ["PRIVATE"], @@ -587,7 +634,7 @@ void testPrintXmlTraceAll() throws IOException { PUBLIC Boo PheePhoo - SourceFileInnerClassesEnclosingMethodSyntheticSignatureDeprecatedNestHostNestMembersRecordRuntimeInvisibleAnnotationsPermittedSubclasses + SourceFileInnerClassesEnclosingMethodSyntheticSignatureDeprecatedNestHostNestMembersRecordRuntimeInvisibleAnnotationsPermittedSubclassesBootstrapMethods <_1>Utf8Foo <_2>Class1Foo @@ -599,68 +646,81 @@ void testPrintXmlTraceAll() throws IOException { <_8>Utf8(ZLjava/lang/Throwable;)Ljava/lang/Void; <_9>Utf8variable <_10>Utf8LPhoo; - <_11>Utf8Phee - <_12>Class11Phee - <_13>Utf8Phoo - <_14>Class13Phoo - <_15>Utf8RuntimeVisibleAnnotations - <_16>Utf8flfl - <_17>Float0.0 - <_18>Utf8frfl - <_19>Float1.0 - <_20>Utf8AnnotationDefault - <_21>Integer1 - <_22>Integer12 - <_23>Integer99 - <_24>Utf8LPhee; - <_25>Double1.3 - <_27>Utf8LBoo; - <_28>Utf8BOO - <_29>Float3.7 - <_30>Integer33 - <_31>Long3333 - <_33>Integer25 - <_34>Utf8param - <_35>Integer3 - <_36>Utf8RuntimeVisibleParameterAnnotations - <_37>Float22.0 - <_38>Float11.0 - <_39>Utf8RuntimeInvisibleParameterAnnotations - <_40>Float-22.0 - <_41>Float-11.0 - <_42>Utf8Exceptions - <_43>Utf8Bee - <_44>Class43Bee - <_45>Utf8Code - <_46>Utf8RuntimeInvisibleTypeAnnotations - <_47>Utf8RuntimeVisibleTypeAnnotations - <_48>Utf8LFee; - <_49>Utf8yes - <_50>Integer0 - <_51>Utf8LocalVariableTable - <_52>Utf8LocalVariableTypeTable - <_53>Utf8LineNumberTable - <_54>Utf8StackMapTable - <_55>Utf8SourceFile - <_56>Utf8Foo.java - <_57>Utf8InnerClasses - <_58>Utf8InnerName - <_59>Utf8EnclosingMethod - <_60>Utf8enclosingMethod - <_61>Utf8(Ljava/util/Collection;)Ljava/lang/Double; - <_62>NameAndType6061enclosingMethod(Ljava/util/Collection;)Ljava/lang/Double; - <_63>Utf8Synthetic - <_64>Utf8Signature - <_65>Utf8LBoo;LPhee;LPhoo; - <_66>Utf8Deprecated - <_67>Utf8NestHost - <_68>Utf8NestMembers - <_69>Utf8Record - <_70>Utf8fee - <_71>Utf8RuntimeInvisibleAnnotations - <_72>Float2.0 - <_73>Float3.0 - <_74>Utf8PermittedSubclasses + <_11>Utf8Phoo + <_12>Class11Phoo + <_13>Utf8phee + <_14>Utf8()LBoo; + <_15>NameAndType1314phee()LBoo; + <_16>Methodref1215Phoophee()LBoo; + <_17>MethodHandleSTATIC16Phoophee()LBoo; + <_18>Utf8bootstrap argument 1 + <_19>String18bootstrap argument 1 + <_20>Utf8bootstrap argument 2 + <_21>String20bootstrap argument 2 + <_22>Utf8intfMethod + <_23>NameAndType2214intfMethod()LBoo; + <_24>InvokeDynamic17192123intfMethod()LBoo; + <_25>Utf8Phee + <_26>Class25Phee + <_27>Utf8RuntimeVisibleAnnotations + <_28>Utf8flfl + <_29>Float0.0 + <_30>Utf8frfl + <_31>Float1.0 + <_32>Utf8AnnotationDefault + <_33>Integer1 + <_34>Integer12 + <_35>Integer99 + <_36>Utf8LPhee; + <_37>Double1.3 + <_39>Utf8LBoo; + <_40>Utf8BOO + <_41>Float3.7 + <_42>Integer33 + <_43>Long3333 + <_45>Integer25 + <_46>Utf8param + <_47>Integer3 + <_48>Utf8RuntimeVisibleParameterAnnotations + <_49>Float22.0 + <_50>Float11.0 + <_51>Utf8RuntimeInvisibleParameterAnnotations + <_52>Float-22.0 + <_53>Float-11.0 + <_54>Utf8Exceptions + <_55>Utf8Bee + <_56>Class55Bee + <_57>Utf8Code + <_58>Utf8RuntimeInvisibleTypeAnnotations + <_59>Utf8RuntimeVisibleTypeAnnotations + <_60>Utf8LFee; + <_61>Utf8yes + <_62>Integer0 + <_63>Utf8LocalVariableTable + <_64>Utf8LocalVariableTypeTable + <_65>Utf8LineNumberTable + <_66>Utf8StackMapTable + <_67>Utf8SourceFile + <_68>Utf8Foo.java + <_69>Utf8InnerClasses + <_70>Utf8InnerName + <_71>Utf8EnclosingMethod + <_72>Utf8enclosingMethod + <_73>Utf8(Ljava/util/Collection;)Ljava/lang/Double; + <_74>NameAndType7273enclosingMethod(Ljava/util/Collection;)Ljava/lang/Double; + <_75>Utf8Synthetic + <_76>Utf8Signature + <_77>Utf8LBoo;LPhee;LPhoo; + <_78>Utf8Deprecated + <_79>Utf8NestHost + <_80>Utf8NestMembers + <_81>Utf8Record + <_82>Utf8fee + <_83>Utf8RuntimeInvisibleAnnotations + <_84>Float2.0 + <_85>Float3.0 + <_86>Utf8PermittedSubclasses + <_87>Utf8BootstrapMethods Foo.java PheePhooInnerNamePROTECTED @@ -680,6 +740,8 @@ void testPrintXmlTraceAll() throws IOException { LPhoo;flfl2.0frfl3.0 BooPhoo + + 0STATICPhoopheebootstrap argument 1bootstrap argument 2 f @@ -705,35 +767,36 @@ void testPrintXmlTraceAll() throws IOException { 3 RuntimeInvisibleTypeAnnotationsRuntimeVisibleTypeAnnotationsLocalVariableTableLocalVariableTypeTableLineNumberTableStackMapTable - <_1>072variableLPhoo; + <_1>0122variableLPhoo; - <_1>072variableLPhoo; + <_1>0122variableLPhoo; <_1>01 <_2>12 <_3>63 - <_4>74 + <_4>124 <_6>Foointjava/lang/Throwable - <_7>Foointjava/lang/ThrowablePhee + <_12>Foointjava/lang/ThrowablePhee LBoo;FIELD LFee;FIELDyesfalse <__stack_map_frame__0>Foointjava/lang/Throwable - <__try_block_1_start>077Phee + <__try_block_1_start>01212Phee <_0>ILOAD_11 <_1>IFEQ6 <_4>ALOAD_22LPhoo;variable <_5>ATHROW <__stack_map_frame__6>Foointjava/lang/Throwable - <_6>RETURN - <__stack_map_frame__7>Foointjava/lang/ThrowablePhee - <__try_block_1_end>077Phee - <__exception_handler_1_start>077Phee - <_7>ATHROW + <_6>INVOKEDYNAMICintfMethod()LBoo;STATIC Phoo::pheebootstrap argument 1bootstrap argument 2 + <_11>RETURN + <__stack_map_frame__12>Foointjava/lang/ThrowablePhee + <__try_block_1_end>01212Phee + <__exception_handler_1_start>01212Phee + <_12>ATHROW - 077Phee + 01212Phee """); } @@ -750,10 +813,12 @@ void testPrintXmlCriticalAttributes() throws IOException { PUBLIC Boo PheePhoo - SourceFileInnerClassesEnclosingMethodSyntheticSignatureDeprecatedNestHostNestMembersRecordRuntimeInvisibleAnnotationsPermittedSubclasses + SourceFileInnerClassesEnclosingMethodSyntheticSignatureDeprecatedNestHostNestMembersRecordRuntimeInvisibleAnnotationsPermittedSubclassesBootstrapMethods Phee PhooBooBee BooPhoo + + 0STATICPhoopheebootstrap argument 1bootstrap argument 2 f @@ -772,21 +837,22 @@ void testPrintXmlCriticalAttributes() throws IOException { RuntimeInvisibleTypeAnnotationsRuntimeVisibleTypeAnnotationsLocalVariableTableLocalVariableTypeTableLineNumberTableStackMapTable <_6>Foointjava/lang/Throwable - <_7>Foointjava/lang/ThrowablePhee + <_12>Foointjava/lang/ThrowablePhee <__stack_map_frame__0>Foointjava/lang/Throwable - <__try_block_1_start>077Phee + <__try_block_1_start>01212Phee <_0>ILOAD_11 <_1>IFEQ6 <_4>ALOAD_22 <_5>ATHROW <__stack_map_frame__6>Foointjava/lang/Throwable - <_6>RETURN - <__stack_map_frame__7>Foointjava/lang/ThrowablePhee - <__try_block_1_end>077Phee - <__exception_handler_1_start>077Phee - <_7>ATHROW + <_6>INVOKEDYNAMICintfMethod()LBoo;STATIC Phoo::pheebootstrap argument 1bootstrap argument 2 + <_11>RETURN + <__stack_map_frame__12>Foointjava/lang/ThrowablePhee + <__try_block_1_end>01212Phee + <__exception_handler_1_start>01212Phee + <_12>ATHROW - 077Phee + 01212Phee """); } @@ -803,7 +869,7 @@ void testPrintXmlMembersOnly() throws IOException { PUBLIC Boo PheePhoo - SourceFileInnerClassesEnclosingMethodSyntheticSignatureDeprecatedNestHostNestMembersRecordRuntimeInvisibleAnnotationsPermittedSubclasses + SourceFileInnerClassesEnclosingMethodSyntheticSignatureDeprecatedNestHostNestMembersRecordRuntimeInvisibleAnnotationsPermittedSubclassesBootstrapMethods f @@ -822,19 +888,19 @@ void testPrintXmlMembersOnly() throws IOException { @Test void testWalkTraceAll() throws IOException { var node = ClassPrinter.toTree(getClassModel(), ClassPrinter.Verbosity.TRACE_ALL); - assertEquals(node.walk().count(), 509); + assertEquals(node.walk().count(), 588); } @Test void testWalkCriticalAttributes() throws IOException { var node = ClassPrinter.toTree(getClassModel(), ClassPrinter.Verbosity.CRITICAL_ATTRIBUTES); - assertEquals(node.walk().count(), 128); + assertEquals(node.walk().count(), 146); } @Test void testWalkMembersOnly() throws IOException { var node = ClassPrinter.toTree(getClassModel(), ClassPrinter.Verbosity.MEMBERS_ONLY); - assertEquals(node.walk().count(), 41); + assertEquals(node.walk().count(), 42); } private static void assertOut(StringBuilder out, String expected) { diff --git a/test/jdk/jdk/classfile/CorpusTest.java b/test/jdk/jdk/classfile/CorpusTest.java index 450643dda29..b13657e2072 100644 --- a/test/jdk/jdk/classfile/CorpusTest.java +++ b/test/jdk/jdk/classfile/CorpusTest.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 @@ -23,6 +23,7 @@ /* * @test + * @bug 8325485 * @summary Testing ClassFile on small Corpus. * @build helpers.* testdata.* * @run junit/othervm/timeout=480 -Djunit.jupiter.execution.parallel.enabled=true CorpusTest diff --git a/test/jdk/jdk/classfile/helpers/ClassRecord.java b/test/jdk/jdk/classfile/helpers/ClassRecord.java index de529cf31b6..b348a51f23e 100644 --- a/test/jdk/jdk/classfile/helpers/ClassRecord.java +++ b/test/jdk/jdk/classfile/helpers/ClassRecord.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 @@ -485,7 +485,7 @@ int multipleTargetsHash(int pc, int firstOffset, int[] otherOffsets, int... othe int hash(int from, int length) { int result = 1; - for (int i = from; i < length; i++) { + for (int i = from; i < from + length; i++) { int elementHash = (codeToIndexMap[i] ^ (codeToIndexMap[i] >>> 32)); result = 31 * result + elementHash; } @@ -557,7 +557,7 @@ else if ((ins instanceof StoreInstruction local)) { yield local.slot(); } else { - yield code.hash(p[0] + 1, ins.sizeInBytes()); + yield code.hash(p[0] + 1, ins.sizeInBytes() - 1); } } }; diff --git a/test/jdk/jdk/classfile/helpers/RebuildingTransformation.java b/test/jdk/jdk/classfile/helpers/RebuildingTransformation.java index c48a583d2e1..88958939317 100644 --- a/test/jdk/jdk/classfile/helpers/RebuildingTransformation.java +++ b/test/jdk/jdk/classfile/helpers/RebuildingTransformation.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 @@ -69,394 +69,15 @@ static byte[] transform(ClassModel clm) { for (var me : mm) { switch (me) { case AccessFlags af -> mb.withFlags(af.flagsMask()); - case CodeModel com -> mb.withCode(cb -> cb.transforming(CodeStackTracker.of(), cob -> { - var labels = new HashMap(); - for (var coe : com) { - switch (coe) { - case ArrayLoadInstruction i -> { - switch (i.typeKind()) { - case ByteType -> cob.baload(); - case ShortType -> cob.saload(); - case IntType -> cob.iaload(); - case FloatType -> cob.faload(); - case LongType -> cob.laload(); - case DoubleType -> cob.daload(); - case ReferenceType -> cob.aaload(); - case CharType -> cob.caload(); - default -> throw new AssertionError("Should not reach here"); - } - } - case ArrayStoreInstruction i -> { - switch (i.typeKind()) { - case ByteType -> cob.bastore(); - case ShortType -> cob.sastore(); - case IntType -> cob.iastore(); - case FloatType -> cob.fastore(); - case LongType -> cob.lastore(); - case DoubleType -> cob.dastore(); - case ReferenceType -> cob.aastore(); - case CharType -> cob.castore(); - default -> throw new AssertionError("Should not reach here"); - } - } - case BranchInstruction i -> { - var target = labels.computeIfAbsent(i.target(), l -> cob.newLabel()); - switch (i.opcode()) { - case GOTO -> cob.goto_(target); - case GOTO_W -> cob.goto_w(target); - case IF_ACMPEQ -> cob.if_acmpeq(target); - case IF_ACMPNE -> cob.if_acmpne(target); - case IF_ICMPEQ -> cob.if_icmpeq(target); - case IF_ICMPGE -> cob.if_icmpge(target); - case IF_ICMPGT -> cob.if_icmpgt(target); - case IF_ICMPLE -> cob.if_icmple(target); - case IF_ICMPLT -> cob.if_icmplt(target); - case IF_ICMPNE -> cob.if_icmpne(target); - case IFNONNULL -> cob.if_nonnull(target); - case IFNULL -> cob.if_null(target); - case IFEQ -> cob.ifeq(target); - case IFGE -> cob.ifge(target); - case IFGT -> cob.ifgt(target); - case IFLE -> cob.ifle(target); - case IFLT -> cob.iflt(target); - case IFNE -> cob.ifne(target); - default -> throw new AssertionError("Should not reach here"); - } - } - case ConstantInstruction i -> { - if (i.constantValue() == null) - if (pathSwitch.nextBoolean()) cob.aconst_null(); - else cob.constantInstruction(null); - else switch (i.constantValue()) { - case Integer iVal -> { - if (iVal == 1 && pathSwitch.nextBoolean()) cob.iconst_1(); - else if (iVal == 2 && pathSwitch.nextBoolean()) cob.iconst_2(); - else if (iVal == 3 && pathSwitch.nextBoolean()) cob.iconst_3(); - else if (iVal == 4 && pathSwitch.nextBoolean()) cob.iconst_4(); - else if (iVal == 5 && pathSwitch.nextBoolean()) cob.iconst_5(); - else if (iVal == -1 && pathSwitch.nextBoolean()) cob.iconst_m1(); - else if (iVal >= -128 && iVal <= 127 && pathSwitch.nextBoolean()) cob.bipush(iVal); - else if (iVal >= -32768 && iVal <= 32767 && pathSwitch.nextBoolean()) cob.sipush(iVal); - else cob.constantInstruction(iVal); - } - case Long lVal -> { - if (lVal == 0 && pathSwitch.nextBoolean()) cob.lconst_0(); - else if (lVal == 1 && pathSwitch.nextBoolean()) cob.lconst_1(); - else cob.constantInstruction(lVal); - } - case Float fVal -> { - if (fVal == 0.0 && pathSwitch.nextBoolean()) cob.fconst_0(); - else if (fVal == 1.0 && pathSwitch.nextBoolean()) cob.fconst_1(); - else if (fVal == 2.0 && pathSwitch.nextBoolean()) cob.fconst_2(); - else cob.constantInstruction(fVal); - } - case Double dVal -> { - if (dVal == 0.0d && pathSwitch.nextBoolean()) cob.dconst_0(); - else if (dVal == 1.0d && pathSwitch.nextBoolean()) cob.dconst_1(); - else cob.constantInstruction(dVal); - } - default -> cob.constantInstruction(i.constantValue()); - } - } - case ConvertInstruction i -> { - switch (i.fromType()) { - case DoubleType -> { - switch (i.toType()) { - case FloatType -> cob.d2f(); - case IntType -> cob.d2i(); - case LongType -> cob.d2l(); - default -> throw new AssertionError("Should not reach here"); - } - } - case FloatType -> { - switch (i.toType()) { - case DoubleType -> cob.f2d(); - case IntType -> cob.f2i(); - case LongType -> cob.f2l(); - default -> throw new AssertionError("Should not reach here"); - } - } - case IntType -> { - switch (i.toType()) { - case ByteType -> cob.i2b(); - case CharType -> cob.i2c(); - case DoubleType -> cob.i2d(); - case FloatType -> cob.i2f(); - case LongType -> cob.i2l(); - case ShortType -> cob.i2s(); - default -> throw new AssertionError("Should not reach here"); - } - } - case LongType -> { - switch (i.toType()) { - case DoubleType -> cob.l2d(); - case FloatType -> cob.l2f(); - case IntType -> cob.l2i(); - default -> throw new AssertionError("Should not reach here"); - } - } - default -> throw new AssertionError("Should not reach here"); - } - } - case DiscontinuedInstruction.JsrInstruction i -> - cob.with(DiscontinuedInstruction.JsrInstruction.of(i.opcode(), labels.computeIfAbsent(i.target(), l -> cob.newLabel()))); - case DiscontinuedInstruction.RetInstruction i -> - cob.with(DiscontinuedInstruction.RetInstruction.of(i.opcode(), i.slot())); - case FieldInstruction i -> { - if (pathSwitch.nextBoolean()) { - switch (i.opcode()) { - case GETFIELD -> cob.getfield(i.owner().asSymbol(), i.name().stringValue(), i.typeSymbol()); - case GETSTATIC -> cob.getstatic(i.owner().asSymbol(), i.name().stringValue(), i.typeSymbol()); - case PUTFIELD -> cob.putfield(i.owner().asSymbol(), i.name().stringValue(), i.typeSymbol()); - case PUTSTATIC -> cob.putstatic(i.owner().asSymbol(), i.name().stringValue(), i.typeSymbol()); - default -> throw new AssertionError("Should not reach here"); - } - } else { - switch (i.opcode()) { - case GETFIELD -> cob.getfield(i.field()); - case GETSTATIC -> cob.getstatic(i.field()); - case PUTFIELD -> cob.putfield(i.field()); - case PUTSTATIC -> cob.putstatic(i.field()); - default -> throw new AssertionError("Should not reach here"); - } - } - } - case InvokeDynamicInstruction i -> { - if (pathSwitch.nextBoolean()) cob.invokedynamic(i.invokedynamic().asSymbol()); - else cob.invokedynamic(i.invokedynamic()); - } - case InvokeInstruction i -> { - if (pathSwitch.nextBoolean()) { - if (i.isInterface()) { - switch (i.opcode()) { - case INVOKEINTERFACE -> cob.invokeinterface(i.owner().asSymbol(), i.name().stringValue(), i.typeSymbol()); - case INVOKESPECIAL -> cob.invokespecial(i.owner().asSymbol(), i.name().stringValue(), i.typeSymbol(), true); - case INVOKESTATIC -> cob.invokestatic(i.owner().asSymbol(), i.name().stringValue(), i.typeSymbol(), true); - default -> throw new AssertionError("Should not reach here"); - } - } else { - switch (i.opcode()) { - case INVOKESPECIAL -> cob.invokespecial(i.owner().asSymbol(), i.name().stringValue(), i.typeSymbol()); - case INVOKESTATIC -> cob.invokestatic(i.owner().asSymbol(), i.name().stringValue(), i.typeSymbol()); - case INVOKEVIRTUAL -> cob.invokevirtual(i.owner().asSymbol(), i.name().stringValue(), i.typeSymbol()); - default -> throw new AssertionError("Should not reach here"); - } - } - } else { - switch (i.method()) { - case InterfaceMethodRefEntry en -> { - switch (i.opcode()) { - case INVOKEINTERFACE -> cob.invokeinterface(en); - case INVOKESPECIAL -> cob.invokespecial(en); - case INVOKESTATIC -> cob.invokestatic(en); - default -> throw new AssertionError("Should not reach here"); - } - } - case MethodRefEntry en -> { - switch (i.opcode()) { - case INVOKESPECIAL -> cob.invokespecial(en); - case INVOKESTATIC -> cob.invokestatic(en); - case INVOKEVIRTUAL -> cob.invokevirtual(en); - default -> throw new AssertionError("Should not reach here"); - } - } - default -> throw new AssertionError("Should not reach here"); - } - } - } - case LoadInstruction i -> { - switch (i.typeKind()) { - case IntType -> cob.iload(i.slot()); - case FloatType -> cob.fload(i.slot()); - case LongType -> cob.lload(i.slot()); - case DoubleType -> cob.dload(i.slot()); - case ReferenceType -> cob.aload(i.slot()); - default -> throw new AssertionError("Should not reach here"); - } - } - case StoreInstruction i -> { - switch (i.typeKind()) { - case IntType -> cob.istore(i.slot()); - case FloatType -> cob.fstore(i.slot()); - case LongType -> cob.lstore(i.slot()); - case DoubleType -> cob.dstore(i.slot()); - case ReferenceType -> cob.astore(i.slot()); - default -> throw new AssertionError("Should not reach here"); - } - } - case IncrementInstruction i -> - cob.iinc(i.slot(), i.constant()); - case LookupSwitchInstruction i -> - cob.lookupswitch(labels.computeIfAbsent(i.defaultTarget(), l -> cob.newLabel()), - i.cases().stream().map(sc -> - SwitchCase.of(sc.caseValue(), labels.computeIfAbsent(sc.target(), l -> cob.newLabel()))).toList()); - case MonitorInstruction i -> { - switch (i.opcode()) { - case MONITORENTER -> cob.monitorenter(); - case MONITOREXIT -> cob.monitorexit(); - default -> throw new AssertionError("Should not reach here"); - } - } - case NewMultiArrayInstruction i -> { - if (pathSwitch.nextBoolean()) { - cob.multianewarray(i.arrayType().asSymbol(), i.dimensions()); - } else { - cob.multianewarray(i.arrayType(), i.dimensions()); - } - } - case NewObjectInstruction i -> { - if (pathSwitch.nextBoolean()) { - cob.new_(i.className().asSymbol()); - } else { - cob.new_(i.className()); - } - } - case NewPrimitiveArrayInstruction i -> - cob.newarray(i.typeKind()); - case NewReferenceArrayInstruction i -> { - if (pathSwitch.nextBoolean()) { - cob.anewarray(i.componentType().asSymbol()); - } else { - cob.anewarray(i.componentType()); - } - } - case NopInstruction i -> - cob.nop(); - case OperatorInstruction i -> { - switch (i.opcode()) { - case IADD -> cob.iadd(); - case LADD -> cob.ladd(); - case FADD -> cob.fadd(); - case DADD -> cob.dadd(); - case ISUB -> cob.isub(); - case LSUB -> cob.lsub(); - case FSUB -> cob.fsub(); - case DSUB -> cob.dsub(); - case IMUL -> cob.imul(); - case LMUL -> cob.lmul(); - case FMUL -> cob.fmul(); - case DMUL -> cob.dmul(); - case IDIV -> cob.idiv(); - case LDIV -> cob.ldiv(); - case FDIV -> cob.fdiv(); - case DDIV -> cob.ddiv(); - case IREM -> cob.irem(); - case LREM -> cob.lrem(); - case FREM -> cob.frem(); - case DREM -> cob.drem(); - case INEG -> cob.ineg(); - case LNEG -> cob.lneg(); - case FNEG -> cob.fneg(); - case DNEG -> cob.dneg(); - case ISHL -> cob.ishl(); - case LSHL -> cob.lshl(); - case ISHR -> cob.ishr(); - case LSHR -> cob.lshr(); - case IUSHR -> cob.iushr(); - case LUSHR -> cob.lushr(); - case IAND -> cob.iand(); - case LAND -> cob.land(); - case IOR -> cob.ior(); - case LOR -> cob.lor(); - case IXOR -> cob.ixor(); - case LXOR -> cob.lxor(); - case LCMP -> cob.lcmp(); - case FCMPL -> cob.fcmpl(); - case FCMPG -> cob.fcmpg(); - case DCMPL -> cob.dcmpl(); - case DCMPG -> cob.dcmpg(); - case ARRAYLENGTH -> cob.arraylength(); - default -> throw new AssertionError("Should not reach here"); - } - } - case ReturnInstruction i -> { - switch (i.typeKind()) { - case IntType -> cob.ireturn(); - case FloatType -> cob.freturn(); - case LongType -> cob.lreturn(); - case DoubleType -> cob.dreturn(); - case ReferenceType -> cob.areturn(); - case VoidType -> cob.return_(); - default -> throw new AssertionError("Should not reach here"); - } - } - case StackInstruction i -> { - switch (i.opcode()) { - case POP -> cob.pop(); - case POP2 -> cob.pop2(); - case DUP -> cob.dup(); - case DUP_X1 -> cob.dup_x1(); - case DUP_X2 -> cob.dup_x2(); - case DUP2 -> cob.dup2(); - case DUP2_X1 -> cob.dup2_x1(); - case DUP2_X2 -> cob.dup2_x2(); - case SWAP -> cob.swap(); - default -> throw new AssertionError("Should not reach here"); - } - } - case TableSwitchInstruction i -> - cob.tableswitch(i.lowValue(), i.highValue(), - labels.computeIfAbsent(i.defaultTarget(), l -> cob.newLabel()), - i.cases().stream().map(sc -> - SwitchCase.of(sc.caseValue(), labels.computeIfAbsent(sc.target(), l -> cob.newLabel()))).toList()); - case ThrowInstruction i -> cob.athrow(); - case TypeCheckInstruction i -> { - if (pathSwitch.nextBoolean()) { - switch (i.opcode()) { - case CHECKCAST -> cob.checkcast(i.type().asSymbol()); - case INSTANCEOF -> cob.instanceof_(i.type().asSymbol()); - default -> throw new AssertionError("Should not reach here"); - } - } else { - switch (i.opcode()) { - case CHECKCAST -> cob.checkcast(i.type()); - case INSTANCEOF -> cob.instanceof_(i.type()); - default -> throw new AssertionError("Should not reach here"); - } - } - } - case CharacterRange pi -> - cob.characterRange(labels.computeIfAbsent(pi.startScope(), l -> cob.newLabel()), - labels.computeIfAbsent(pi.endScope(), l -> cob.newLabel()), - pi.characterRangeStart(), pi.characterRangeEnd(), pi.flags()); - case ExceptionCatch pi -> - pi.catchType().ifPresentOrElse( - catchType -> cob.exceptionCatch(labels.computeIfAbsent(pi.tryStart(), l -> cob.newLabel()), - labels.computeIfAbsent(pi.tryEnd(), l -> cob.newLabel()), - labels.computeIfAbsent(pi.handler(), l -> cob.newLabel()), - catchType.asSymbol()), - () -> cob.exceptionCatchAll(labels.computeIfAbsent(pi.tryStart(), l -> cob.newLabel()), - labels.computeIfAbsent(pi.tryEnd(), l -> cob.newLabel()), - labels.computeIfAbsent(pi.handler(), l -> cob.newLabel()))); - case LabelTarget pi -> - cob.labelBinding(labels.computeIfAbsent(pi.label(), l -> cob.newLabel())); - case LineNumber pi -> - cob.lineNumber(pi.line()); - case LocalVariable pi -> - cob.localVariable(pi.slot(), pi.name().stringValue(), pi.typeSymbol(), - labels.computeIfAbsent(pi.startScope(), l -> cob.newLabel()), - labels.computeIfAbsent(pi.endScope(), l -> cob.newLabel())); - case LocalVariableType pi -> - cob.localVariableType(pi.slot(), pi.name().stringValue(), - Signature.parseFrom(pi.signatureSymbol().signatureString()), - labels.computeIfAbsent(pi.startScope(), l -> cob.newLabel()), - labels.computeIfAbsent(pi.endScope(), l -> cob.newLabel())); - case RuntimeInvisibleTypeAnnotationsAttribute a -> - cob.with(RuntimeInvisibleTypeAnnotationsAttribute.of(transformTypeAnnotations(a.annotations(), cob, labels))); - case RuntimeVisibleTypeAnnotationsAttribute a -> - cob.with(RuntimeVisibleTypeAnnotationsAttribute.of(transformTypeAnnotations(a.annotations(), cob, labels))); - case StackMapTableAttribute a -> - throw new AssertionError("Unexpected StackMapTableAttribute here"); - case CustomAttribute a -> - throw new AssertionError("Unexpected custom attribute: " + a.attributeName()); - } - } - com.findAttribute(Attributes.STACK_MAP_TABLE).ifPresent(smta -> - cob.with(StackMapTableAttribute.of(smta.entries().stream().map(fr -> - StackMapFrameInfo.of(labels.computeIfAbsent(fr.target(), l -> cob.newLabel()), - transformFrameTypeInfos(fr.locals(), cob, labels), - transformFrameTypeInfos(fr.stack(), cob, labels))).toList()))); - })); + case CodeModel com -> mb.withCode(cob1 -> + cob1.transforming(CodeStackTracker.of(), cob2 -> + // second pass transforms unbound to unbound instructions + cob2.transforming(new CodeRebuildingTransform(), cob3 -> + // first pass transforms bound to unbound instructions + cob3.transforming(new CodeRebuildingTransform(), cob4 -> { + com.forEachElement(cob4::with); + com.findAttribute(Attributes.STACK_MAP_TABLE).ifPresent(cob4::with); + })))); case AnnotationDefaultAttribute a -> mb.with(AnnotationDefaultAttribute.of(transformAnnotationValue(a.defaultValue()))); case DeprecatedAttribute a -> mb.with(DeprecatedAttribute.of()); case ExceptionsAttribute a -> mb.with(ExceptionsAttribute.ofSymbols(a.exceptions().stream().map(ClassEntry::asSymbol).toArray(ClassDesc[]::new))); @@ -589,4 +210,394 @@ static List transformFrameTypeInfos(List }; }).toList(); } + + static class CodeRebuildingTransform implements CodeTransform { + + final HashMap labels = new HashMap<>(); + + @Override + public void accept(CodeBuilder cob, CodeElement coe) { + switch (coe) { + case ArrayLoadInstruction i -> { + switch (i.typeKind()) { + case ByteType -> cob.baload(); + case ShortType -> cob.saload(); + case IntType -> cob.iaload(); + case FloatType -> cob.faload(); + case LongType -> cob.laload(); + case DoubleType -> cob.daload(); + case ReferenceType -> cob.aaload(); + case CharType -> cob.caload(); + default -> throw new AssertionError("Should not reach here"); + } + } + case ArrayStoreInstruction i -> { + switch (i.typeKind()) { + case ByteType -> cob.bastore(); + case ShortType -> cob.sastore(); + case IntType -> cob.iastore(); + case FloatType -> cob.fastore(); + case LongType -> cob.lastore(); + case DoubleType -> cob.dastore(); + case ReferenceType -> cob.aastore(); + case CharType -> cob.castore(); + default -> throw new AssertionError("Should not reach here"); + } + } + case BranchInstruction i -> { + var target = labels.computeIfAbsent(i.target(), l -> cob.newLabel()); + switch (i.opcode()) { + case GOTO -> cob.goto_(target); + case GOTO_W -> cob.goto_w(target); + case IF_ACMPEQ -> cob.if_acmpeq(target); + case IF_ACMPNE -> cob.if_acmpne(target); + case IF_ICMPEQ -> cob.if_icmpeq(target); + case IF_ICMPGE -> cob.if_icmpge(target); + case IF_ICMPGT -> cob.if_icmpgt(target); + case IF_ICMPLE -> cob.if_icmple(target); + case IF_ICMPLT -> cob.if_icmplt(target); + case IF_ICMPNE -> cob.if_icmpne(target); + case IFNONNULL -> cob.if_nonnull(target); + case IFNULL -> cob.if_null(target); + case IFEQ -> cob.ifeq(target); + case IFGE -> cob.ifge(target); + case IFGT -> cob.ifgt(target); + case IFLE -> cob.ifle(target); + case IFLT -> cob.iflt(target); + case IFNE -> cob.ifne(target); + default -> throw new AssertionError("Should not reach here"); + } + } + case ConstantInstruction i -> { + if (i.constantValue() == null) + if (pathSwitch.nextBoolean()) cob.aconst_null(); + else cob.constantInstruction(null); + else switch (i.constantValue()) { + case Integer iVal -> { + if (iVal == 1 && pathSwitch.nextBoolean()) cob.iconst_1(); + else if (iVal == 2 && pathSwitch.nextBoolean()) cob.iconst_2(); + else if (iVal == 3 && pathSwitch.nextBoolean()) cob.iconst_3(); + else if (iVal == 4 && pathSwitch.nextBoolean()) cob.iconst_4(); + else if (iVal == 5 && pathSwitch.nextBoolean()) cob.iconst_5(); + else if (iVal == -1 && pathSwitch.nextBoolean()) cob.iconst_m1(); + else if (iVal >= -128 && iVal <= 127 && pathSwitch.nextBoolean()) cob.bipush(iVal); + else if (iVal >= -32768 && iVal <= 32767 && pathSwitch.nextBoolean()) cob.sipush(iVal); + else cob.constantInstruction(iVal); + } + case Long lVal -> { + if (lVal == 0 && pathSwitch.nextBoolean()) cob.lconst_0(); + else if (lVal == 1 && pathSwitch.nextBoolean()) cob.lconst_1(); + else cob.constantInstruction(lVal); + } + case Float fVal -> { + if (fVal == 0.0 && pathSwitch.nextBoolean()) cob.fconst_0(); + else if (fVal == 1.0 && pathSwitch.nextBoolean()) cob.fconst_1(); + else if (fVal == 2.0 && pathSwitch.nextBoolean()) cob.fconst_2(); + else cob.constantInstruction(fVal); + } + case Double dVal -> { + if (dVal == 0.0d && pathSwitch.nextBoolean()) cob.dconst_0(); + else if (dVal == 1.0d && pathSwitch.nextBoolean()) cob.dconst_1(); + else cob.constantInstruction(dVal); + } + default -> cob.constantInstruction(i.constantValue()); + } + } + case ConvertInstruction i -> { + switch (i.fromType()) { + case DoubleType -> { + switch (i.toType()) { + case FloatType -> cob.d2f(); + case IntType -> cob.d2i(); + case LongType -> cob.d2l(); + default -> throw new AssertionError("Should not reach here"); + } + } + case FloatType -> { + switch (i.toType()) { + case DoubleType -> cob.f2d(); + case IntType -> cob.f2i(); + case LongType -> cob.f2l(); + default -> throw new AssertionError("Should not reach here"); + } + } + case IntType -> { + switch (i.toType()) { + case ByteType -> cob.i2b(); + case CharType -> cob.i2c(); + case DoubleType -> cob.i2d(); + case FloatType -> cob.i2f(); + case LongType -> cob.i2l(); + case ShortType -> cob.i2s(); + default -> throw new AssertionError("Should not reach here"); + } + } + case LongType -> { + switch (i.toType()) { + case DoubleType -> cob.l2d(); + case FloatType -> cob.l2f(); + case IntType -> cob.l2i(); + default -> throw new AssertionError("Should not reach here"); + } + } + default -> throw new AssertionError("Should not reach here"); + } + } + case DiscontinuedInstruction.JsrInstruction i -> + cob.with(DiscontinuedInstruction.JsrInstruction.of(i.opcode(), labels.computeIfAbsent(i.target(), l -> cob.newLabel()))); + case DiscontinuedInstruction.RetInstruction i -> + cob.with(DiscontinuedInstruction.RetInstruction.of(i.opcode(), i.slot())); + case FieldInstruction i -> { + if (pathSwitch.nextBoolean()) { + switch (i.opcode()) { + case GETFIELD -> cob.getfield(i.owner().asSymbol(), i.name().stringValue(), i.typeSymbol()); + case GETSTATIC -> cob.getstatic(i.owner().asSymbol(), i.name().stringValue(), i.typeSymbol()); + case PUTFIELD -> cob.putfield(i.owner().asSymbol(), i.name().stringValue(), i.typeSymbol()); + case PUTSTATIC -> cob.putstatic(i.owner().asSymbol(), i.name().stringValue(), i.typeSymbol()); + default -> throw new AssertionError("Should not reach here"); + } + } else { + switch (i.opcode()) { + case GETFIELD -> cob.getfield(i.field()); + case GETSTATIC -> cob.getstatic(i.field()); + case PUTFIELD -> cob.putfield(i.field()); + case PUTSTATIC -> cob.putstatic(i.field()); + default -> throw new AssertionError("Should not reach here"); + } + } + } + case InvokeDynamicInstruction i -> { + if (pathSwitch.nextBoolean()) cob.invokedynamic(i.invokedynamic().asSymbol()); + else cob.invokedynamic(i.invokedynamic()); + } + case InvokeInstruction i -> { + if (pathSwitch.nextBoolean()) { + if (i.isInterface()) { + switch (i.opcode()) { + case INVOKEINTERFACE -> cob.invokeinterface(i.owner().asSymbol(), i.name().stringValue(), i.typeSymbol()); + case INVOKESPECIAL -> cob.invokespecial(i.owner().asSymbol(), i.name().stringValue(), i.typeSymbol(), true); + case INVOKESTATIC -> cob.invokestatic(i.owner().asSymbol(), i.name().stringValue(), i.typeSymbol(), true); + default -> throw new AssertionError("Should not reach here"); + } + } else { + switch (i.opcode()) { + case INVOKESPECIAL -> cob.invokespecial(i.owner().asSymbol(), i.name().stringValue(), i.typeSymbol()); + case INVOKESTATIC -> cob.invokestatic(i.owner().asSymbol(), i.name().stringValue(), i.typeSymbol()); + case INVOKEVIRTUAL -> cob.invokevirtual(i.owner().asSymbol(), i.name().stringValue(), i.typeSymbol()); + default -> throw new AssertionError("Should not reach here"); + } + } + } else { + switch (i.method()) { + case InterfaceMethodRefEntry en -> { + switch (i.opcode()) { + case INVOKEINTERFACE -> cob.invokeinterface(en); + case INVOKESPECIAL -> cob.invokespecial(en); + case INVOKESTATIC -> cob.invokestatic(en); + default -> throw new AssertionError("Should not reach here"); + } + } + case MethodRefEntry en -> { + switch (i.opcode()) { + case INVOKESPECIAL -> cob.invokespecial(en); + case INVOKESTATIC -> cob.invokestatic(en); + case INVOKEVIRTUAL -> cob.invokevirtual(en); + default -> throw new AssertionError("Should not reach here"); + } + } + default -> throw new AssertionError("Should not reach here"); + } + } + } + case LoadInstruction i -> { + switch (i.typeKind()) { + case IntType -> cob.iload(i.slot()); + case FloatType -> cob.fload(i.slot()); + case LongType -> cob.lload(i.slot()); + case DoubleType -> cob.dload(i.slot()); + case ReferenceType -> cob.aload(i.slot()); + default -> throw new AssertionError("Should not reach here"); + } + } + case StoreInstruction i -> { + switch (i.typeKind()) { + case IntType -> cob.istore(i.slot()); + case FloatType -> cob.fstore(i.slot()); + case LongType -> cob.lstore(i.slot()); + case DoubleType -> cob.dstore(i.slot()); + case ReferenceType -> cob.astore(i.slot()); + default -> throw new AssertionError("Should not reach here"); + } + } + case IncrementInstruction i -> + cob.iinc(i.slot(), i.constant()); + case LookupSwitchInstruction i -> + cob.lookupswitch(labels.computeIfAbsent(i.defaultTarget(), l -> cob.newLabel()), + i.cases().stream().map(sc -> + SwitchCase.of(sc.caseValue(), labels.computeIfAbsent(sc.target(), l -> cob.newLabel()))).toList()); + case MonitorInstruction i -> { + switch (i.opcode()) { + case MONITORENTER -> cob.monitorenter(); + case MONITOREXIT -> cob.monitorexit(); + default -> throw new AssertionError("Should not reach here"); + } + } + case NewMultiArrayInstruction i -> { + if (pathSwitch.nextBoolean()) { + cob.multianewarray(i.arrayType().asSymbol(), i.dimensions()); + } else { + cob.multianewarray(i.arrayType(), i.dimensions()); + } + } + case NewObjectInstruction i -> { + if (pathSwitch.nextBoolean()) { + cob.new_(i.className().asSymbol()); + } else { + cob.new_(i.className()); + } + } + case NewPrimitiveArrayInstruction i -> + cob.newarray(i.typeKind()); + case NewReferenceArrayInstruction i -> { + if (pathSwitch.nextBoolean()) { + cob.anewarray(i.componentType().asSymbol()); + } else { + cob.anewarray(i.componentType()); + } + } + case NopInstruction i -> + cob.nop(); + case OperatorInstruction i -> { + switch (i.opcode()) { + case IADD -> cob.iadd(); + case LADD -> cob.ladd(); + case FADD -> cob.fadd(); + case DADD -> cob.dadd(); + case ISUB -> cob.isub(); + case LSUB -> cob.lsub(); + case FSUB -> cob.fsub(); + case DSUB -> cob.dsub(); + case IMUL -> cob.imul(); + case LMUL -> cob.lmul(); + case FMUL -> cob.fmul(); + case DMUL -> cob.dmul(); + case IDIV -> cob.idiv(); + case LDIV -> cob.ldiv(); + case FDIV -> cob.fdiv(); + case DDIV -> cob.ddiv(); + case IREM -> cob.irem(); + case LREM -> cob.lrem(); + case FREM -> cob.frem(); + case DREM -> cob.drem(); + case INEG -> cob.ineg(); + case LNEG -> cob.lneg(); + case FNEG -> cob.fneg(); + case DNEG -> cob.dneg(); + case ISHL -> cob.ishl(); + case LSHL -> cob.lshl(); + case ISHR -> cob.ishr(); + case LSHR -> cob.lshr(); + case IUSHR -> cob.iushr(); + case LUSHR -> cob.lushr(); + case IAND -> cob.iand(); + case LAND -> cob.land(); + case IOR -> cob.ior(); + case LOR -> cob.lor(); + case IXOR -> cob.ixor(); + case LXOR -> cob.lxor(); + case LCMP -> cob.lcmp(); + case FCMPL -> cob.fcmpl(); + case FCMPG -> cob.fcmpg(); + case DCMPL -> cob.dcmpl(); + case DCMPG -> cob.dcmpg(); + case ARRAYLENGTH -> cob.arraylength(); + default -> throw new AssertionError("Should not reach here"); + } + } + case ReturnInstruction i -> { + switch (i.typeKind()) { + case IntType -> cob.ireturn(); + case FloatType -> cob.freturn(); + case LongType -> cob.lreturn(); + case DoubleType -> cob.dreturn(); + case ReferenceType -> cob.areturn(); + case VoidType -> cob.return_(); + default -> throw new AssertionError("Should not reach here"); + } + } + case StackInstruction i -> { + switch (i.opcode()) { + case POP -> cob.pop(); + case POP2 -> cob.pop2(); + case DUP -> cob.dup(); + case DUP_X1 -> cob.dup_x1(); + case DUP_X2 -> cob.dup_x2(); + case DUP2 -> cob.dup2(); + case DUP2_X1 -> cob.dup2_x1(); + case DUP2_X2 -> cob.dup2_x2(); + case SWAP -> cob.swap(); + default -> throw new AssertionError("Should not reach here"); + } + } + case TableSwitchInstruction i -> + cob.tableswitch(i.lowValue(), i.highValue(), + labels.computeIfAbsent(i.defaultTarget(), l -> cob.newLabel()), + i.cases().stream().map(sc -> + SwitchCase.of(sc.caseValue(), labels.computeIfAbsent(sc.target(), l -> cob.newLabel()))).toList()); + case ThrowInstruction i -> cob.athrow(); + case TypeCheckInstruction i -> { + if (pathSwitch.nextBoolean()) { + switch (i.opcode()) { + case CHECKCAST -> cob.checkcast(i.type().asSymbol()); + case INSTANCEOF -> cob.instanceof_(i.type().asSymbol()); + default -> throw new AssertionError("Should not reach here"); + } + } else { + switch (i.opcode()) { + case CHECKCAST -> cob.checkcast(i.type()); + case INSTANCEOF -> cob.instanceof_(i.type()); + default -> throw new AssertionError("Should not reach here"); + } + } + } + case CharacterRange pi -> + cob.characterRange(labels.computeIfAbsent(pi.startScope(), l -> cob.newLabel()), + labels.computeIfAbsent(pi.endScope(), l -> cob.newLabel()), + pi.characterRangeStart(), pi.characterRangeEnd(), pi.flags()); + case ExceptionCatch pi -> + pi.catchType().ifPresentOrElse( + catchType -> cob.exceptionCatch(labels.computeIfAbsent(pi.tryStart(), l -> cob.newLabel()), + labels.computeIfAbsent(pi.tryEnd(), l -> cob.newLabel()), + labels.computeIfAbsent(pi.handler(), l -> cob.newLabel()), + catchType.asSymbol()), + () -> cob.exceptionCatchAll(labels.computeIfAbsent(pi.tryStart(), l -> cob.newLabel()), + labels.computeIfAbsent(pi.tryEnd(), l -> cob.newLabel()), + labels.computeIfAbsent(pi.handler(), l -> cob.newLabel()))); + case LabelTarget pi -> + cob.labelBinding(labels.computeIfAbsent(pi.label(), l -> cob.newLabel())); + case LineNumber pi -> + cob.lineNumber(pi.line()); + case LocalVariable pi -> + cob.localVariable(pi.slot(), pi.name().stringValue(), pi.typeSymbol(), + labels.computeIfAbsent(pi.startScope(), l -> cob.newLabel()), + labels.computeIfAbsent(pi.endScope(), l -> cob.newLabel())); + case LocalVariableType pi -> + cob.localVariableType(pi.slot(), pi.name().stringValue(), + Signature.parseFrom(pi.signatureSymbol().signatureString()), + labels.computeIfAbsent(pi.startScope(), l -> cob.newLabel()), + labels.computeIfAbsent(pi.endScope(), l -> cob.newLabel())); + case RuntimeInvisibleTypeAnnotationsAttribute a -> + cob.with(RuntimeInvisibleTypeAnnotationsAttribute.of(transformTypeAnnotations(a.annotations(), cob, labels))); + case RuntimeVisibleTypeAnnotationsAttribute a -> + cob.with(RuntimeVisibleTypeAnnotationsAttribute.of(transformTypeAnnotations(a.annotations(), cob, labels))); + case StackMapTableAttribute a -> + cob.with(StackMapTableAttribute.of(a.entries().stream().map(fr -> + StackMapFrameInfo.of(labels.computeIfAbsent(fr.target(), l -> cob.newLabel()), + transformFrameTypeInfos(fr.locals(), cob, labels), + transformFrameTypeInfos(fr.stack(), cob, labels))).toList())); + case CustomAttribute a -> + throw new AssertionError("Unexpected custom attribute: " + a.attributeName()); + } + } + } } diff --git a/test/jdk/jdk/incubator/vector/AbstractVectorTest.java b/test/jdk/jdk/incubator/vector/AbstractVectorTest.java index e7d66881d72..9352091bafc 100644 --- a/test/jdk/jdk/incubator/vector/AbstractVectorTest.java +++ b/test/jdk/jdk/incubator/vector/AbstractVectorTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2021, 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 @@ -35,11 +35,13 @@ import java.util.stream.Stream; import java.util.stream.Collectors; +import jdk.test.lib.Utils; + import org.testng.Assert; public class AbstractVectorTest { - static final Random RAND = new Random(Integer.getInteger("jdk.incubator.vector.test.random-seed", 1337)); + static final Random RAND = Utils.getRandomInstance(); interface ToBoolF { boolean apply(int i); diff --git a/test/jdk/jdk/incubator/vector/Byte128VectorLoadStoreTests.java b/test/jdk/jdk/incubator/vector/Byte128VectorLoadStoreTests.java index b95119678fb..ee428120d9d 100644 --- a/test/jdk/jdk/incubator/vector/Byte128VectorLoadStoreTests.java +++ b/test/jdk/jdk/incubator/vector/Byte128VectorLoadStoreTests.java @@ -23,6 +23,9 @@ /* * @test + * @key randomness + * + * @library /test/lib * @modules jdk.incubator.vector java.base/jdk.internal.vm.annotation * @run testng/othervm -XX:-TieredCompilation Byte128VectorLoadStoreTests * diff --git a/test/jdk/jdk/incubator/vector/Byte128VectorTests.java b/test/jdk/jdk/incubator/vector/Byte128VectorTests.java index 65a0acf6dac..11f45b24c8e 100644 --- a/test/jdk/jdk/incubator/vector/Byte128VectorTests.java +++ b/test/jdk/jdk/incubator/vector/Byte128VectorTests.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 @@ -23,6 +23,9 @@ /* * @test + * @key randomness + * + * @library /test/lib * @modules jdk.incubator.vector * @run testng/othervm/timeout=300 -ea -esa -Xbatch -XX:-TieredCompilation Byte128VectorTests */ @@ -4741,7 +4744,7 @@ static byte[] sliceUnary(byte[] a, int origin, int idx) { static void sliceUnaryByte128VectorTests(IntFunction fa) { byte[] a = fa.apply(SPECIES.length()); byte[] r = new byte[a.length]; - int origin = (new java.util.Random()).nextInt(SPECIES.length()); + int origin = RAND.nextInt(SPECIES.length()); for (int ic = 0; ic < INVOC_COUNT; ic++) { for (int i = 0; i < a.length; i += SPECIES.length()) { ByteVector av = ByteVector.fromArray(SPECIES, a, i); @@ -4770,7 +4773,7 @@ static void sliceBinaryByte128VectorTestsBinary(IntFunction fa, IntFunct byte[] a = fa.apply(SPECIES.length()); byte[] b = fb.apply(SPECIES.length()); byte[] r = new byte[a.length]; - int origin = (new java.util.Random()).nextInt(SPECIES.length()); + int origin = RAND.nextInt(SPECIES.length()); for (int ic = 0; ic < INVOC_COUNT; ic++) { for (int i = 0; i < a.length; i += SPECIES.length()) { ByteVector av = ByteVector.fromArray(SPECIES, a, i); @@ -4804,7 +4807,7 @@ static void sliceByte128VectorTestsMasked(IntFunction fa, IntFunction vmask = VectorMask.fromArray(SPECIES, mask, 0); byte[] r = new byte[a.length]; - int origin = (new java.util.Random()).nextInt(SPECIES.length()); + int origin = RAND.nextInt(SPECIES.length()); for (int ic = 0; ic < INVOC_COUNT; ic++) { for (int i = 0; i < a.length; i += SPECIES.length()) { ByteVector av = ByteVector.fromArray(SPECIES, a, i); @@ -4833,7 +4836,7 @@ static byte[] unsliceUnary(byte[] a, int origin, int idx) { static void unsliceUnaryByte128VectorTests(IntFunction fa) { byte[] a = fa.apply(SPECIES.length()); byte[] r = new byte[a.length]; - int origin = (new java.util.Random()).nextInt(SPECIES.length()); + int origin = RAND.nextInt(SPECIES.length()); for (int ic = 0; ic < INVOC_COUNT; ic++) { for (int i = 0; i < a.length; i += SPECIES.length()) { ByteVector av = ByteVector.fromArray(SPECIES, a, i); @@ -4871,8 +4874,8 @@ static void unsliceBinaryByte128VectorTestsBinary(IntFunction fa, IntFun byte[] a = fa.apply(SPECIES.length()); byte[] b = fb.apply(SPECIES.length()); byte[] r = new byte[a.length]; - int origin = (new java.util.Random()).nextInt(SPECIES.length()); - int part = (new java.util.Random()).nextInt(2); + int origin = RAND.nextInt(SPECIES.length()); + int part = RAND.nextInt(2); for (int ic = 0; ic < INVOC_COUNT; ic++) { for (int i = 0; i < a.length; i += SPECIES.length()) { ByteVector av = ByteVector.fromArray(SPECIES, a, i); @@ -4928,8 +4931,8 @@ static void unsliceByte128VectorTestsMasked(IntFunction fa, IntFunction< boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); byte[] r = new byte[a.length]; - int origin = (new java.util.Random()).nextInt(SPECIES.length()); - int part = (new java.util.Random()).nextInt(2); + int origin = RAND.nextInt(SPECIES.length()); + int part = RAND.nextInt(2); for (int ic = 0; ic < INVOC_COUNT; ic++) { for (int i = 0; i < a.length; i += SPECIES.length()) { ByteVector av = ByteVector.fromArray(SPECIES, a, i); diff --git a/test/jdk/jdk/incubator/vector/Byte256VectorLoadStoreTests.java b/test/jdk/jdk/incubator/vector/Byte256VectorLoadStoreTests.java index fac54c8450c..45d7b914776 100644 --- a/test/jdk/jdk/incubator/vector/Byte256VectorLoadStoreTests.java +++ b/test/jdk/jdk/incubator/vector/Byte256VectorLoadStoreTests.java @@ -23,6 +23,9 @@ /* * @test + * @key randomness + * + * @library /test/lib * @modules jdk.incubator.vector java.base/jdk.internal.vm.annotation * @run testng/othervm -XX:-TieredCompilation Byte256VectorLoadStoreTests * diff --git a/test/jdk/jdk/incubator/vector/Byte256VectorTests.java b/test/jdk/jdk/incubator/vector/Byte256VectorTests.java index 87c5f3a39c2..c050ab1daa8 100644 --- a/test/jdk/jdk/incubator/vector/Byte256VectorTests.java +++ b/test/jdk/jdk/incubator/vector/Byte256VectorTests.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 @@ -23,6 +23,9 @@ /* * @test + * @key randomness + * + * @library /test/lib * @modules jdk.incubator.vector * @run testng/othervm/timeout=300 -ea -esa -Xbatch -XX:-TieredCompilation Byte256VectorTests */ @@ -4741,7 +4744,7 @@ static byte[] sliceUnary(byte[] a, int origin, int idx) { static void sliceUnaryByte256VectorTests(IntFunction fa) { byte[] a = fa.apply(SPECIES.length()); byte[] r = new byte[a.length]; - int origin = (new java.util.Random()).nextInt(SPECIES.length()); + int origin = RAND.nextInt(SPECIES.length()); for (int ic = 0; ic < INVOC_COUNT; ic++) { for (int i = 0; i < a.length; i += SPECIES.length()) { ByteVector av = ByteVector.fromArray(SPECIES, a, i); @@ -4770,7 +4773,7 @@ static void sliceBinaryByte256VectorTestsBinary(IntFunction fa, IntFunct byte[] a = fa.apply(SPECIES.length()); byte[] b = fb.apply(SPECIES.length()); byte[] r = new byte[a.length]; - int origin = (new java.util.Random()).nextInt(SPECIES.length()); + int origin = RAND.nextInt(SPECIES.length()); for (int ic = 0; ic < INVOC_COUNT; ic++) { for (int i = 0; i < a.length; i += SPECIES.length()) { ByteVector av = ByteVector.fromArray(SPECIES, a, i); @@ -4804,7 +4807,7 @@ static void sliceByte256VectorTestsMasked(IntFunction fa, IntFunction vmask = VectorMask.fromArray(SPECIES, mask, 0); byte[] r = new byte[a.length]; - int origin = (new java.util.Random()).nextInt(SPECIES.length()); + int origin = RAND.nextInt(SPECIES.length()); for (int ic = 0; ic < INVOC_COUNT; ic++) { for (int i = 0; i < a.length; i += SPECIES.length()) { ByteVector av = ByteVector.fromArray(SPECIES, a, i); @@ -4833,7 +4836,7 @@ static byte[] unsliceUnary(byte[] a, int origin, int idx) { static void unsliceUnaryByte256VectorTests(IntFunction fa) { byte[] a = fa.apply(SPECIES.length()); byte[] r = new byte[a.length]; - int origin = (new java.util.Random()).nextInt(SPECIES.length()); + int origin = RAND.nextInt(SPECIES.length()); for (int ic = 0; ic < INVOC_COUNT; ic++) { for (int i = 0; i < a.length; i += SPECIES.length()) { ByteVector av = ByteVector.fromArray(SPECIES, a, i); @@ -4871,8 +4874,8 @@ static void unsliceBinaryByte256VectorTestsBinary(IntFunction fa, IntFun byte[] a = fa.apply(SPECIES.length()); byte[] b = fb.apply(SPECIES.length()); byte[] r = new byte[a.length]; - int origin = (new java.util.Random()).nextInt(SPECIES.length()); - int part = (new java.util.Random()).nextInt(2); + int origin = RAND.nextInt(SPECIES.length()); + int part = RAND.nextInt(2); for (int ic = 0; ic < INVOC_COUNT; ic++) { for (int i = 0; i < a.length; i += SPECIES.length()) { ByteVector av = ByteVector.fromArray(SPECIES, a, i); @@ -4928,8 +4931,8 @@ static void unsliceByte256VectorTestsMasked(IntFunction fa, IntFunction< boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); byte[] r = new byte[a.length]; - int origin = (new java.util.Random()).nextInt(SPECIES.length()); - int part = (new java.util.Random()).nextInt(2); + int origin = RAND.nextInt(SPECIES.length()); + int part = RAND.nextInt(2); for (int ic = 0; ic < INVOC_COUNT; ic++) { for (int i = 0; i < a.length; i += SPECIES.length()) { ByteVector av = ByteVector.fromArray(SPECIES, a, i); diff --git a/test/jdk/jdk/incubator/vector/Byte512VectorLoadStoreTests.java b/test/jdk/jdk/incubator/vector/Byte512VectorLoadStoreTests.java index 208f543855a..ddbe78b7099 100644 --- a/test/jdk/jdk/incubator/vector/Byte512VectorLoadStoreTests.java +++ b/test/jdk/jdk/incubator/vector/Byte512VectorLoadStoreTests.java @@ -23,6 +23,9 @@ /* * @test + * @key randomness + * + * @library /test/lib * @modules jdk.incubator.vector java.base/jdk.internal.vm.annotation * @run testng/othervm -XX:-TieredCompilation Byte512VectorLoadStoreTests * diff --git a/test/jdk/jdk/incubator/vector/Byte512VectorTests.java b/test/jdk/jdk/incubator/vector/Byte512VectorTests.java index 97e70d2f85d..4498714a170 100644 --- a/test/jdk/jdk/incubator/vector/Byte512VectorTests.java +++ b/test/jdk/jdk/incubator/vector/Byte512VectorTests.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 @@ -23,6 +23,9 @@ /* * @test + * @key randomness + * + * @library /test/lib * @modules jdk.incubator.vector * @run testng/othervm/timeout=300 -ea -esa -Xbatch -XX:-TieredCompilation Byte512VectorTests */ @@ -4741,7 +4744,7 @@ static byte[] sliceUnary(byte[] a, int origin, int idx) { static void sliceUnaryByte512VectorTests(IntFunction fa) { byte[] a = fa.apply(SPECIES.length()); byte[] r = new byte[a.length]; - int origin = (new java.util.Random()).nextInt(SPECIES.length()); + int origin = RAND.nextInt(SPECIES.length()); for (int ic = 0; ic < INVOC_COUNT; ic++) { for (int i = 0; i < a.length; i += SPECIES.length()) { ByteVector av = ByteVector.fromArray(SPECIES, a, i); @@ -4770,7 +4773,7 @@ static void sliceBinaryByte512VectorTestsBinary(IntFunction fa, IntFunct byte[] a = fa.apply(SPECIES.length()); byte[] b = fb.apply(SPECIES.length()); byte[] r = new byte[a.length]; - int origin = (new java.util.Random()).nextInt(SPECIES.length()); + int origin = RAND.nextInt(SPECIES.length()); for (int ic = 0; ic < INVOC_COUNT; ic++) { for (int i = 0; i < a.length; i += SPECIES.length()) { ByteVector av = ByteVector.fromArray(SPECIES, a, i); @@ -4804,7 +4807,7 @@ static void sliceByte512VectorTestsMasked(IntFunction fa, IntFunction vmask = VectorMask.fromArray(SPECIES, mask, 0); byte[] r = new byte[a.length]; - int origin = (new java.util.Random()).nextInt(SPECIES.length()); + int origin = RAND.nextInt(SPECIES.length()); for (int ic = 0; ic < INVOC_COUNT; ic++) { for (int i = 0; i < a.length; i += SPECIES.length()) { ByteVector av = ByteVector.fromArray(SPECIES, a, i); @@ -4833,7 +4836,7 @@ static byte[] unsliceUnary(byte[] a, int origin, int idx) { static void unsliceUnaryByte512VectorTests(IntFunction fa) { byte[] a = fa.apply(SPECIES.length()); byte[] r = new byte[a.length]; - int origin = (new java.util.Random()).nextInt(SPECIES.length()); + int origin = RAND.nextInt(SPECIES.length()); for (int ic = 0; ic < INVOC_COUNT; ic++) { for (int i = 0; i < a.length; i += SPECIES.length()) { ByteVector av = ByteVector.fromArray(SPECIES, a, i); @@ -4871,8 +4874,8 @@ static void unsliceBinaryByte512VectorTestsBinary(IntFunction fa, IntFun byte[] a = fa.apply(SPECIES.length()); byte[] b = fb.apply(SPECIES.length()); byte[] r = new byte[a.length]; - int origin = (new java.util.Random()).nextInt(SPECIES.length()); - int part = (new java.util.Random()).nextInt(2); + int origin = RAND.nextInt(SPECIES.length()); + int part = RAND.nextInt(2); for (int ic = 0; ic < INVOC_COUNT; ic++) { for (int i = 0; i < a.length; i += SPECIES.length()) { ByteVector av = ByteVector.fromArray(SPECIES, a, i); @@ -4928,8 +4931,8 @@ static void unsliceByte512VectorTestsMasked(IntFunction fa, IntFunction< boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); byte[] r = new byte[a.length]; - int origin = (new java.util.Random()).nextInt(SPECIES.length()); - int part = (new java.util.Random()).nextInt(2); + int origin = RAND.nextInt(SPECIES.length()); + int part = RAND.nextInt(2); for (int ic = 0; ic < INVOC_COUNT; ic++) { for (int i = 0; i < a.length; i += SPECIES.length()) { ByteVector av = ByteVector.fromArray(SPECIES, a, i); diff --git a/test/jdk/jdk/incubator/vector/Byte64VectorLoadStoreTests.java b/test/jdk/jdk/incubator/vector/Byte64VectorLoadStoreTests.java index d486fae103c..139ed113963 100644 --- a/test/jdk/jdk/incubator/vector/Byte64VectorLoadStoreTests.java +++ b/test/jdk/jdk/incubator/vector/Byte64VectorLoadStoreTests.java @@ -23,6 +23,9 @@ /* * @test + * @key randomness + * + * @library /test/lib * @modules jdk.incubator.vector java.base/jdk.internal.vm.annotation * @run testng/othervm -XX:-TieredCompilation Byte64VectorLoadStoreTests * diff --git a/test/jdk/jdk/incubator/vector/Byte64VectorTests.java b/test/jdk/jdk/incubator/vector/Byte64VectorTests.java index 92019e6957a..9fb90a5fdd3 100644 --- a/test/jdk/jdk/incubator/vector/Byte64VectorTests.java +++ b/test/jdk/jdk/incubator/vector/Byte64VectorTests.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 @@ -23,6 +23,9 @@ /* * @test + * @key randomness + * + * @library /test/lib * @modules jdk.incubator.vector * @run testng/othervm/timeout=300 -ea -esa -Xbatch -XX:-TieredCompilation Byte64VectorTests */ @@ -4741,7 +4744,7 @@ static byte[] sliceUnary(byte[] a, int origin, int idx) { static void sliceUnaryByte64VectorTests(IntFunction fa) { byte[] a = fa.apply(SPECIES.length()); byte[] r = new byte[a.length]; - int origin = (new java.util.Random()).nextInt(SPECIES.length()); + int origin = RAND.nextInt(SPECIES.length()); for (int ic = 0; ic < INVOC_COUNT; ic++) { for (int i = 0; i < a.length; i += SPECIES.length()) { ByteVector av = ByteVector.fromArray(SPECIES, a, i); @@ -4770,7 +4773,7 @@ static void sliceBinaryByte64VectorTestsBinary(IntFunction fa, IntFuncti byte[] a = fa.apply(SPECIES.length()); byte[] b = fb.apply(SPECIES.length()); byte[] r = new byte[a.length]; - int origin = (new java.util.Random()).nextInt(SPECIES.length()); + int origin = RAND.nextInt(SPECIES.length()); for (int ic = 0; ic < INVOC_COUNT; ic++) { for (int i = 0; i < a.length; i += SPECIES.length()) { ByteVector av = ByteVector.fromArray(SPECIES, a, i); @@ -4804,7 +4807,7 @@ static void sliceByte64VectorTestsMasked(IntFunction fa, IntFunction vmask = VectorMask.fromArray(SPECIES, mask, 0); byte[] r = new byte[a.length]; - int origin = (new java.util.Random()).nextInt(SPECIES.length()); + int origin = RAND.nextInt(SPECIES.length()); for (int ic = 0; ic < INVOC_COUNT; ic++) { for (int i = 0; i < a.length; i += SPECIES.length()) { ByteVector av = ByteVector.fromArray(SPECIES, a, i); @@ -4833,7 +4836,7 @@ static byte[] unsliceUnary(byte[] a, int origin, int idx) { static void unsliceUnaryByte64VectorTests(IntFunction fa) { byte[] a = fa.apply(SPECIES.length()); byte[] r = new byte[a.length]; - int origin = (new java.util.Random()).nextInt(SPECIES.length()); + int origin = RAND.nextInt(SPECIES.length()); for (int ic = 0; ic < INVOC_COUNT; ic++) { for (int i = 0; i < a.length; i += SPECIES.length()) { ByteVector av = ByteVector.fromArray(SPECIES, a, i); @@ -4871,8 +4874,8 @@ static void unsliceBinaryByte64VectorTestsBinary(IntFunction fa, IntFunc byte[] a = fa.apply(SPECIES.length()); byte[] b = fb.apply(SPECIES.length()); byte[] r = new byte[a.length]; - int origin = (new java.util.Random()).nextInt(SPECIES.length()); - int part = (new java.util.Random()).nextInt(2); + int origin = RAND.nextInt(SPECIES.length()); + int part = RAND.nextInt(2); for (int ic = 0; ic < INVOC_COUNT; ic++) { for (int i = 0; i < a.length; i += SPECIES.length()) { ByteVector av = ByteVector.fromArray(SPECIES, a, i); @@ -4928,8 +4931,8 @@ static void unsliceByte64VectorTestsMasked(IntFunction fa, IntFunction vmask = VectorMask.fromArray(SPECIES, mask, 0); byte[] r = new byte[a.length]; - int origin = (new java.util.Random()).nextInt(SPECIES.length()); - int part = (new java.util.Random()).nextInt(2); + int origin = RAND.nextInt(SPECIES.length()); + int part = RAND.nextInt(2); for (int ic = 0; ic < INVOC_COUNT; ic++) { for (int i = 0; i < a.length; i += SPECIES.length()) { ByteVector av = ByteVector.fromArray(SPECIES, a, i); diff --git a/test/jdk/jdk/incubator/vector/ByteMaxVectorLoadStoreTests.java b/test/jdk/jdk/incubator/vector/ByteMaxVectorLoadStoreTests.java index 64e9b8d09dd..3ea2205f515 100644 --- a/test/jdk/jdk/incubator/vector/ByteMaxVectorLoadStoreTests.java +++ b/test/jdk/jdk/incubator/vector/ByteMaxVectorLoadStoreTests.java @@ -23,6 +23,9 @@ /* * @test + * @key randomness + * + * @library /test/lib * @modules jdk.incubator.vector java.base/jdk.internal.vm.annotation * @run testng/othervm --add-opens jdk.incubator.vector/jdk.incubator.vector=ALL-UNNAMED * -XX:-TieredCompilation ByteMaxVectorLoadStoreTests diff --git a/test/jdk/jdk/incubator/vector/ByteMaxVectorTests.java b/test/jdk/jdk/incubator/vector/ByteMaxVectorTests.java index 921b2be725c..44b47293444 100644 --- a/test/jdk/jdk/incubator/vector/ByteMaxVectorTests.java +++ b/test/jdk/jdk/incubator/vector/ByteMaxVectorTests.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 @@ -23,6 +23,9 @@ /* * @test + * @key randomness + * + * @library /test/lib * @modules jdk.incubator.vector * @run testng/othervm/timeout=300 -ea -esa -Xbatch -XX:-TieredCompilation ByteMaxVectorTests */ @@ -4746,7 +4749,7 @@ static byte[] sliceUnary(byte[] a, int origin, int idx) { static void sliceUnaryByteMaxVectorTests(IntFunction fa) { byte[] a = fa.apply(SPECIES.length()); byte[] r = new byte[a.length]; - int origin = (new java.util.Random()).nextInt(SPECIES.length()); + int origin = RAND.nextInt(SPECIES.length()); for (int ic = 0; ic < INVOC_COUNT; ic++) { for (int i = 0; i < a.length; i += SPECIES.length()) { ByteVector av = ByteVector.fromArray(SPECIES, a, i); @@ -4775,7 +4778,7 @@ static void sliceBinaryByteMaxVectorTestsBinary(IntFunction fa, IntFunct byte[] a = fa.apply(SPECIES.length()); byte[] b = fb.apply(SPECIES.length()); byte[] r = new byte[a.length]; - int origin = (new java.util.Random()).nextInt(SPECIES.length()); + int origin = RAND.nextInt(SPECIES.length()); for (int ic = 0; ic < INVOC_COUNT; ic++) { for (int i = 0; i < a.length; i += SPECIES.length()) { ByteVector av = ByteVector.fromArray(SPECIES, a, i); @@ -4809,7 +4812,7 @@ static void sliceByteMaxVectorTestsMasked(IntFunction fa, IntFunction vmask = VectorMask.fromArray(SPECIES, mask, 0); byte[] r = new byte[a.length]; - int origin = (new java.util.Random()).nextInt(SPECIES.length()); + int origin = RAND.nextInt(SPECIES.length()); for (int ic = 0; ic < INVOC_COUNT; ic++) { for (int i = 0; i < a.length; i += SPECIES.length()) { ByteVector av = ByteVector.fromArray(SPECIES, a, i); @@ -4838,7 +4841,7 @@ static byte[] unsliceUnary(byte[] a, int origin, int idx) { static void unsliceUnaryByteMaxVectorTests(IntFunction fa) { byte[] a = fa.apply(SPECIES.length()); byte[] r = new byte[a.length]; - int origin = (new java.util.Random()).nextInt(SPECIES.length()); + int origin = RAND.nextInt(SPECIES.length()); for (int ic = 0; ic < INVOC_COUNT; ic++) { for (int i = 0; i < a.length; i += SPECIES.length()) { ByteVector av = ByteVector.fromArray(SPECIES, a, i); @@ -4876,8 +4879,8 @@ static void unsliceBinaryByteMaxVectorTestsBinary(IntFunction fa, IntFun byte[] a = fa.apply(SPECIES.length()); byte[] b = fb.apply(SPECIES.length()); byte[] r = new byte[a.length]; - int origin = (new java.util.Random()).nextInt(SPECIES.length()); - int part = (new java.util.Random()).nextInt(2); + int origin = RAND.nextInt(SPECIES.length()); + int part = RAND.nextInt(2); for (int ic = 0; ic < INVOC_COUNT; ic++) { for (int i = 0; i < a.length; i += SPECIES.length()) { ByteVector av = ByteVector.fromArray(SPECIES, a, i); @@ -4933,8 +4936,8 @@ static void unsliceByteMaxVectorTestsMasked(IntFunction fa, IntFunction< boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); byte[] r = new byte[a.length]; - int origin = (new java.util.Random()).nextInt(SPECIES.length()); - int part = (new java.util.Random()).nextInt(2); + int origin = RAND.nextInt(SPECIES.length()); + int part = RAND.nextInt(2); for (int ic = 0; ic < INVOC_COUNT; ic++) { for (int i = 0; i < a.length; i += SPECIES.length()) { ByteVector av = ByteVector.fromArray(SPECIES, a, i); diff --git a/test/jdk/jdk/incubator/vector/Double128VectorLoadStoreTests.java b/test/jdk/jdk/incubator/vector/Double128VectorLoadStoreTests.java index e2a18853b31..b1b5726c8cc 100644 --- a/test/jdk/jdk/incubator/vector/Double128VectorLoadStoreTests.java +++ b/test/jdk/jdk/incubator/vector/Double128VectorLoadStoreTests.java @@ -23,6 +23,9 @@ /* * @test + * @key randomness + * + * @library /test/lib * @modules jdk.incubator.vector java.base/jdk.internal.vm.annotation * @run testng/othervm -XX:-TieredCompilation Double128VectorLoadStoreTests * diff --git a/test/jdk/jdk/incubator/vector/Double128VectorTests.java b/test/jdk/jdk/incubator/vector/Double128VectorTests.java index f7c955a08ce..577b1f26912 100644 --- a/test/jdk/jdk/incubator/vector/Double128VectorTests.java +++ b/test/jdk/jdk/incubator/vector/Double128VectorTests.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 @@ -23,6 +23,9 @@ /* * @test + * @key randomness + * + * @library /test/lib * @modules jdk.incubator.vector * @run testng/othervm/timeout=300 -ea -esa -Xbatch -XX:-TieredCompilation Double128VectorTests */ @@ -3547,7 +3550,7 @@ static double[] sliceUnary(double[] a, int origin, int idx) { static void sliceUnaryDouble128VectorTests(IntFunction fa) { double[] a = fa.apply(SPECIES.length()); double[] r = new double[a.length]; - int origin = (new java.util.Random()).nextInt(SPECIES.length()); + int origin = RAND.nextInt(SPECIES.length()); for (int ic = 0; ic < INVOC_COUNT; ic++) { for (int i = 0; i < a.length; i += SPECIES.length()) { DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); @@ -3576,7 +3579,7 @@ static void sliceBinaryDouble128VectorTestsBinary(IntFunction fa, IntF double[] a = fa.apply(SPECIES.length()); double[] b = fb.apply(SPECIES.length()); double[] r = new double[a.length]; - int origin = (new java.util.Random()).nextInt(SPECIES.length()); + int origin = RAND.nextInt(SPECIES.length()); for (int ic = 0; ic < INVOC_COUNT; ic++) { for (int i = 0; i < a.length; i += SPECIES.length()) { DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); @@ -3610,7 +3613,7 @@ static void sliceDouble128VectorTestsMasked(IntFunction fa, IntFunctio VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); double[] r = new double[a.length]; - int origin = (new java.util.Random()).nextInt(SPECIES.length()); + int origin = RAND.nextInt(SPECIES.length()); for (int ic = 0; ic < INVOC_COUNT; ic++) { for (int i = 0; i < a.length; i += SPECIES.length()) { DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); @@ -3639,7 +3642,7 @@ static double[] unsliceUnary(double[] a, int origin, int idx) { static void unsliceUnaryDouble128VectorTests(IntFunction fa) { double[] a = fa.apply(SPECIES.length()); double[] r = new double[a.length]; - int origin = (new java.util.Random()).nextInt(SPECIES.length()); + int origin = RAND.nextInt(SPECIES.length()); for (int ic = 0; ic < INVOC_COUNT; ic++) { for (int i = 0; i < a.length; i += SPECIES.length()) { DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); @@ -3677,8 +3680,8 @@ static void unsliceBinaryDouble128VectorTestsBinary(IntFunction fa, In double[] a = fa.apply(SPECIES.length()); double[] b = fb.apply(SPECIES.length()); double[] r = new double[a.length]; - int origin = (new java.util.Random()).nextInt(SPECIES.length()); - int part = (new java.util.Random()).nextInt(2); + int origin = RAND.nextInt(SPECIES.length()); + int part = RAND.nextInt(2); for (int ic = 0; ic < INVOC_COUNT; ic++) { for (int i = 0; i < a.length; i += SPECIES.length()) { DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); @@ -3734,8 +3737,8 @@ static void unsliceDouble128VectorTestsMasked(IntFunction fa, IntFunct boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); double[] r = new double[a.length]; - int origin = (new java.util.Random()).nextInt(SPECIES.length()); - int part = (new java.util.Random()).nextInt(2); + int origin = RAND.nextInt(SPECIES.length()); + int part = RAND.nextInt(2); for (int ic = 0; ic < INVOC_COUNT; ic++) { for (int i = 0; i < a.length; i += SPECIES.length()) { DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); diff --git a/test/jdk/jdk/incubator/vector/Double256VectorLoadStoreTests.java b/test/jdk/jdk/incubator/vector/Double256VectorLoadStoreTests.java index 9ceb01569b4..96f7602c7c4 100644 --- a/test/jdk/jdk/incubator/vector/Double256VectorLoadStoreTests.java +++ b/test/jdk/jdk/incubator/vector/Double256VectorLoadStoreTests.java @@ -23,6 +23,9 @@ /* * @test + * @key randomness + * + * @library /test/lib * @modules jdk.incubator.vector java.base/jdk.internal.vm.annotation * @run testng/othervm -XX:-TieredCompilation Double256VectorLoadStoreTests * diff --git a/test/jdk/jdk/incubator/vector/Double256VectorTests.java b/test/jdk/jdk/incubator/vector/Double256VectorTests.java index 27f9c0df194..b8ecc5e6e69 100644 --- a/test/jdk/jdk/incubator/vector/Double256VectorTests.java +++ b/test/jdk/jdk/incubator/vector/Double256VectorTests.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 @@ -23,6 +23,9 @@ /* * @test + * @key randomness + * + * @library /test/lib * @modules jdk.incubator.vector * @run testng/othervm/timeout=300 -ea -esa -Xbatch -XX:-TieredCompilation Double256VectorTests */ @@ -3547,7 +3550,7 @@ static double[] sliceUnary(double[] a, int origin, int idx) { static void sliceUnaryDouble256VectorTests(IntFunction fa) { double[] a = fa.apply(SPECIES.length()); double[] r = new double[a.length]; - int origin = (new java.util.Random()).nextInt(SPECIES.length()); + int origin = RAND.nextInt(SPECIES.length()); for (int ic = 0; ic < INVOC_COUNT; ic++) { for (int i = 0; i < a.length; i += SPECIES.length()) { DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); @@ -3576,7 +3579,7 @@ static void sliceBinaryDouble256VectorTestsBinary(IntFunction fa, IntF double[] a = fa.apply(SPECIES.length()); double[] b = fb.apply(SPECIES.length()); double[] r = new double[a.length]; - int origin = (new java.util.Random()).nextInt(SPECIES.length()); + int origin = RAND.nextInt(SPECIES.length()); for (int ic = 0; ic < INVOC_COUNT; ic++) { for (int i = 0; i < a.length; i += SPECIES.length()) { DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); @@ -3610,7 +3613,7 @@ static void sliceDouble256VectorTestsMasked(IntFunction fa, IntFunctio VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); double[] r = new double[a.length]; - int origin = (new java.util.Random()).nextInt(SPECIES.length()); + int origin = RAND.nextInt(SPECIES.length()); for (int ic = 0; ic < INVOC_COUNT; ic++) { for (int i = 0; i < a.length; i += SPECIES.length()) { DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); @@ -3639,7 +3642,7 @@ static double[] unsliceUnary(double[] a, int origin, int idx) { static void unsliceUnaryDouble256VectorTests(IntFunction fa) { double[] a = fa.apply(SPECIES.length()); double[] r = new double[a.length]; - int origin = (new java.util.Random()).nextInt(SPECIES.length()); + int origin = RAND.nextInt(SPECIES.length()); for (int ic = 0; ic < INVOC_COUNT; ic++) { for (int i = 0; i < a.length; i += SPECIES.length()) { DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); @@ -3677,8 +3680,8 @@ static void unsliceBinaryDouble256VectorTestsBinary(IntFunction fa, In double[] a = fa.apply(SPECIES.length()); double[] b = fb.apply(SPECIES.length()); double[] r = new double[a.length]; - int origin = (new java.util.Random()).nextInt(SPECIES.length()); - int part = (new java.util.Random()).nextInt(2); + int origin = RAND.nextInt(SPECIES.length()); + int part = RAND.nextInt(2); for (int ic = 0; ic < INVOC_COUNT; ic++) { for (int i = 0; i < a.length; i += SPECIES.length()) { DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); @@ -3734,8 +3737,8 @@ static void unsliceDouble256VectorTestsMasked(IntFunction fa, IntFunct boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); double[] r = new double[a.length]; - int origin = (new java.util.Random()).nextInt(SPECIES.length()); - int part = (new java.util.Random()).nextInt(2); + int origin = RAND.nextInt(SPECIES.length()); + int part = RAND.nextInt(2); for (int ic = 0; ic < INVOC_COUNT; ic++) { for (int i = 0; i < a.length; i += SPECIES.length()) { DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); diff --git a/test/jdk/jdk/incubator/vector/Double512VectorLoadStoreTests.java b/test/jdk/jdk/incubator/vector/Double512VectorLoadStoreTests.java index d997f19340e..85d41b4ea3d 100644 --- a/test/jdk/jdk/incubator/vector/Double512VectorLoadStoreTests.java +++ b/test/jdk/jdk/incubator/vector/Double512VectorLoadStoreTests.java @@ -23,6 +23,9 @@ /* * @test + * @key randomness + * + * @library /test/lib * @modules jdk.incubator.vector java.base/jdk.internal.vm.annotation * @run testng/othervm -XX:-TieredCompilation Double512VectorLoadStoreTests * diff --git a/test/jdk/jdk/incubator/vector/Double512VectorTests.java b/test/jdk/jdk/incubator/vector/Double512VectorTests.java index 440a553dc33..57e68cb2076 100644 --- a/test/jdk/jdk/incubator/vector/Double512VectorTests.java +++ b/test/jdk/jdk/incubator/vector/Double512VectorTests.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 @@ -23,6 +23,9 @@ /* * @test + * @key randomness + * + * @library /test/lib * @modules jdk.incubator.vector * @run testng/othervm/timeout=300 -ea -esa -Xbatch -XX:-TieredCompilation Double512VectorTests */ @@ -3547,7 +3550,7 @@ static double[] sliceUnary(double[] a, int origin, int idx) { static void sliceUnaryDouble512VectorTests(IntFunction fa) { double[] a = fa.apply(SPECIES.length()); double[] r = new double[a.length]; - int origin = (new java.util.Random()).nextInt(SPECIES.length()); + int origin = RAND.nextInt(SPECIES.length()); for (int ic = 0; ic < INVOC_COUNT; ic++) { for (int i = 0; i < a.length; i += SPECIES.length()) { DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); @@ -3576,7 +3579,7 @@ static void sliceBinaryDouble512VectorTestsBinary(IntFunction fa, IntF double[] a = fa.apply(SPECIES.length()); double[] b = fb.apply(SPECIES.length()); double[] r = new double[a.length]; - int origin = (new java.util.Random()).nextInt(SPECIES.length()); + int origin = RAND.nextInt(SPECIES.length()); for (int ic = 0; ic < INVOC_COUNT; ic++) { for (int i = 0; i < a.length; i += SPECIES.length()) { DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); @@ -3610,7 +3613,7 @@ static void sliceDouble512VectorTestsMasked(IntFunction fa, IntFunctio VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); double[] r = new double[a.length]; - int origin = (new java.util.Random()).nextInt(SPECIES.length()); + int origin = RAND.nextInt(SPECIES.length()); for (int ic = 0; ic < INVOC_COUNT; ic++) { for (int i = 0; i < a.length; i += SPECIES.length()) { DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); @@ -3639,7 +3642,7 @@ static double[] unsliceUnary(double[] a, int origin, int idx) { static void unsliceUnaryDouble512VectorTests(IntFunction fa) { double[] a = fa.apply(SPECIES.length()); double[] r = new double[a.length]; - int origin = (new java.util.Random()).nextInt(SPECIES.length()); + int origin = RAND.nextInt(SPECIES.length()); for (int ic = 0; ic < INVOC_COUNT; ic++) { for (int i = 0; i < a.length; i += SPECIES.length()) { DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); @@ -3677,8 +3680,8 @@ static void unsliceBinaryDouble512VectorTestsBinary(IntFunction fa, In double[] a = fa.apply(SPECIES.length()); double[] b = fb.apply(SPECIES.length()); double[] r = new double[a.length]; - int origin = (new java.util.Random()).nextInt(SPECIES.length()); - int part = (new java.util.Random()).nextInt(2); + int origin = RAND.nextInt(SPECIES.length()); + int part = RAND.nextInt(2); for (int ic = 0; ic < INVOC_COUNT; ic++) { for (int i = 0; i < a.length; i += SPECIES.length()) { DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); @@ -3734,8 +3737,8 @@ static void unsliceDouble512VectorTestsMasked(IntFunction fa, IntFunct boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); double[] r = new double[a.length]; - int origin = (new java.util.Random()).nextInt(SPECIES.length()); - int part = (new java.util.Random()).nextInt(2); + int origin = RAND.nextInt(SPECIES.length()); + int part = RAND.nextInt(2); for (int ic = 0; ic < INVOC_COUNT; ic++) { for (int i = 0; i < a.length; i += SPECIES.length()) { DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); diff --git a/test/jdk/jdk/incubator/vector/Double64VectorLoadStoreTests.java b/test/jdk/jdk/incubator/vector/Double64VectorLoadStoreTests.java index 056fdebafcf..c197ecef8c0 100644 --- a/test/jdk/jdk/incubator/vector/Double64VectorLoadStoreTests.java +++ b/test/jdk/jdk/incubator/vector/Double64VectorLoadStoreTests.java @@ -23,6 +23,9 @@ /* * @test + * @key randomness + * + * @library /test/lib * @modules jdk.incubator.vector java.base/jdk.internal.vm.annotation * @run testng/othervm -XX:-TieredCompilation Double64VectorLoadStoreTests * diff --git a/test/jdk/jdk/incubator/vector/Double64VectorTests.java b/test/jdk/jdk/incubator/vector/Double64VectorTests.java index 73ac9b00c05..04ba2729398 100644 --- a/test/jdk/jdk/incubator/vector/Double64VectorTests.java +++ b/test/jdk/jdk/incubator/vector/Double64VectorTests.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 @@ -23,6 +23,9 @@ /* * @test + * @key randomness + * + * @library /test/lib * @modules jdk.incubator.vector * @run testng/othervm/timeout=300 -ea -esa -Xbatch -XX:-TieredCompilation Double64VectorTests */ @@ -3547,7 +3550,7 @@ static double[] sliceUnary(double[] a, int origin, int idx) { static void sliceUnaryDouble64VectorTests(IntFunction fa) { double[] a = fa.apply(SPECIES.length()); double[] r = new double[a.length]; - int origin = (new java.util.Random()).nextInt(SPECIES.length()); + int origin = RAND.nextInt(SPECIES.length()); for (int ic = 0; ic < INVOC_COUNT; ic++) { for (int i = 0; i < a.length; i += SPECIES.length()) { DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); @@ -3576,7 +3579,7 @@ static void sliceBinaryDouble64VectorTestsBinary(IntFunction fa, IntFu double[] a = fa.apply(SPECIES.length()); double[] b = fb.apply(SPECIES.length()); double[] r = new double[a.length]; - int origin = (new java.util.Random()).nextInt(SPECIES.length()); + int origin = RAND.nextInt(SPECIES.length()); for (int ic = 0; ic < INVOC_COUNT; ic++) { for (int i = 0; i < a.length; i += SPECIES.length()) { DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); @@ -3610,7 +3613,7 @@ static void sliceDouble64VectorTestsMasked(IntFunction fa, IntFunction VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); double[] r = new double[a.length]; - int origin = (new java.util.Random()).nextInt(SPECIES.length()); + int origin = RAND.nextInt(SPECIES.length()); for (int ic = 0; ic < INVOC_COUNT; ic++) { for (int i = 0; i < a.length; i += SPECIES.length()) { DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); @@ -3639,7 +3642,7 @@ static double[] unsliceUnary(double[] a, int origin, int idx) { static void unsliceUnaryDouble64VectorTests(IntFunction fa) { double[] a = fa.apply(SPECIES.length()); double[] r = new double[a.length]; - int origin = (new java.util.Random()).nextInt(SPECIES.length()); + int origin = RAND.nextInt(SPECIES.length()); for (int ic = 0; ic < INVOC_COUNT; ic++) { for (int i = 0; i < a.length; i += SPECIES.length()) { DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); @@ -3677,8 +3680,8 @@ static void unsliceBinaryDouble64VectorTestsBinary(IntFunction fa, Int double[] a = fa.apply(SPECIES.length()); double[] b = fb.apply(SPECIES.length()); double[] r = new double[a.length]; - int origin = (new java.util.Random()).nextInt(SPECIES.length()); - int part = (new java.util.Random()).nextInt(2); + int origin = RAND.nextInt(SPECIES.length()); + int part = RAND.nextInt(2); for (int ic = 0; ic < INVOC_COUNT; ic++) { for (int i = 0; i < a.length; i += SPECIES.length()) { DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); @@ -3734,8 +3737,8 @@ static void unsliceDouble64VectorTestsMasked(IntFunction fa, IntFuncti boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); double[] r = new double[a.length]; - int origin = (new java.util.Random()).nextInt(SPECIES.length()); - int part = (new java.util.Random()).nextInt(2); + int origin = RAND.nextInt(SPECIES.length()); + int part = RAND.nextInt(2); for (int ic = 0; ic < INVOC_COUNT; ic++) { for (int i = 0; i < a.length; i += SPECIES.length()) { DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); diff --git a/test/jdk/jdk/incubator/vector/DoubleMaxVectorLoadStoreTests.java b/test/jdk/jdk/incubator/vector/DoubleMaxVectorLoadStoreTests.java index 69a6525ff99..1b7868a3e3b 100644 --- a/test/jdk/jdk/incubator/vector/DoubleMaxVectorLoadStoreTests.java +++ b/test/jdk/jdk/incubator/vector/DoubleMaxVectorLoadStoreTests.java @@ -23,6 +23,9 @@ /* * @test + * @key randomness + * + * @library /test/lib * @modules jdk.incubator.vector java.base/jdk.internal.vm.annotation * @run testng/othervm --add-opens jdk.incubator.vector/jdk.incubator.vector=ALL-UNNAMED * -XX:-TieredCompilation DoubleMaxVectorLoadStoreTests diff --git a/test/jdk/jdk/incubator/vector/DoubleMaxVectorTests.java b/test/jdk/jdk/incubator/vector/DoubleMaxVectorTests.java index 296e23a7023..474ef0043c9 100644 --- a/test/jdk/jdk/incubator/vector/DoubleMaxVectorTests.java +++ b/test/jdk/jdk/incubator/vector/DoubleMaxVectorTests.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 @@ -23,6 +23,9 @@ /* * @test + * @key randomness + * + * @library /test/lib * @modules jdk.incubator.vector * @run testng/othervm/timeout=300 -ea -esa -Xbatch -XX:-TieredCompilation DoubleMaxVectorTests */ @@ -3552,7 +3555,7 @@ static double[] sliceUnary(double[] a, int origin, int idx) { static void sliceUnaryDoubleMaxVectorTests(IntFunction fa) { double[] a = fa.apply(SPECIES.length()); double[] r = new double[a.length]; - int origin = (new java.util.Random()).nextInt(SPECIES.length()); + int origin = RAND.nextInt(SPECIES.length()); for (int ic = 0; ic < INVOC_COUNT; ic++) { for (int i = 0; i < a.length; i += SPECIES.length()) { DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); @@ -3581,7 +3584,7 @@ static void sliceBinaryDoubleMaxVectorTestsBinary(IntFunction fa, IntF double[] a = fa.apply(SPECIES.length()); double[] b = fb.apply(SPECIES.length()); double[] r = new double[a.length]; - int origin = (new java.util.Random()).nextInt(SPECIES.length()); + int origin = RAND.nextInt(SPECIES.length()); for (int ic = 0; ic < INVOC_COUNT; ic++) { for (int i = 0; i < a.length; i += SPECIES.length()) { DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); @@ -3615,7 +3618,7 @@ static void sliceDoubleMaxVectorTestsMasked(IntFunction fa, IntFunctio VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); double[] r = new double[a.length]; - int origin = (new java.util.Random()).nextInt(SPECIES.length()); + int origin = RAND.nextInt(SPECIES.length()); for (int ic = 0; ic < INVOC_COUNT; ic++) { for (int i = 0; i < a.length; i += SPECIES.length()) { DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); @@ -3644,7 +3647,7 @@ static double[] unsliceUnary(double[] a, int origin, int idx) { static void unsliceUnaryDoubleMaxVectorTests(IntFunction fa) { double[] a = fa.apply(SPECIES.length()); double[] r = new double[a.length]; - int origin = (new java.util.Random()).nextInt(SPECIES.length()); + int origin = RAND.nextInt(SPECIES.length()); for (int ic = 0; ic < INVOC_COUNT; ic++) { for (int i = 0; i < a.length; i += SPECIES.length()) { DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); @@ -3682,8 +3685,8 @@ static void unsliceBinaryDoubleMaxVectorTestsBinary(IntFunction fa, In double[] a = fa.apply(SPECIES.length()); double[] b = fb.apply(SPECIES.length()); double[] r = new double[a.length]; - int origin = (new java.util.Random()).nextInt(SPECIES.length()); - int part = (new java.util.Random()).nextInt(2); + int origin = RAND.nextInt(SPECIES.length()); + int part = RAND.nextInt(2); for (int ic = 0; ic < INVOC_COUNT; ic++) { for (int i = 0; i < a.length; i += SPECIES.length()) { DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); @@ -3739,8 +3742,8 @@ static void unsliceDoubleMaxVectorTestsMasked(IntFunction fa, IntFunct boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); double[] r = new double[a.length]; - int origin = (new java.util.Random()).nextInt(SPECIES.length()); - int part = (new java.util.Random()).nextInt(2); + int origin = RAND.nextInt(SPECIES.length()); + int part = RAND.nextInt(2); for (int ic = 0; ic < INVOC_COUNT; ic++) { for (int i = 0; i < a.length; i += SPECIES.length()) { DoubleVector av = DoubleVector.fromArray(SPECIES, a, i); diff --git a/test/jdk/jdk/incubator/vector/Float128VectorLoadStoreTests.java b/test/jdk/jdk/incubator/vector/Float128VectorLoadStoreTests.java index 6c583c39195..7a9de397eee 100644 --- a/test/jdk/jdk/incubator/vector/Float128VectorLoadStoreTests.java +++ b/test/jdk/jdk/incubator/vector/Float128VectorLoadStoreTests.java @@ -23,6 +23,9 @@ /* * @test + * @key randomness + * + * @library /test/lib * @modules jdk.incubator.vector java.base/jdk.internal.vm.annotation * @run testng/othervm -XX:-TieredCompilation Float128VectorLoadStoreTests * diff --git a/test/jdk/jdk/incubator/vector/Float128VectorTests.java b/test/jdk/jdk/incubator/vector/Float128VectorTests.java index bf61881e3d8..5d503860ee9 100644 --- a/test/jdk/jdk/incubator/vector/Float128VectorTests.java +++ b/test/jdk/jdk/incubator/vector/Float128VectorTests.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 @@ -23,6 +23,9 @@ /* * @test + * @key randomness + * + * @library /test/lib * @modules jdk.incubator.vector * @run testng/othervm/timeout=300 -ea -esa -Xbatch -XX:-TieredCompilation Float128VectorTests */ @@ -3558,7 +3561,7 @@ static float[] sliceUnary(float[] a, int origin, int idx) { static void sliceUnaryFloat128VectorTests(IntFunction fa) { float[] a = fa.apply(SPECIES.length()); float[] r = new float[a.length]; - int origin = (new java.util.Random()).nextInt(SPECIES.length()); + int origin = RAND.nextInt(SPECIES.length()); for (int ic = 0; ic < INVOC_COUNT; ic++) { for (int i = 0; i < a.length; i += SPECIES.length()) { FloatVector av = FloatVector.fromArray(SPECIES, a, i); @@ -3587,7 +3590,7 @@ static void sliceBinaryFloat128VectorTestsBinary(IntFunction fa, IntFun float[] a = fa.apply(SPECIES.length()); float[] b = fb.apply(SPECIES.length()); float[] r = new float[a.length]; - int origin = (new java.util.Random()).nextInt(SPECIES.length()); + int origin = RAND.nextInt(SPECIES.length()); for (int ic = 0; ic < INVOC_COUNT; ic++) { for (int i = 0; i < a.length; i += SPECIES.length()) { FloatVector av = FloatVector.fromArray(SPECIES, a, i); @@ -3621,7 +3624,7 @@ static void sliceFloat128VectorTestsMasked(IntFunction fa, IntFunction< VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); float[] r = new float[a.length]; - int origin = (new java.util.Random()).nextInt(SPECIES.length()); + int origin = RAND.nextInt(SPECIES.length()); for (int ic = 0; ic < INVOC_COUNT; ic++) { for (int i = 0; i < a.length; i += SPECIES.length()) { FloatVector av = FloatVector.fromArray(SPECIES, a, i); @@ -3650,7 +3653,7 @@ static float[] unsliceUnary(float[] a, int origin, int idx) { static void unsliceUnaryFloat128VectorTests(IntFunction fa) { float[] a = fa.apply(SPECIES.length()); float[] r = new float[a.length]; - int origin = (new java.util.Random()).nextInt(SPECIES.length()); + int origin = RAND.nextInt(SPECIES.length()); for (int ic = 0; ic < INVOC_COUNT; ic++) { for (int i = 0; i < a.length; i += SPECIES.length()) { FloatVector av = FloatVector.fromArray(SPECIES, a, i); @@ -3688,8 +3691,8 @@ static void unsliceBinaryFloat128VectorTestsBinary(IntFunction fa, IntF float[] a = fa.apply(SPECIES.length()); float[] b = fb.apply(SPECIES.length()); float[] r = new float[a.length]; - int origin = (new java.util.Random()).nextInt(SPECIES.length()); - int part = (new java.util.Random()).nextInt(2); + int origin = RAND.nextInt(SPECIES.length()); + int part = RAND.nextInt(2); for (int ic = 0; ic < INVOC_COUNT; ic++) { for (int i = 0; i < a.length; i += SPECIES.length()) { FloatVector av = FloatVector.fromArray(SPECIES, a, i); @@ -3745,8 +3748,8 @@ static void unsliceFloat128VectorTestsMasked(IntFunction fa, IntFunctio boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); float[] r = new float[a.length]; - int origin = (new java.util.Random()).nextInt(SPECIES.length()); - int part = (new java.util.Random()).nextInt(2); + int origin = RAND.nextInt(SPECIES.length()); + int part = RAND.nextInt(2); for (int ic = 0; ic < INVOC_COUNT; ic++) { for (int i = 0; i < a.length; i += SPECIES.length()) { FloatVector av = FloatVector.fromArray(SPECIES, a, i); diff --git a/test/jdk/jdk/incubator/vector/Float256VectorLoadStoreTests.java b/test/jdk/jdk/incubator/vector/Float256VectorLoadStoreTests.java index fbb2496bd6e..511674f7a2a 100644 --- a/test/jdk/jdk/incubator/vector/Float256VectorLoadStoreTests.java +++ b/test/jdk/jdk/incubator/vector/Float256VectorLoadStoreTests.java @@ -23,6 +23,9 @@ /* * @test + * @key randomness + * + * @library /test/lib * @modules jdk.incubator.vector java.base/jdk.internal.vm.annotation * @run testng/othervm -XX:-TieredCompilation Float256VectorLoadStoreTests * diff --git a/test/jdk/jdk/incubator/vector/Float256VectorTests.java b/test/jdk/jdk/incubator/vector/Float256VectorTests.java index 7292f55aa6d..7c38b370b12 100644 --- a/test/jdk/jdk/incubator/vector/Float256VectorTests.java +++ b/test/jdk/jdk/incubator/vector/Float256VectorTests.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 @@ -23,6 +23,9 @@ /* * @test + * @key randomness + * + * @library /test/lib * @modules jdk.incubator.vector * @run testng/othervm/timeout=300 -ea -esa -Xbatch -XX:-TieredCompilation Float256VectorTests */ @@ -3558,7 +3561,7 @@ static float[] sliceUnary(float[] a, int origin, int idx) { static void sliceUnaryFloat256VectorTests(IntFunction fa) { float[] a = fa.apply(SPECIES.length()); float[] r = new float[a.length]; - int origin = (new java.util.Random()).nextInt(SPECIES.length()); + int origin = RAND.nextInt(SPECIES.length()); for (int ic = 0; ic < INVOC_COUNT; ic++) { for (int i = 0; i < a.length; i += SPECIES.length()) { FloatVector av = FloatVector.fromArray(SPECIES, a, i); @@ -3587,7 +3590,7 @@ static void sliceBinaryFloat256VectorTestsBinary(IntFunction fa, IntFun float[] a = fa.apply(SPECIES.length()); float[] b = fb.apply(SPECIES.length()); float[] r = new float[a.length]; - int origin = (new java.util.Random()).nextInt(SPECIES.length()); + int origin = RAND.nextInt(SPECIES.length()); for (int ic = 0; ic < INVOC_COUNT; ic++) { for (int i = 0; i < a.length; i += SPECIES.length()) { FloatVector av = FloatVector.fromArray(SPECIES, a, i); @@ -3621,7 +3624,7 @@ static void sliceFloat256VectorTestsMasked(IntFunction fa, IntFunction< VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); float[] r = new float[a.length]; - int origin = (new java.util.Random()).nextInt(SPECIES.length()); + int origin = RAND.nextInt(SPECIES.length()); for (int ic = 0; ic < INVOC_COUNT; ic++) { for (int i = 0; i < a.length; i += SPECIES.length()) { FloatVector av = FloatVector.fromArray(SPECIES, a, i); @@ -3650,7 +3653,7 @@ static float[] unsliceUnary(float[] a, int origin, int idx) { static void unsliceUnaryFloat256VectorTests(IntFunction fa) { float[] a = fa.apply(SPECIES.length()); float[] r = new float[a.length]; - int origin = (new java.util.Random()).nextInt(SPECIES.length()); + int origin = RAND.nextInt(SPECIES.length()); for (int ic = 0; ic < INVOC_COUNT; ic++) { for (int i = 0; i < a.length; i += SPECIES.length()) { FloatVector av = FloatVector.fromArray(SPECIES, a, i); @@ -3688,8 +3691,8 @@ static void unsliceBinaryFloat256VectorTestsBinary(IntFunction fa, IntF float[] a = fa.apply(SPECIES.length()); float[] b = fb.apply(SPECIES.length()); float[] r = new float[a.length]; - int origin = (new java.util.Random()).nextInt(SPECIES.length()); - int part = (new java.util.Random()).nextInt(2); + int origin = RAND.nextInt(SPECIES.length()); + int part = RAND.nextInt(2); for (int ic = 0; ic < INVOC_COUNT; ic++) { for (int i = 0; i < a.length; i += SPECIES.length()) { FloatVector av = FloatVector.fromArray(SPECIES, a, i); @@ -3745,8 +3748,8 @@ static void unsliceFloat256VectorTestsMasked(IntFunction fa, IntFunctio boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); float[] r = new float[a.length]; - int origin = (new java.util.Random()).nextInt(SPECIES.length()); - int part = (new java.util.Random()).nextInt(2); + int origin = RAND.nextInt(SPECIES.length()); + int part = RAND.nextInt(2); for (int ic = 0; ic < INVOC_COUNT; ic++) { for (int i = 0; i < a.length; i += SPECIES.length()) { FloatVector av = FloatVector.fromArray(SPECIES, a, i); diff --git a/test/jdk/jdk/incubator/vector/Float512VectorLoadStoreTests.java b/test/jdk/jdk/incubator/vector/Float512VectorLoadStoreTests.java index adc9b7a89c5..9efcfe31fc7 100644 --- a/test/jdk/jdk/incubator/vector/Float512VectorLoadStoreTests.java +++ b/test/jdk/jdk/incubator/vector/Float512VectorLoadStoreTests.java @@ -23,6 +23,9 @@ /* * @test + * @key randomness + * + * @library /test/lib * @modules jdk.incubator.vector java.base/jdk.internal.vm.annotation * @run testng/othervm -XX:-TieredCompilation Float512VectorLoadStoreTests * diff --git a/test/jdk/jdk/incubator/vector/Float512VectorTests.java b/test/jdk/jdk/incubator/vector/Float512VectorTests.java index 01d1e27209b..70e4e1ea24f 100644 --- a/test/jdk/jdk/incubator/vector/Float512VectorTests.java +++ b/test/jdk/jdk/incubator/vector/Float512VectorTests.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 @@ -23,6 +23,9 @@ /* * @test + * @key randomness + * + * @library /test/lib * @modules jdk.incubator.vector * @run testng/othervm/timeout=300 -ea -esa -Xbatch -XX:-TieredCompilation Float512VectorTests */ @@ -3558,7 +3561,7 @@ static float[] sliceUnary(float[] a, int origin, int idx) { static void sliceUnaryFloat512VectorTests(IntFunction fa) { float[] a = fa.apply(SPECIES.length()); float[] r = new float[a.length]; - int origin = (new java.util.Random()).nextInt(SPECIES.length()); + int origin = RAND.nextInt(SPECIES.length()); for (int ic = 0; ic < INVOC_COUNT; ic++) { for (int i = 0; i < a.length; i += SPECIES.length()) { FloatVector av = FloatVector.fromArray(SPECIES, a, i); @@ -3587,7 +3590,7 @@ static void sliceBinaryFloat512VectorTestsBinary(IntFunction fa, IntFun float[] a = fa.apply(SPECIES.length()); float[] b = fb.apply(SPECIES.length()); float[] r = new float[a.length]; - int origin = (new java.util.Random()).nextInt(SPECIES.length()); + int origin = RAND.nextInt(SPECIES.length()); for (int ic = 0; ic < INVOC_COUNT; ic++) { for (int i = 0; i < a.length; i += SPECIES.length()) { FloatVector av = FloatVector.fromArray(SPECIES, a, i); @@ -3621,7 +3624,7 @@ static void sliceFloat512VectorTestsMasked(IntFunction fa, IntFunction< VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); float[] r = new float[a.length]; - int origin = (new java.util.Random()).nextInt(SPECIES.length()); + int origin = RAND.nextInt(SPECIES.length()); for (int ic = 0; ic < INVOC_COUNT; ic++) { for (int i = 0; i < a.length; i += SPECIES.length()) { FloatVector av = FloatVector.fromArray(SPECIES, a, i); @@ -3650,7 +3653,7 @@ static float[] unsliceUnary(float[] a, int origin, int idx) { static void unsliceUnaryFloat512VectorTests(IntFunction fa) { float[] a = fa.apply(SPECIES.length()); float[] r = new float[a.length]; - int origin = (new java.util.Random()).nextInt(SPECIES.length()); + int origin = RAND.nextInt(SPECIES.length()); for (int ic = 0; ic < INVOC_COUNT; ic++) { for (int i = 0; i < a.length; i += SPECIES.length()) { FloatVector av = FloatVector.fromArray(SPECIES, a, i); @@ -3688,8 +3691,8 @@ static void unsliceBinaryFloat512VectorTestsBinary(IntFunction fa, IntF float[] a = fa.apply(SPECIES.length()); float[] b = fb.apply(SPECIES.length()); float[] r = new float[a.length]; - int origin = (new java.util.Random()).nextInt(SPECIES.length()); - int part = (new java.util.Random()).nextInt(2); + int origin = RAND.nextInt(SPECIES.length()); + int part = RAND.nextInt(2); for (int ic = 0; ic < INVOC_COUNT; ic++) { for (int i = 0; i < a.length; i += SPECIES.length()) { FloatVector av = FloatVector.fromArray(SPECIES, a, i); @@ -3745,8 +3748,8 @@ static void unsliceFloat512VectorTestsMasked(IntFunction fa, IntFunctio boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); float[] r = new float[a.length]; - int origin = (new java.util.Random()).nextInt(SPECIES.length()); - int part = (new java.util.Random()).nextInt(2); + int origin = RAND.nextInt(SPECIES.length()); + int part = RAND.nextInt(2); for (int ic = 0; ic < INVOC_COUNT; ic++) { for (int i = 0; i < a.length; i += SPECIES.length()) { FloatVector av = FloatVector.fromArray(SPECIES, a, i); diff --git a/test/jdk/jdk/incubator/vector/Float64VectorLoadStoreTests.java b/test/jdk/jdk/incubator/vector/Float64VectorLoadStoreTests.java index e9d042c53c5..e1aa2f34cb1 100644 --- a/test/jdk/jdk/incubator/vector/Float64VectorLoadStoreTests.java +++ b/test/jdk/jdk/incubator/vector/Float64VectorLoadStoreTests.java @@ -23,6 +23,9 @@ /* * @test + * @key randomness + * + * @library /test/lib * @modules jdk.incubator.vector java.base/jdk.internal.vm.annotation * @run testng/othervm -XX:-TieredCompilation Float64VectorLoadStoreTests * diff --git a/test/jdk/jdk/incubator/vector/Float64VectorTests.java b/test/jdk/jdk/incubator/vector/Float64VectorTests.java index b7fd8ab2767..65a71504561 100644 --- a/test/jdk/jdk/incubator/vector/Float64VectorTests.java +++ b/test/jdk/jdk/incubator/vector/Float64VectorTests.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 @@ -23,6 +23,9 @@ /* * @test + * @key randomness + * + * @library /test/lib * @modules jdk.incubator.vector * @run testng/othervm/timeout=300 -ea -esa -Xbatch -XX:-TieredCompilation Float64VectorTests */ @@ -3558,7 +3561,7 @@ static float[] sliceUnary(float[] a, int origin, int idx) { static void sliceUnaryFloat64VectorTests(IntFunction fa) { float[] a = fa.apply(SPECIES.length()); float[] r = new float[a.length]; - int origin = (new java.util.Random()).nextInt(SPECIES.length()); + int origin = RAND.nextInt(SPECIES.length()); for (int ic = 0; ic < INVOC_COUNT; ic++) { for (int i = 0; i < a.length; i += SPECIES.length()) { FloatVector av = FloatVector.fromArray(SPECIES, a, i); @@ -3587,7 +3590,7 @@ static void sliceBinaryFloat64VectorTestsBinary(IntFunction fa, IntFunc float[] a = fa.apply(SPECIES.length()); float[] b = fb.apply(SPECIES.length()); float[] r = new float[a.length]; - int origin = (new java.util.Random()).nextInt(SPECIES.length()); + int origin = RAND.nextInt(SPECIES.length()); for (int ic = 0; ic < INVOC_COUNT; ic++) { for (int i = 0; i < a.length; i += SPECIES.length()) { FloatVector av = FloatVector.fromArray(SPECIES, a, i); @@ -3621,7 +3624,7 @@ static void sliceFloat64VectorTestsMasked(IntFunction fa, IntFunction vmask = VectorMask.fromArray(SPECIES, mask, 0); float[] r = new float[a.length]; - int origin = (new java.util.Random()).nextInt(SPECIES.length()); + int origin = RAND.nextInt(SPECIES.length()); for (int ic = 0; ic < INVOC_COUNT; ic++) { for (int i = 0; i < a.length; i += SPECIES.length()) { FloatVector av = FloatVector.fromArray(SPECIES, a, i); @@ -3650,7 +3653,7 @@ static float[] unsliceUnary(float[] a, int origin, int idx) { static void unsliceUnaryFloat64VectorTests(IntFunction fa) { float[] a = fa.apply(SPECIES.length()); float[] r = new float[a.length]; - int origin = (new java.util.Random()).nextInt(SPECIES.length()); + int origin = RAND.nextInt(SPECIES.length()); for (int ic = 0; ic < INVOC_COUNT; ic++) { for (int i = 0; i < a.length; i += SPECIES.length()) { FloatVector av = FloatVector.fromArray(SPECIES, a, i); @@ -3688,8 +3691,8 @@ static void unsliceBinaryFloat64VectorTestsBinary(IntFunction fa, IntFu float[] a = fa.apply(SPECIES.length()); float[] b = fb.apply(SPECIES.length()); float[] r = new float[a.length]; - int origin = (new java.util.Random()).nextInt(SPECIES.length()); - int part = (new java.util.Random()).nextInt(2); + int origin = RAND.nextInt(SPECIES.length()); + int part = RAND.nextInt(2); for (int ic = 0; ic < INVOC_COUNT; ic++) { for (int i = 0; i < a.length; i += SPECIES.length()) { FloatVector av = FloatVector.fromArray(SPECIES, a, i); @@ -3745,8 +3748,8 @@ static void unsliceFloat64VectorTestsMasked(IntFunction fa, IntFunction boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); float[] r = new float[a.length]; - int origin = (new java.util.Random()).nextInt(SPECIES.length()); - int part = (new java.util.Random()).nextInt(2); + int origin = RAND.nextInt(SPECIES.length()); + int part = RAND.nextInt(2); for (int ic = 0; ic < INVOC_COUNT; ic++) { for (int i = 0; i < a.length; i += SPECIES.length()) { FloatVector av = FloatVector.fromArray(SPECIES, a, i); diff --git a/test/jdk/jdk/incubator/vector/FloatMaxVectorLoadStoreTests.java b/test/jdk/jdk/incubator/vector/FloatMaxVectorLoadStoreTests.java index 844942e2010..ff9d0e67202 100644 --- a/test/jdk/jdk/incubator/vector/FloatMaxVectorLoadStoreTests.java +++ b/test/jdk/jdk/incubator/vector/FloatMaxVectorLoadStoreTests.java @@ -23,6 +23,9 @@ /* * @test + * @key randomness + * + * @library /test/lib * @modules jdk.incubator.vector java.base/jdk.internal.vm.annotation * @run testng/othervm --add-opens jdk.incubator.vector/jdk.incubator.vector=ALL-UNNAMED * -XX:-TieredCompilation FloatMaxVectorLoadStoreTests diff --git a/test/jdk/jdk/incubator/vector/FloatMaxVectorTests.java b/test/jdk/jdk/incubator/vector/FloatMaxVectorTests.java index 5592f5985b0..f6b05fb6bc7 100644 --- a/test/jdk/jdk/incubator/vector/FloatMaxVectorTests.java +++ b/test/jdk/jdk/incubator/vector/FloatMaxVectorTests.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 @@ -23,6 +23,9 @@ /* * @test + * @key randomness + * + * @library /test/lib * @modules jdk.incubator.vector * @run testng/othervm/timeout=300 -ea -esa -Xbatch -XX:-TieredCompilation FloatMaxVectorTests */ @@ -3563,7 +3566,7 @@ static float[] sliceUnary(float[] a, int origin, int idx) { static void sliceUnaryFloatMaxVectorTests(IntFunction fa) { float[] a = fa.apply(SPECIES.length()); float[] r = new float[a.length]; - int origin = (new java.util.Random()).nextInt(SPECIES.length()); + int origin = RAND.nextInt(SPECIES.length()); for (int ic = 0; ic < INVOC_COUNT; ic++) { for (int i = 0; i < a.length; i += SPECIES.length()) { FloatVector av = FloatVector.fromArray(SPECIES, a, i); @@ -3592,7 +3595,7 @@ static void sliceBinaryFloatMaxVectorTestsBinary(IntFunction fa, IntFun float[] a = fa.apply(SPECIES.length()); float[] b = fb.apply(SPECIES.length()); float[] r = new float[a.length]; - int origin = (new java.util.Random()).nextInt(SPECIES.length()); + int origin = RAND.nextInt(SPECIES.length()); for (int ic = 0; ic < INVOC_COUNT; ic++) { for (int i = 0; i < a.length; i += SPECIES.length()) { FloatVector av = FloatVector.fromArray(SPECIES, a, i); @@ -3626,7 +3629,7 @@ static void sliceFloatMaxVectorTestsMasked(IntFunction fa, IntFunction< VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); float[] r = new float[a.length]; - int origin = (new java.util.Random()).nextInt(SPECIES.length()); + int origin = RAND.nextInt(SPECIES.length()); for (int ic = 0; ic < INVOC_COUNT; ic++) { for (int i = 0; i < a.length; i += SPECIES.length()) { FloatVector av = FloatVector.fromArray(SPECIES, a, i); @@ -3655,7 +3658,7 @@ static float[] unsliceUnary(float[] a, int origin, int idx) { static void unsliceUnaryFloatMaxVectorTests(IntFunction fa) { float[] a = fa.apply(SPECIES.length()); float[] r = new float[a.length]; - int origin = (new java.util.Random()).nextInt(SPECIES.length()); + int origin = RAND.nextInt(SPECIES.length()); for (int ic = 0; ic < INVOC_COUNT; ic++) { for (int i = 0; i < a.length; i += SPECIES.length()) { FloatVector av = FloatVector.fromArray(SPECIES, a, i); @@ -3693,8 +3696,8 @@ static void unsliceBinaryFloatMaxVectorTestsBinary(IntFunction fa, IntF float[] a = fa.apply(SPECIES.length()); float[] b = fb.apply(SPECIES.length()); float[] r = new float[a.length]; - int origin = (new java.util.Random()).nextInt(SPECIES.length()); - int part = (new java.util.Random()).nextInt(2); + int origin = RAND.nextInt(SPECIES.length()); + int part = RAND.nextInt(2); for (int ic = 0; ic < INVOC_COUNT; ic++) { for (int i = 0; i < a.length; i += SPECIES.length()) { FloatVector av = FloatVector.fromArray(SPECIES, a, i); @@ -3750,8 +3753,8 @@ static void unsliceFloatMaxVectorTestsMasked(IntFunction fa, IntFunctio boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); float[] r = new float[a.length]; - int origin = (new java.util.Random()).nextInt(SPECIES.length()); - int part = (new java.util.Random()).nextInt(2); + int origin = RAND.nextInt(SPECIES.length()); + int part = RAND.nextInt(2); for (int ic = 0; ic < INVOC_COUNT; ic++) { for (int i = 0; i < a.length; i += SPECIES.length()) { FloatVector av = FloatVector.fromArray(SPECIES, a, i); diff --git a/test/jdk/jdk/incubator/vector/Int128VectorLoadStoreTests.java b/test/jdk/jdk/incubator/vector/Int128VectorLoadStoreTests.java index 9e6d82510e1..fc678965d0f 100644 --- a/test/jdk/jdk/incubator/vector/Int128VectorLoadStoreTests.java +++ b/test/jdk/jdk/incubator/vector/Int128VectorLoadStoreTests.java @@ -23,6 +23,9 @@ /* * @test + * @key randomness + * + * @library /test/lib * @modules jdk.incubator.vector java.base/jdk.internal.vm.annotation * @run testng/othervm -XX:-TieredCompilation Int128VectorLoadStoreTests * diff --git a/test/jdk/jdk/incubator/vector/Int128VectorTests.java b/test/jdk/jdk/incubator/vector/Int128VectorTests.java index fcfe286034d..25d656af7da 100644 --- a/test/jdk/jdk/incubator/vector/Int128VectorTests.java +++ b/test/jdk/jdk/incubator/vector/Int128VectorTests.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 @@ -23,6 +23,9 @@ /* * @test + * @key randomness + * + * @library /test/lib * @modules jdk.incubator.vector * @run testng/othervm/timeout=300 -ea -esa -Xbatch -XX:-TieredCompilation Int128VectorTests */ @@ -4785,7 +4788,7 @@ static int[] sliceUnary(int[] a, int origin, int idx) { static void sliceUnaryInt128VectorTests(IntFunction fa) { int[] a = fa.apply(SPECIES.length()); int[] r = new int[a.length]; - int origin = (new java.util.Random()).nextInt(SPECIES.length()); + int origin = RAND.nextInt(SPECIES.length()); for (int ic = 0; ic < INVOC_COUNT; ic++) { for (int i = 0; i < a.length; i += SPECIES.length()) { IntVector av = IntVector.fromArray(SPECIES, a, i); @@ -4814,7 +4817,7 @@ static void sliceBinaryInt128VectorTestsBinary(IntFunction fa, IntFunctio int[] a = fa.apply(SPECIES.length()); int[] b = fb.apply(SPECIES.length()); int[] r = new int[a.length]; - int origin = (new java.util.Random()).nextInt(SPECIES.length()); + int origin = RAND.nextInt(SPECIES.length()); for (int ic = 0; ic < INVOC_COUNT; ic++) { for (int i = 0; i < a.length; i += SPECIES.length()) { IntVector av = IntVector.fromArray(SPECIES, a, i); @@ -4848,7 +4851,7 @@ static void sliceInt128VectorTestsMasked(IntFunction fa, IntFunction vmask = VectorMask.fromArray(SPECIES, mask, 0); int[] r = new int[a.length]; - int origin = (new java.util.Random()).nextInt(SPECIES.length()); + int origin = RAND.nextInt(SPECIES.length()); for (int ic = 0; ic < INVOC_COUNT; ic++) { for (int i = 0; i < a.length; i += SPECIES.length()) { IntVector av = IntVector.fromArray(SPECIES, a, i); @@ -4877,7 +4880,7 @@ static int[] unsliceUnary(int[] a, int origin, int idx) { static void unsliceUnaryInt128VectorTests(IntFunction fa) { int[] a = fa.apply(SPECIES.length()); int[] r = new int[a.length]; - int origin = (new java.util.Random()).nextInt(SPECIES.length()); + int origin = RAND.nextInt(SPECIES.length()); for (int ic = 0; ic < INVOC_COUNT; ic++) { for (int i = 0; i < a.length; i += SPECIES.length()) { IntVector av = IntVector.fromArray(SPECIES, a, i); @@ -4915,8 +4918,8 @@ static void unsliceBinaryInt128VectorTestsBinary(IntFunction fa, IntFunct int[] a = fa.apply(SPECIES.length()); int[] b = fb.apply(SPECIES.length()); int[] r = new int[a.length]; - int origin = (new java.util.Random()).nextInt(SPECIES.length()); - int part = (new java.util.Random()).nextInt(2); + int origin = RAND.nextInt(SPECIES.length()); + int part = RAND.nextInt(2); for (int ic = 0; ic < INVOC_COUNT; ic++) { for (int i = 0; i < a.length; i += SPECIES.length()) { IntVector av = IntVector.fromArray(SPECIES, a, i); @@ -4972,8 +4975,8 @@ static void unsliceInt128VectorTestsMasked(IntFunction fa, IntFunction vmask = VectorMask.fromArray(SPECIES, mask, 0); int[] r = new int[a.length]; - int origin = (new java.util.Random()).nextInt(SPECIES.length()); - int part = (new java.util.Random()).nextInt(2); + int origin = RAND.nextInt(SPECIES.length()); + int part = RAND.nextInt(2); for (int ic = 0; ic < INVOC_COUNT; ic++) { for (int i = 0; i < a.length; i += SPECIES.length()) { IntVector av = IntVector.fromArray(SPECIES, a, i); diff --git a/test/jdk/jdk/incubator/vector/Int256VectorLoadStoreTests.java b/test/jdk/jdk/incubator/vector/Int256VectorLoadStoreTests.java index b90b0a42d10..85027d700d2 100644 --- a/test/jdk/jdk/incubator/vector/Int256VectorLoadStoreTests.java +++ b/test/jdk/jdk/incubator/vector/Int256VectorLoadStoreTests.java @@ -23,6 +23,9 @@ /* * @test + * @key randomness + * + * @library /test/lib * @modules jdk.incubator.vector java.base/jdk.internal.vm.annotation * @run testng/othervm -XX:-TieredCompilation Int256VectorLoadStoreTests * diff --git a/test/jdk/jdk/incubator/vector/Int256VectorTests.java b/test/jdk/jdk/incubator/vector/Int256VectorTests.java index 64cad182a24..7420c7842d5 100644 --- a/test/jdk/jdk/incubator/vector/Int256VectorTests.java +++ b/test/jdk/jdk/incubator/vector/Int256VectorTests.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 @@ -23,6 +23,9 @@ /* * @test + * @key randomness + * + * @library /test/lib * @modules jdk.incubator.vector * @run testng/othervm/timeout=300 -ea -esa -Xbatch -XX:-TieredCompilation Int256VectorTests */ @@ -4785,7 +4788,7 @@ static int[] sliceUnary(int[] a, int origin, int idx) { static void sliceUnaryInt256VectorTests(IntFunction fa) { int[] a = fa.apply(SPECIES.length()); int[] r = new int[a.length]; - int origin = (new java.util.Random()).nextInt(SPECIES.length()); + int origin = RAND.nextInt(SPECIES.length()); for (int ic = 0; ic < INVOC_COUNT; ic++) { for (int i = 0; i < a.length; i += SPECIES.length()) { IntVector av = IntVector.fromArray(SPECIES, a, i); @@ -4814,7 +4817,7 @@ static void sliceBinaryInt256VectorTestsBinary(IntFunction fa, IntFunctio int[] a = fa.apply(SPECIES.length()); int[] b = fb.apply(SPECIES.length()); int[] r = new int[a.length]; - int origin = (new java.util.Random()).nextInt(SPECIES.length()); + int origin = RAND.nextInt(SPECIES.length()); for (int ic = 0; ic < INVOC_COUNT; ic++) { for (int i = 0; i < a.length; i += SPECIES.length()) { IntVector av = IntVector.fromArray(SPECIES, a, i); @@ -4848,7 +4851,7 @@ static void sliceInt256VectorTestsMasked(IntFunction fa, IntFunction vmask = VectorMask.fromArray(SPECIES, mask, 0); int[] r = new int[a.length]; - int origin = (new java.util.Random()).nextInt(SPECIES.length()); + int origin = RAND.nextInt(SPECIES.length()); for (int ic = 0; ic < INVOC_COUNT; ic++) { for (int i = 0; i < a.length; i += SPECIES.length()) { IntVector av = IntVector.fromArray(SPECIES, a, i); @@ -4877,7 +4880,7 @@ static int[] unsliceUnary(int[] a, int origin, int idx) { static void unsliceUnaryInt256VectorTests(IntFunction fa) { int[] a = fa.apply(SPECIES.length()); int[] r = new int[a.length]; - int origin = (new java.util.Random()).nextInt(SPECIES.length()); + int origin = RAND.nextInt(SPECIES.length()); for (int ic = 0; ic < INVOC_COUNT; ic++) { for (int i = 0; i < a.length; i += SPECIES.length()) { IntVector av = IntVector.fromArray(SPECIES, a, i); @@ -4915,8 +4918,8 @@ static void unsliceBinaryInt256VectorTestsBinary(IntFunction fa, IntFunct int[] a = fa.apply(SPECIES.length()); int[] b = fb.apply(SPECIES.length()); int[] r = new int[a.length]; - int origin = (new java.util.Random()).nextInt(SPECIES.length()); - int part = (new java.util.Random()).nextInt(2); + int origin = RAND.nextInt(SPECIES.length()); + int part = RAND.nextInt(2); for (int ic = 0; ic < INVOC_COUNT; ic++) { for (int i = 0; i < a.length; i += SPECIES.length()) { IntVector av = IntVector.fromArray(SPECIES, a, i); @@ -4972,8 +4975,8 @@ static void unsliceInt256VectorTestsMasked(IntFunction fa, IntFunction vmask = VectorMask.fromArray(SPECIES, mask, 0); int[] r = new int[a.length]; - int origin = (new java.util.Random()).nextInt(SPECIES.length()); - int part = (new java.util.Random()).nextInt(2); + int origin = RAND.nextInt(SPECIES.length()); + int part = RAND.nextInt(2); for (int ic = 0; ic < INVOC_COUNT; ic++) { for (int i = 0; i < a.length; i += SPECIES.length()) { IntVector av = IntVector.fromArray(SPECIES, a, i); diff --git a/test/jdk/jdk/incubator/vector/Int512VectorLoadStoreTests.java b/test/jdk/jdk/incubator/vector/Int512VectorLoadStoreTests.java index 424d4b63fcb..f9b72103107 100644 --- a/test/jdk/jdk/incubator/vector/Int512VectorLoadStoreTests.java +++ b/test/jdk/jdk/incubator/vector/Int512VectorLoadStoreTests.java @@ -23,6 +23,9 @@ /* * @test + * @key randomness + * + * @library /test/lib * @modules jdk.incubator.vector java.base/jdk.internal.vm.annotation * @run testng/othervm -XX:-TieredCompilation Int512VectorLoadStoreTests * diff --git a/test/jdk/jdk/incubator/vector/Int512VectorTests.java b/test/jdk/jdk/incubator/vector/Int512VectorTests.java index 468a2c3a8f1..ccd2bb7a5c9 100644 --- a/test/jdk/jdk/incubator/vector/Int512VectorTests.java +++ b/test/jdk/jdk/incubator/vector/Int512VectorTests.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 @@ -23,6 +23,9 @@ /* * @test + * @key randomness + * + * @library /test/lib * @modules jdk.incubator.vector * @run testng/othervm/timeout=300 -ea -esa -Xbatch -XX:-TieredCompilation Int512VectorTests */ @@ -4785,7 +4788,7 @@ static int[] sliceUnary(int[] a, int origin, int idx) { static void sliceUnaryInt512VectorTests(IntFunction fa) { int[] a = fa.apply(SPECIES.length()); int[] r = new int[a.length]; - int origin = (new java.util.Random()).nextInt(SPECIES.length()); + int origin = RAND.nextInt(SPECIES.length()); for (int ic = 0; ic < INVOC_COUNT; ic++) { for (int i = 0; i < a.length; i += SPECIES.length()) { IntVector av = IntVector.fromArray(SPECIES, a, i); @@ -4814,7 +4817,7 @@ static void sliceBinaryInt512VectorTestsBinary(IntFunction fa, IntFunctio int[] a = fa.apply(SPECIES.length()); int[] b = fb.apply(SPECIES.length()); int[] r = new int[a.length]; - int origin = (new java.util.Random()).nextInt(SPECIES.length()); + int origin = RAND.nextInt(SPECIES.length()); for (int ic = 0; ic < INVOC_COUNT; ic++) { for (int i = 0; i < a.length; i += SPECIES.length()) { IntVector av = IntVector.fromArray(SPECIES, a, i); @@ -4848,7 +4851,7 @@ static void sliceInt512VectorTestsMasked(IntFunction fa, IntFunction vmask = VectorMask.fromArray(SPECIES, mask, 0); int[] r = new int[a.length]; - int origin = (new java.util.Random()).nextInt(SPECIES.length()); + int origin = RAND.nextInt(SPECIES.length()); for (int ic = 0; ic < INVOC_COUNT; ic++) { for (int i = 0; i < a.length; i += SPECIES.length()) { IntVector av = IntVector.fromArray(SPECIES, a, i); @@ -4877,7 +4880,7 @@ static int[] unsliceUnary(int[] a, int origin, int idx) { static void unsliceUnaryInt512VectorTests(IntFunction fa) { int[] a = fa.apply(SPECIES.length()); int[] r = new int[a.length]; - int origin = (new java.util.Random()).nextInt(SPECIES.length()); + int origin = RAND.nextInt(SPECIES.length()); for (int ic = 0; ic < INVOC_COUNT; ic++) { for (int i = 0; i < a.length; i += SPECIES.length()) { IntVector av = IntVector.fromArray(SPECIES, a, i); @@ -4915,8 +4918,8 @@ static void unsliceBinaryInt512VectorTestsBinary(IntFunction fa, IntFunct int[] a = fa.apply(SPECIES.length()); int[] b = fb.apply(SPECIES.length()); int[] r = new int[a.length]; - int origin = (new java.util.Random()).nextInt(SPECIES.length()); - int part = (new java.util.Random()).nextInt(2); + int origin = RAND.nextInt(SPECIES.length()); + int part = RAND.nextInt(2); for (int ic = 0; ic < INVOC_COUNT; ic++) { for (int i = 0; i < a.length; i += SPECIES.length()) { IntVector av = IntVector.fromArray(SPECIES, a, i); @@ -4972,8 +4975,8 @@ static void unsliceInt512VectorTestsMasked(IntFunction fa, IntFunction vmask = VectorMask.fromArray(SPECIES, mask, 0); int[] r = new int[a.length]; - int origin = (new java.util.Random()).nextInt(SPECIES.length()); - int part = (new java.util.Random()).nextInt(2); + int origin = RAND.nextInt(SPECIES.length()); + int part = RAND.nextInt(2); for (int ic = 0; ic < INVOC_COUNT; ic++) { for (int i = 0; i < a.length; i += SPECIES.length()) { IntVector av = IntVector.fromArray(SPECIES, a, i); diff --git a/test/jdk/jdk/incubator/vector/Int64VectorLoadStoreTests.java b/test/jdk/jdk/incubator/vector/Int64VectorLoadStoreTests.java index e1abfdcccd9..6dc2bb1a504 100644 --- a/test/jdk/jdk/incubator/vector/Int64VectorLoadStoreTests.java +++ b/test/jdk/jdk/incubator/vector/Int64VectorLoadStoreTests.java @@ -23,6 +23,9 @@ /* * @test + * @key randomness + * + * @library /test/lib * @modules jdk.incubator.vector java.base/jdk.internal.vm.annotation * @run testng/othervm -XX:-TieredCompilation Int64VectorLoadStoreTests * diff --git a/test/jdk/jdk/incubator/vector/Int64VectorTests.java b/test/jdk/jdk/incubator/vector/Int64VectorTests.java index 14b853c1e72..26201745ad4 100644 --- a/test/jdk/jdk/incubator/vector/Int64VectorTests.java +++ b/test/jdk/jdk/incubator/vector/Int64VectorTests.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 @@ -23,6 +23,9 @@ /* * @test + * @key randomness + * + * @library /test/lib * @modules jdk.incubator.vector * @run testng/othervm/timeout=300 -ea -esa -Xbatch -XX:-TieredCompilation Int64VectorTests */ @@ -4785,7 +4788,7 @@ static int[] sliceUnary(int[] a, int origin, int idx) { static void sliceUnaryInt64VectorTests(IntFunction fa) { int[] a = fa.apply(SPECIES.length()); int[] r = new int[a.length]; - int origin = (new java.util.Random()).nextInt(SPECIES.length()); + int origin = RAND.nextInt(SPECIES.length()); for (int ic = 0; ic < INVOC_COUNT; ic++) { for (int i = 0; i < a.length; i += SPECIES.length()) { IntVector av = IntVector.fromArray(SPECIES, a, i); @@ -4814,7 +4817,7 @@ static void sliceBinaryInt64VectorTestsBinary(IntFunction fa, IntFunction int[] a = fa.apply(SPECIES.length()); int[] b = fb.apply(SPECIES.length()); int[] r = new int[a.length]; - int origin = (new java.util.Random()).nextInt(SPECIES.length()); + int origin = RAND.nextInt(SPECIES.length()); for (int ic = 0; ic < INVOC_COUNT; ic++) { for (int i = 0; i < a.length; i += SPECIES.length()) { IntVector av = IntVector.fromArray(SPECIES, a, i); @@ -4848,7 +4851,7 @@ static void sliceInt64VectorTestsMasked(IntFunction fa, IntFunction vmask = VectorMask.fromArray(SPECIES, mask, 0); int[] r = new int[a.length]; - int origin = (new java.util.Random()).nextInt(SPECIES.length()); + int origin = RAND.nextInt(SPECIES.length()); for (int ic = 0; ic < INVOC_COUNT; ic++) { for (int i = 0; i < a.length; i += SPECIES.length()) { IntVector av = IntVector.fromArray(SPECIES, a, i); @@ -4877,7 +4880,7 @@ static int[] unsliceUnary(int[] a, int origin, int idx) { static void unsliceUnaryInt64VectorTests(IntFunction fa) { int[] a = fa.apply(SPECIES.length()); int[] r = new int[a.length]; - int origin = (new java.util.Random()).nextInt(SPECIES.length()); + int origin = RAND.nextInt(SPECIES.length()); for (int ic = 0; ic < INVOC_COUNT; ic++) { for (int i = 0; i < a.length; i += SPECIES.length()) { IntVector av = IntVector.fromArray(SPECIES, a, i); @@ -4915,8 +4918,8 @@ static void unsliceBinaryInt64VectorTestsBinary(IntFunction fa, IntFuncti int[] a = fa.apply(SPECIES.length()); int[] b = fb.apply(SPECIES.length()); int[] r = new int[a.length]; - int origin = (new java.util.Random()).nextInt(SPECIES.length()); - int part = (new java.util.Random()).nextInt(2); + int origin = RAND.nextInt(SPECIES.length()); + int part = RAND.nextInt(2); for (int ic = 0; ic < INVOC_COUNT; ic++) { for (int i = 0; i < a.length; i += SPECIES.length()) { IntVector av = IntVector.fromArray(SPECIES, a, i); @@ -4972,8 +4975,8 @@ static void unsliceInt64VectorTestsMasked(IntFunction fa, IntFunction vmask = VectorMask.fromArray(SPECIES, mask, 0); int[] r = new int[a.length]; - int origin = (new java.util.Random()).nextInt(SPECIES.length()); - int part = (new java.util.Random()).nextInt(2); + int origin = RAND.nextInt(SPECIES.length()); + int part = RAND.nextInt(2); for (int ic = 0; ic < INVOC_COUNT; ic++) { for (int i = 0; i < a.length; i += SPECIES.length()) { IntVector av = IntVector.fromArray(SPECIES, a, i); diff --git a/test/jdk/jdk/incubator/vector/IntMaxVectorLoadStoreTests.java b/test/jdk/jdk/incubator/vector/IntMaxVectorLoadStoreTests.java index 3e11b366a77..cc4aef80f6f 100644 --- a/test/jdk/jdk/incubator/vector/IntMaxVectorLoadStoreTests.java +++ b/test/jdk/jdk/incubator/vector/IntMaxVectorLoadStoreTests.java @@ -23,6 +23,9 @@ /* * @test + * @key randomness + * + * @library /test/lib * @modules jdk.incubator.vector java.base/jdk.internal.vm.annotation * @run testng/othervm --add-opens jdk.incubator.vector/jdk.incubator.vector=ALL-UNNAMED * -XX:-TieredCompilation IntMaxVectorLoadStoreTests diff --git a/test/jdk/jdk/incubator/vector/IntMaxVectorTests.java b/test/jdk/jdk/incubator/vector/IntMaxVectorTests.java index b608b548cee..612dc5080e2 100644 --- a/test/jdk/jdk/incubator/vector/IntMaxVectorTests.java +++ b/test/jdk/jdk/incubator/vector/IntMaxVectorTests.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 @@ -23,6 +23,9 @@ /* * @test + * @key randomness + * + * @library /test/lib * @modules jdk.incubator.vector * @run testng/othervm/timeout=300 -ea -esa -Xbatch -XX:-TieredCompilation IntMaxVectorTests */ @@ -4790,7 +4793,7 @@ static int[] sliceUnary(int[] a, int origin, int idx) { static void sliceUnaryIntMaxVectorTests(IntFunction fa) { int[] a = fa.apply(SPECIES.length()); int[] r = new int[a.length]; - int origin = (new java.util.Random()).nextInt(SPECIES.length()); + int origin = RAND.nextInt(SPECIES.length()); for (int ic = 0; ic < INVOC_COUNT; ic++) { for (int i = 0; i < a.length; i += SPECIES.length()) { IntVector av = IntVector.fromArray(SPECIES, a, i); @@ -4819,7 +4822,7 @@ static void sliceBinaryIntMaxVectorTestsBinary(IntFunction fa, IntFunctio int[] a = fa.apply(SPECIES.length()); int[] b = fb.apply(SPECIES.length()); int[] r = new int[a.length]; - int origin = (new java.util.Random()).nextInt(SPECIES.length()); + int origin = RAND.nextInt(SPECIES.length()); for (int ic = 0; ic < INVOC_COUNT; ic++) { for (int i = 0; i < a.length; i += SPECIES.length()) { IntVector av = IntVector.fromArray(SPECIES, a, i); @@ -4853,7 +4856,7 @@ static void sliceIntMaxVectorTestsMasked(IntFunction fa, IntFunction vmask = VectorMask.fromArray(SPECIES, mask, 0); int[] r = new int[a.length]; - int origin = (new java.util.Random()).nextInt(SPECIES.length()); + int origin = RAND.nextInt(SPECIES.length()); for (int ic = 0; ic < INVOC_COUNT; ic++) { for (int i = 0; i < a.length; i += SPECIES.length()) { IntVector av = IntVector.fromArray(SPECIES, a, i); @@ -4882,7 +4885,7 @@ static int[] unsliceUnary(int[] a, int origin, int idx) { static void unsliceUnaryIntMaxVectorTests(IntFunction fa) { int[] a = fa.apply(SPECIES.length()); int[] r = new int[a.length]; - int origin = (new java.util.Random()).nextInt(SPECIES.length()); + int origin = RAND.nextInt(SPECIES.length()); for (int ic = 0; ic < INVOC_COUNT; ic++) { for (int i = 0; i < a.length; i += SPECIES.length()) { IntVector av = IntVector.fromArray(SPECIES, a, i); @@ -4920,8 +4923,8 @@ static void unsliceBinaryIntMaxVectorTestsBinary(IntFunction fa, IntFunct int[] a = fa.apply(SPECIES.length()); int[] b = fb.apply(SPECIES.length()); int[] r = new int[a.length]; - int origin = (new java.util.Random()).nextInt(SPECIES.length()); - int part = (new java.util.Random()).nextInt(2); + int origin = RAND.nextInt(SPECIES.length()); + int part = RAND.nextInt(2); for (int ic = 0; ic < INVOC_COUNT; ic++) { for (int i = 0; i < a.length; i += SPECIES.length()) { IntVector av = IntVector.fromArray(SPECIES, a, i); @@ -4977,8 +4980,8 @@ static void unsliceIntMaxVectorTestsMasked(IntFunction fa, IntFunction vmask = VectorMask.fromArray(SPECIES, mask, 0); int[] r = new int[a.length]; - int origin = (new java.util.Random()).nextInt(SPECIES.length()); - int part = (new java.util.Random()).nextInt(2); + int origin = RAND.nextInt(SPECIES.length()); + int part = RAND.nextInt(2); for (int ic = 0; ic < INVOC_COUNT; ic++) { for (int i = 0; i < a.length; i += SPECIES.length()) { IntVector av = IntVector.fromArray(SPECIES, a, i); diff --git a/test/jdk/jdk/incubator/vector/Long128VectorLoadStoreTests.java b/test/jdk/jdk/incubator/vector/Long128VectorLoadStoreTests.java index 7425e8e11e8..f9fb3a452a1 100644 --- a/test/jdk/jdk/incubator/vector/Long128VectorLoadStoreTests.java +++ b/test/jdk/jdk/incubator/vector/Long128VectorLoadStoreTests.java @@ -23,6 +23,9 @@ /* * @test + * @key randomness + * + * @library /test/lib * @modules jdk.incubator.vector java.base/jdk.internal.vm.annotation * @run testng/othervm -XX:-TieredCompilation Long128VectorLoadStoreTests * diff --git a/test/jdk/jdk/incubator/vector/Long128VectorTests.java b/test/jdk/jdk/incubator/vector/Long128VectorTests.java index e80497c3584..5ebc7f2c673 100644 --- a/test/jdk/jdk/incubator/vector/Long128VectorTests.java +++ b/test/jdk/jdk/incubator/vector/Long128VectorTests.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 @@ -23,6 +23,9 @@ /* * @test + * @key randomness + * + * @library /test/lib * @modules jdk.incubator.vector * @run testng/othervm/timeout=300 -ea -esa -Xbatch -XX:-TieredCompilation Long128VectorTests */ @@ -4737,7 +4740,7 @@ static long[] sliceUnary(long[] a, int origin, int idx) { static void sliceUnaryLong128VectorTests(IntFunction fa) { long[] a = fa.apply(SPECIES.length()); long[] r = new long[a.length]; - int origin = (new java.util.Random()).nextInt(SPECIES.length()); + int origin = RAND.nextInt(SPECIES.length()); for (int ic = 0; ic < INVOC_COUNT; ic++) { for (int i = 0; i < a.length; i += SPECIES.length()) { LongVector av = LongVector.fromArray(SPECIES, a, i); @@ -4766,7 +4769,7 @@ static void sliceBinaryLong128VectorTestsBinary(IntFunction fa, IntFunct long[] a = fa.apply(SPECIES.length()); long[] b = fb.apply(SPECIES.length()); long[] r = new long[a.length]; - int origin = (new java.util.Random()).nextInt(SPECIES.length()); + int origin = RAND.nextInt(SPECIES.length()); for (int ic = 0; ic < INVOC_COUNT; ic++) { for (int i = 0; i < a.length; i += SPECIES.length()) { LongVector av = LongVector.fromArray(SPECIES, a, i); @@ -4800,7 +4803,7 @@ static void sliceLong128VectorTestsMasked(IntFunction fa, IntFunction vmask = VectorMask.fromArray(SPECIES, mask, 0); long[] r = new long[a.length]; - int origin = (new java.util.Random()).nextInt(SPECIES.length()); + int origin = RAND.nextInt(SPECIES.length()); for (int ic = 0; ic < INVOC_COUNT; ic++) { for (int i = 0; i < a.length; i += SPECIES.length()) { LongVector av = LongVector.fromArray(SPECIES, a, i); @@ -4829,7 +4832,7 @@ static long[] unsliceUnary(long[] a, int origin, int idx) { static void unsliceUnaryLong128VectorTests(IntFunction fa) { long[] a = fa.apply(SPECIES.length()); long[] r = new long[a.length]; - int origin = (new java.util.Random()).nextInt(SPECIES.length()); + int origin = RAND.nextInt(SPECIES.length()); for (int ic = 0; ic < INVOC_COUNT; ic++) { for (int i = 0; i < a.length; i += SPECIES.length()) { LongVector av = LongVector.fromArray(SPECIES, a, i); @@ -4867,8 +4870,8 @@ static void unsliceBinaryLong128VectorTestsBinary(IntFunction fa, IntFun long[] a = fa.apply(SPECIES.length()); long[] b = fb.apply(SPECIES.length()); long[] r = new long[a.length]; - int origin = (new java.util.Random()).nextInt(SPECIES.length()); - int part = (new java.util.Random()).nextInt(2); + int origin = RAND.nextInt(SPECIES.length()); + int part = RAND.nextInt(2); for (int ic = 0; ic < INVOC_COUNT; ic++) { for (int i = 0; i < a.length; i += SPECIES.length()) { LongVector av = LongVector.fromArray(SPECIES, a, i); @@ -4924,8 +4927,8 @@ static void unsliceLong128VectorTestsMasked(IntFunction fa, IntFunction< boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); long[] r = new long[a.length]; - int origin = (new java.util.Random()).nextInt(SPECIES.length()); - int part = (new java.util.Random()).nextInt(2); + int origin = RAND.nextInt(SPECIES.length()); + int part = RAND.nextInt(2); for (int ic = 0; ic < INVOC_COUNT; ic++) { for (int i = 0; i < a.length; i += SPECIES.length()) { LongVector av = LongVector.fromArray(SPECIES, a, i); diff --git a/test/jdk/jdk/incubator/vector/Long256VectorLoadStoreTests.java b/test/jdk/jdk/incubator/vector/Long256VectorLoadStoreTests.java index 78e16570eb8..73e81a2635f 100644 --- a/test/jdk/jdk/incubator/vector/Long256VectorLoadStoreTests.java +++ b/test/jdk/jdk/incubator/vector/Long256VectorLoadStoreTests.java @@ -23,6 +23,9 @@ /* * @test + * @key randomness + * + * @library /test/lib * @modules jdk.incubator.vector java.base/jdk.internal.vm.annotation * @run testng/othervm -XX:-TieredCompilation Long256VectorLoadStoreTests * diff --git a/test/jdk/jdk/incubator/vector/Long256VectorTests.java b/test/jdk/jdk/incubator/vector/Long256VectorTests.java index b3762b4c15a..b7b66008917 100644 --- a/test/jdk/jdk/incubator/vector/Long256VectorTests.java +++ b/test/jdk/jdk/incubator/vector/Long256VectorTests.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 @@ -23,6 +23,9 @@ /* * @test + * @key randomness + * + * @library /test/lib * @modules jdk.incubator.vector * @run testng/othervm/timeout=300 -ea -esa -Xbatch -XX:-TieredCompilation Long256VectorTests */ @@ -4737,7 +4740,7 @@ static long[] sliceUnary(long[] a, int origin, int idx) { static void sliceUnaryLong256VectorTests(IntFunction fa) { long[] a = fa.apply(SPECIES.length()); long[] r = new long[a.length]; - int origin = (new java.util.Random()).nextInt(SPECIES.length()); + int origin = RAND.nextInt(SPECIES.length()); for (int ic = 0; ic < INVOC_COUNT; ic++) { for (int i = 0; i < a.length; i += SPECIES.length()) { LongVector av = LongVector.fromArray(SPECIES, a, i); @@ -4766,7 +4769,7 @@ static void sliceBinaryLong256VectorTestsBinary(IntFunction fa, IntFunct long[] a = fa.apply(SPECIES.length()); long[] b = fb.apply(SPECIES.length()); long[] r = new long[a.length]; - int origin = (new java.util.Random()).nextInt(SPECIES.length()); + int origin = RAND.nextInt(SPECIES.length()); for (int ic = 0; ic < INVOC_COUNT; ic++) { for (int i = 0; i < a.length; i += SPECIES.length()) { LongVector av = LongVector.fromArray(SPECIES, a, i); @@ -4800,7 +4803,7 @@ static void sliceLong256VectorTestsMasked(IntFunction fa, IntFunction vmask = VectorMask.fromArray(SPECIES, mask, 0); long[] r = new long[a.length]; - int origin = (new java.util.Random()).nextInt(SPECIES.length()); + int origin = RAND.nextInt(SPECIES.length()); for (int ic = 0; ic < INVOC_COUNT; ic++) { for (int i = 0; i < a.length; i += SPECIES.length()) { LongVector av = LongVector.fromArray(SPECIES, a, i); @@ -4829,7 +4832,7 @@ static long[] unsliceUnary(long[] a, int origin, int idx) { static void unsliceUnaryLong256VectorTests(IntFunction fa) { long[] a = fa.apply(SPECIES.length()); long[] r = new long[a.length]; - int origin = (new java.util.Random()).nextInt(SPECIES.length()); + int origin = RAND.nextInt(SPECIES.length()); for (int ic = 0; ic < INVOC_COUNT; ic++) { for (int i = 0; i < a.length; i += SPECIES.length()) { LongVector av = LongVector.fromArray(SPECIES, a, i); @@ -4867,8 +4870,8 @@ static void unsliceBinaryLong256VectorTestsBinary(IntFunction fa, IntFun long[] a = fa.apply(SPECIES.length()); long[] b = fb.apply(SPECIES.length()); long[] r = new long[a.length]; - int origin = (new java.util.Random()).nextInt(SPECIES.length()); - int part = (new java.util.Random()).nextInt(2); + int origin = RAND.nextInt(SPECIES.length()); + int part = RAND.nextInt(2); for (int ic = 0; ic < INVOC_COUNT; ic++) { for (int i = 0; i < a.length; i += SPECIES.length()) { LongVector av = LongVector.fromArray(SPECIES, a, i); @@ -4924,8 +4927,8 @@ static void unsliceLong256VectorTestsMasked(IntFunction fa, IntFunction< boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); long[] r = new long[a.length]; - int origin = (new java.util.Random()).nextInt(SPECIES.length()); - int part = (new java.util.Random()).nextInt(2); + int origin = RAND.nextInt(SPECIES.length()); + int part = RAND.nextInt(2); for (int ic = 0; ic < INVOC_COUNT; ic++) { for (int i = 0; i < a.length; i += SPECIES.length()) { LongVector av = LongVector.fromArray(SPECIES, a, i); diff --git a/test/jdk/jdk/incubator/vector/Long512VectorLoadStoreTests.java b/test/jdk/jdk/incubator/vector/Long512VectorLoadStoreTests.java index cf41e488c44..7f38adb46a1 100644 --- a/test/jdk/jdk/incubator/vector/Long512VectorLoadStoreTests.java +++ b/test/jdk/jdk/incubator/vector/Long512VectorLoadStoreTests.java @@ -23,6 +23,9 @@ /* * @test + * @key randomness + * + * @library /test/lib * @modules jdk.incubator.vector java.base/jdk.internal.vm.annotation * @run testng/othervm -XX:-TieredCompilation Long512VectorLoadStoreTests * diff --git a/test/jdk/jdk/incubator/vector/Long512VectorTests.java b/test/jdk/jdk/incubator/vector/Long512VectorTests.java index 57ba7738d13..65edac9114c 100644 --- a/test/jdk/jdk/incubator/vector/Long512VectorTests.java +++ b/test/jdk/jdk/incubator/vector/Long512VectorTests.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 @@ -23,6 +23,9 @@ /* * @test + * @key randomness + * + * @library /test/lib * @modules jdk.incubator.vector * @run testng/othervm/timeout=300 -ea -esa -Xbatch -XX:-TieredCompilation Long512VectorTests */ @@ -4737,7 +4740,7 @@ static long[] sliceUnary(long[] a, int origin, int idx) { static void sliceUnaryLong512VectorTests(IntFunction fa) { long[] a = fa.apply(SPECIES.length()); long[] r = new long[a.length]; - int origin = (new java.util.Random()).nextInt(SPECIES.length()); + int origin = RAND.nextInt(SPECIES.length()); for (int ic = 0; ic < INVOC_COUNT; ic++) { for (int i = 0; i < a.length; i += SPECIES.length()) { LongVector av = LongVector.fromArray(SPECIES, a, i); @@ -4766,7 +4769,7 @@ static void sliceBinaryLong512VectorTestsBinary(IntFunction fa, IntFunct long[] a = fa.apply(SPECIES.length()); long[] b = fb.apply(SPECIES.length()); long[] r = new long[a.length]; - int origin = (new java.util.Random()).nextInt(SPECIES.length()); + int origin = RAND.nextInt(SPECIES.length()); for (int ic = 0; ic < INVOC_COUNT; ic++) { for (int i = 0; i < a.length; i += SPECIES.length()) { LongVector av = LongVector.fromArray(SPECIES, a, i); @@ -4800,7 +4803,7 @@ static void sliceLong512VectorTestsMasked(IntFunction fa, IntFunction vmask = VectorMask.fromArray(SPECIES, mask, 0); long[] r = new long[a.length]; - int origin = (new java.util.Random()).nextInt(SPECIES.length()); + int origin = RAND.nextInt(SPECIES.length()); for (int ic = 0; ic < INVOC_COUNT; ic++) { for (int i = 0; i < a.length; i += SPECIES.length()) { LongVector av = LongVector.fromArray(SPECIES, a, i); @@ -4829,7 +4832,7 @@ static long[] unsliceUnary(long[] a, int origin, int idx) { static void unsliceUnaryLong512VectorTests(IntFunction fa) { long[] a = fa.apply(SPECIES.length()); long[] r = new long[a.length]; - int origin = (new java.util.Random()).nextInt(SPECIES.length()); + int origin = RAND.nextInt(SPECIES.length()); for (int ic = 0; ic < INVOC_COUNT; ic++) { for (int i = 0; i < a.length; i += SPECIES.length()) { LongVector av = LongVector.fromArray(SPECIES, a, i); @@ -4867,8 +4870,8 @@ static void unsliceBinaryLong512VectorTestsBinary(IntFunction fa, IntFun long[] a = fa.apply(SPECIES.length()); long[] b = fb.apply(SPECIES.length()); long[] r = new long[a.length]; - int origin = (new java.util.Random()).nextInt(SPECIES.length()); - int part = (new java.util.Random()).nextInt(2); + int origin = RAND.nextInt(SPECIES.length()); + int part = RAND.nextInt(2); for (int ic = 0; ic < INVOC_COUNT; ic++) { for (int i = 0; i < a.length; i += SPECIES.length()) { LongVector av = LongVector.fromArray(SPECIES, a, i); @@ -4924,8 +4927,8 @@ static void unsliceLong512VectorTestsMasked(IntFunction fa, IntFunction< boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); long[] r = new long[a.length]; - int origin = (new java.util.Random()).nextInt(SPECIES.length()); - int part = (new java.util.Random()).nextInt(2); + int origin = RAND.nextInt(SPECIES.length()); + int part = RAND.nextInt(2); for (int ic = 0; ic < INVOC_COUNT; ic++) { for (int i = 0; i < a.length; i += SPECIES.length()) { LongVector av = LongVector.fromArray(SPECIES, a, i); diff --git a/test/jdk/jdk/incubator/vector/Long64VectorLoadStoreTests.java b/test/jdk/jdk/incubator/vector/Long64VectorLoadStoreTests.java index 532074f9d62..398aec1981a 100644 --- a/test/jdk/jdk/incubator/vector/Long64VectorLoadStoreTests.java +++ b/test/jdk/jdk/incubator/vector/Long64VectorLoadStoreTests.java @@ -23,6 +23,9 @@ /* * @test + * @key randomness + * + * @library /test/lib * @modules jdk.incubator.vector java.base/jdk.internal.vm.annotation * @run testng/othervm -XX:-TieredCompilation Long64VectorLoadStoreTests * diff --git a/test/jdk/jdk/incubator/vector/Long64VectorTests.java b/test/jdk/jdk/incubator/vector/Long64VectorTests.java index 8917281196f..7b1c65716aa 100644 --- a/test/jdk/jdk/incubator/vector/Long64VectorTests.java +++ b/test/jdk/jdk/incubator/vector/Long64VectorTests.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 @@ -23,6 +23,9 @@ /* * @test + * @key randomness + * + * @library /test/lib * @modules jdk.incubator.vector * @run testng/othervm/timeout=300 -ea -esa -Xbatch -XX:-TieredCompilation Long64VectorTests */ @@ -4737,7 +4740,7 @@ static long[] sliceUnary(long[] a, int origin, int idx) { static void sliceUnaryLong64VectorTests(IntFunction fa) { long[] a = fa.apply(SPECIES.length()); long[] r = new long[a.length]; - int origin = (new java.util.Random()).nextInt(SPECIES.length()); + int origin = RAND.nextInt(SPECIES.length()); for (int ic = 0; ic < INVOC_COUNT; ic++) { for (int i = 0; i < a.length; i += SPECIES.length()) { LongVector av = LongVector.fromArray(SPECIES, a, i); @@ -4766,7 +4769,7 @@ static void sliceBinaryLong64VectorTestsBinary(IntFunction fa, IntFuncti long[] a = fa.apply(SPECIES.length()); long[] b = fb.apply(SPECIES.length()); long[] r = new long[a.length]; - int origin = (new java.util.Random()).nextInt(SPECIES.length()); + int origin = RAND.nextInt(SPECIES.length()); for (int ic = 0; ic < INVOC_COUNT; ic++) { for (int i = 0; i < a.length; i += SPECIES.length()) { LongVector av = LongVector.fromArray(SPECIES, a, i); @@ -4800,7 +4803,7 @@ static void sliceLong64VectorTestsMasked(IntFunction fa, IntFunction vmask = VectorMask.fromArray(SPECIES, mask, 0); long[] r = new long[a.length]; - int origin = (new java.util.Random()).nextInt(SPECIES.length()); + int origin = RAND.nextInt(SPECIES.length()); for (int ic = 0; ic < INVOC_COUNT; ic++) { for (int i = 0; i < a.length; i += SPECIES.length()) { LongVector av = LongVector.fromArray(SPECIES, a, i); @@ -4829,7 +4832,7 @@ static long[] unsliceUnary(long[] a, int origin, int idx) { static void unsliceUnaryLong64VectorTests(IntFunction fa) { long[] a = fa.apply(SPECIES.length()); long[] r = new long[a.length]; - int origin = (new java.util.Random()).nextInt(SPECIES.length()); + int origin = RAND.nextInt(SPECIES.length()); for (int ic = 0; ic < INVOC_COUNT; ic++) { for (int i = 0; i < a.length; i += SPECIES.length()) { LongVector av = LongVector.fromArray(SPECIES, a, i); @@ -4867,8 +4870,8 @@ static void unsliceBinaryLong64VectorTestsBinary(IntFunction fa, IntFunc long[] a = fa.apply(SPECIES.length()); long[] b = fb.apply(SPECIES.length()); long[] r = new long[a.length]; - int origin = (new java.util.Random()).nextInt(SPECIES.length()); - int part = (new java.util.Random()).nextInt(2); + int origin = RAND.nextInt(SPECIES.length()); + int part = RAND.nextInt(2); for (int ic = 0; ic < INVOC_COUNT; ic++) { for (int i = 0; i < a.length; i += SPECIES.length()) { LongVector av = LongVector.fromArray(SPECIES, a, i); @@ -4924,8 +4927,8 @@ static void unsliceLong64VectorTestsMasked(IntFunction fa, IntFunction vmask = VectorMask.fromArray(SPECIES, mask, 0); long[] r = new long[a.length]; - int origin = (new java.util.Random()).nextInt(SPECIES.length()); - int part = (new java.util.Random()).nextInt(2); + int origin = RAND.nextInt(SPECIES.length()); + int part = RAND.nextInt(2); for (int ic = 0; ic < INVOC_COUNT; ic++) { for (int i = 0; i < a.length; i += SPECIES.length()) { LongVector av = LongVector.fromArray(SPECIES, a, i); diff --git a/test/jdk/jdk/incubator/vector/LongMaxVectorLoadStoreTests.java b/test/jdk/jdk/incubator/vector/LongMaxVectorLoadStoreTests.java index 462fe0dcd8c..48c2534b66c 100644 --- a/test/jdk/jdk/incubator/vector/LongMaxVectorLoadStoreTests.java +++ b/test/jdk/jdk/incubator/vector/LongMaxVectorLoadStoreTests.java @@ -23,6 +23,9 @@ /* * @test + * @key randomness + * + * @library /test/lib * @modules jdk.incubator.vector java.base/jdk.internal.vm.annotation * @run testng/othervm --add-opens jdk.incubator.vector/jdk.incubator.vector=ALL-UNNAMED * -XX:-TieredCompilation LongMaxVectorLoadStoreTests diff --git a/test/jdk/jdk/incubator/vector/LongMaxVectorTests.java b/test/jdk/jdk/incubator/vector/LongMaxVectorTests.java index 913f7d6f527..06f5814e533 100644 --- a/test/jdk/jdk/incubator/vector/LongMaxVectorTests.java +++ b/test/jdk/jdk/incubator/vector/LongMaxVectorTests.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 @@ -23,6 +23,9 @@ /* * @test + * @key randomness + * + * @library /test/lib * @modules jdk.incubator.vector * @run testng/othervm/timeout=300 -ea -esa -Xbatch -XX:-TieredCompilation LongMaxVectorTests */ @@ -4742,7 +4745,7 @@ static long[] sliceUnary(long[] a, int origin, int idx) { static void sliceUnaryLongMaxVectorTests(IntFunction fa) { long[] a = fa.apply(SPECIES.length()); long[] r = new long[a.length]; - int origin = (new java.util.Random()).nextInt(SPECIES.length()); + int origin = RAND.nextInt(SPECIES.length()); for (int ic = 0; ic < INVOC_COUNT; ic++) { for (int i = 0; i < a.length; i += SPECIES.length()) { LongVector av = LongVector.fromArray(SPECIES, a, i); @@ -4771,7 +4774,7 @@ static void sliceBinaryLongMaxVectorTestsBinary(IntFunction fa, IntFunct long[] a = fa.apply(SPECIES.length()); long[] b = fb.apply(SPECIES.length()); long[] r = new long[a.length]; - int origin = (new java.util.Random()).nextInt(SPECIES.length()); + int origin = RAND.nextInt(SPECIES.length()); for (int ic = 0; ic < INVOC_COUNT; ic++) { for (int i = 0; i < a.length; i += SPECIES.length()) { LongVector av = LongVector.fromArray(SPECIES, a, i); @@ -4805,7 +4808,7 @@ static void sliceLongMaxVectorTestsMasked(IntFunction fa, IntFunction vmask = VectorMask.fromArray(SPECIES, mask, 0); long[] r = new long[a.length]; - int origin = (new java.util.Random()).nextInt(SPECIES.length()); + int origin = RAND.nextInt(SPECIES.length()); for (int ic = 0; ic < INVOC_COUNT; ic++) { for (int i = 0; i < a.length; i += SPECIES.length()) { LongVector av = LongVector.fromArray(SPECIES, a, i); @@ -4834,7 +4837,7 @@ static long[] unsliceUnary(long[] a, int origin, int idx) { static void unsliceUnaryLongMaxVectorTests(IntFunction fa) { long[] a = fa.apply(SPECIES.length()); long[] r = new long[a.length]; - int origin = (new java.util.Random()).nextInt(SPECIES.length()); + int origin = RAND.nextInt(SPECIES.length()); for (int ic = 0; ic < INVOC_COUNT; ic++) { for (int i = 0; i < a.length; i += SPECIES.length()) { LongVector av = LongVector.fromArray(SPECIES, a, i); @@ -4872,8 +4875,8 @@ static void unsliceBinaryLongMaxVectorTestsBinary(IntFunction fa, IntFun long[] a = fa.apply(SPECIES.length()); long[] b = fb.apply(SPECIES.length()); long[] r = new long[a.length]; - int origin = (new java.util.Random()).nextInt(SPECIES.length()); - int part = (new java.util.Random()).nextInt(2); + int origin = RAND.nextInt(SPECIES.length()); + int part = RAND.nextInt(2); for (int ic = 0; ic < INVOC_COUNT; ic++) { for (int i = 0; i < a.length; i += SPECIES.length()) { LongVector av = LongVector.fromArray(SPECIES, a, i); @@ -4929,8 +4932,8 @@ static void unsliceLongMaxVectorTestsMasked(IntFunction fa, IntFunction< boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); long[] r = new long[a.length]; - int origin = (new java.util.Random()).nextInt(SPECIES.length()); - int part = (new java.util.Random()).nextInt(2); + int origin = RAND.nextInt(SPECIES.length()); + int part = RAND.nextInt(2); for (int ic = 0; ic < INVOC_COUNT; ic++) { for (int i = 0; i < a.length; i += SPECIES.length()) { LongVector av = LongVector.fromArray(SPECIES, a, i); diff --git a/test/jdk/jdk/incubator/vector/Short128VectorLoadStoreTests.java b/test/jdk/jdk/incubator/vector/Short128VectorLoadStoreTests.java index 6898bdea621..400b3c376a1 100644 --- a/test/jdk/jdk/incubator/vector/Short128VectorLoadStoreTests.java +++ b/test/jdk/jdk/incubator/vector/Short128VectorLoadStoreTests.java @@ -23,6 +23,9 @@ /* * @test + * @key randomness + * + * @library /test/lib * @modules jdk.incubator.vector java.base/jdk.internal.vm.annotation * @run testng/othervm -XX:-TieredCompilation Short128VectorLoadStoreTests * diff --git a/test/jdk/jdk/incubator/vector/Short128VectorTests.java b/test/jdk/jdk/incubator/vector/Short128VectorTests.java index e40a40686c9..c9fe21f8125 100644 --- a/test/jdk/jdk/incubator/vector/Short128VectorTests.java +++ b/test/jdk/jdk/incubator/vector/Short128VectorTests.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 @@ -23,6 +23,9 @@ /* * @test + * @key randomness + * + * @library /test/lib * @modules jdk.incubator.vector * @run testng/othervm/timeout=300 -ea -esa -Xbatch -XX:-TieredCompilation Short128VectorTests */ @@ -4732,7 +4735,7 @@ static short[] sliceUnary(short[] a, int origin, int idx) { static void sliceUnaryShort128VectorTests(IntFunction fa) { short[] a = fa.apply(SPECIES.length()); short[] r = new short[a.length]; - int origin = (new java.util.Random()).nextInt(SPECIES.length()); + int origin = RAND.nextInt(SPECIES.length()); for (int ic = 0; ic < INVOC_COUNT; ic++) { for (int i = 0; i < a.length; i += SPECIES.length()) { ShortVector av = ShortVector.fromArray(SPECIES, a, i); @@ -4761,7 +4764,7 @@ static void sliceBinaryShort128VectorTestsBinary(IntFunction fa, IntFun short[] a = fa.apply(SPECIES.length()); short[] b = fb.apply(SPECIES.length()); short[] r = new short[a.length]; - int origin = (new java.util.Random()).nextInt(SPECIES.length()); + int origin = RAND.nextInt(SPECIES.length()); for (int ic = 0; ic < INVOC_COUNT; ic++) { for (int i = 0; i < a.length; i += SPECIES.length()) { ShortVector av = ShortVector.fromArray(SPECIES, a, i); @@ -4795,7 +4798,7 @@ static void sliceShort128VectorTestsMasked(IntFunction fa, IntFunction< VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); short[] r = new short[a.length]; - int origin = (new java.util.Random()).nextInt(SPECIES.length()); + int origin = RAND.nextInt(SPECIES.length()); for (int ic = 0; ic < INVOC_COUNT; ic++) { for (int i = 0; i < a.length; i += SPECIES.length()) { ShortVector av = ShortVector.fromArray(SPECIES, a, i); @@ -4824,7 +4827,7 @@ static short[] unsliceUnary(short[] a, int origin, int idx) { static void unsliceUnaryShort128VectorTests(IntFunction fa) { short[] a = fa.apply(SPECIES.length()); short[] r = new short[a.length]; - int origin = (new java.util.Random()).nextInt(SPECIES.length()); + int origin = RAND.nextInt(SPECIES.length()); for (int ic = 0; ic < INVOC_COUNT; ic++) { for (int i = 0; i < a.length; i += SPECIES.length()) { ShortVector av = ShortVector.fromArray(SPECIES, a, i); @@ -4862,8 +4865,8 @@ static void unsliceBinaryShort128VectorTestsBinary(IntFunction fa, IntF short[] a = fa.apply(SPECIES.length()); short[] b = fb.apply(SPECIES.length()); short[] r = new short[a.length]; - int origin = (new java.util.Random()).nextInt(SPECIES.length()); - int part = (new java.util.Random()).nextInt(2); + int origin = RAND.nextInt(SPECIES.length()); + int part = RAND.nextInt(2); for (int ic = 0; ic < INVOC_COUNT; ic++) { for (int i = 0; i < a.length; i += SPECIES.length()) { ShortVector av = ShortVector.fromArray(SPECIES, a, i); @@ -4919,8 +4922,8 @@ static void unsliceShort128VectorTestsMasked(IntFunction fa, IntFunctio boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); short[] r = new short[a.length]; - int origin = (new java.util.Random()).nextInt(SPECIES.length()); - int part = (new java.util.Random()).nextInt(2); + int origin = RAND.nextInt(SPECIES.length()); + int part = RAND.nextInt(2); for (int ic = 0; ic < INVOC_COUNT; ic++) { for (int i = 0; i < a.length; i += SPECIES.length()) { ShortVector av = ShortVector.fromArray(SPECIES, a, i); diff --git a/test/jdk/jdk/incubator/vector/Short256VectorLoadStoreTests.java b/test/jdk/jdk/incubator/vector/Short256VectorLoadStoreTests.java index 45044570a1a..92cecf534b5 100644 --- a/test/jdk/jdk/incubator/vector/Short256VectorLoadStoreTests.java +++ b/test/jdk/jdk/incubator/vector/Short256VectorLoadStoreTests.java @@ -23,6 +23,9 @@ /* * @test + * @key randomness + * + * @library /test/lib * @modules jdk.incubator.vector java.base/jdk.internal.vm.annotation * @run testng/othervm -XX:-TieredCompilation Short256VectorLoadStoreTests * diff --git a/test/jdk/jdk/incubator/vector/Short256VectorTests.java b/test/jdk/jdk/incubator/vector/Short256VectorTests.java index 02138e3e8aa..a39ec0126d4 100644 --- a/test/jdk/jdk/incubator/vector/Short256VectorTests.java +++ b/test/jdk/jdk/incubator/vector/Short256VectorTests.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 @@ -23,6 +23,9 @@ /* * @test + * @key randomness + * + * @library /test/lib * @modules jdk.incubator.vector * @run testng/othervm/timeout=300 -ea -esa -Xbatch -XX:-TieredCompilation Short256VectorTests */ @@ -4732,7 +4735,7 @@ static short[] sliceUnary(short[] a, int origin, int idx) { static void sliceUnaryShort256VectorTests(IntFunction fa) { short[] a = fa.apply(SPECIES.length()); short[] r = new short[a.length]; - int origin = (new java.util.Random()).nextInt(SPECIES.length()); + int origin = RAND.nextInt(SPECIES.length()); for (int ic = 0; ic < INVOC_COUNT; ic++) { for (int i = 0; i < a.length; i += SPECIES.length()) { ShortVector av = ShortVector.fromArray(SPECIES, a, i); @@ -4761,7 +4764,7 @@ static void sliceBinaryShort256VectorTestsBinary(IntFunction fa, IntFun short[] a = fa.apply(SPECIES.length()); short[] b = fb.apply(SPECIES.length()); short[] r = new short[a.length]; - int origin = (new java.util.Random()).nextInt(SPECIES.length()); + int origin = RAND.nextInt(SPECIES.length()); for (int ic = 0; ic < INVOC_COUNT; ic++) { for (int i = 0; i < a.length; i += SPECIES.length()) { ShortVector av = ShortVector.fromArray(SPECIES, a, i); @@ -4795,7 +4798,7 @@ static void sliceShort256VectorTestsMasked(IntFunction fa, IntFunction< VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); short[] r = new short[a.length]; - int origin = (new java.util.Random()).nextInt(SPECIES.length()); + int origin = RAND.nextInt(SPECIES.length()); for (int ic = 0; ic < INVOC_COUNT; ic++) { for (int i = 0; i < a.length; i += SPECIES.length()) { ShortVector av = ShortVector.fromArray(SPECIES, a, i); @@ -4824,7 +4827,7 @@ static short[] unsliceUnary(short[] a, int origin, int idx) { static void unsliceUnaryShort256VectorTests(IntFunction fa) { short[] a = fa.apply(SPECIES.length()); short[] r = new short[a.length]; - int origin = (new java.util.Random()).nextInt(SPECIES.length()); + int origin = RAND.nextInt(SPECIES.length()); for (int ic = 0; ic < INVOC_COUNT; ic++) { for (int i = 0; i < a.length; i += SPECIES.length()) { ShortVector av = ShortVector.fromArray(SPECIES, a, i); @@ -4862,8 +4865,8 @@ static void unsliceBinaryShort256VectorTestsBinary(IntFunction fa, IntF short[] a = fa.apply(SPECIES.length()); short[] b = fb.apply(SPECIES.length()); short[] r = new short[a.length]; - int origin = (new java.util.Random()).nextInt(SPECIES.length()); - int part = (new java.util.Random()).nextInt(2); + int origin = RAND.nextInt(SPECIES.length()); + int part = RAND.nextInt(2); for (int ic = 0; ic < INVOC_COUNT; ic++) { for (int i = 0; i < a.length; i += SPECIES.length()) { ShortVector av = ShortVector.fromArray(SPECIES, a, i); @@ -4919,8 +4922,8 @@ static void unsliceShort256VectorTestsMasked(IntFunction fa, IntFunctio boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); short[] r = new short[a.length]; - int origin = (new java.util.Random()).nextInt(SPECIES.length()); - int part = (new java.util.Random()).nextInt(2); + int origin = RAND.nextInt(SPECIES.length()); + int part = RAND.nextInt(2); for (int ic = 0; ic < INVOC_COUNT; ic++) { for (int i = 0; i < a.length; i += SPECIES.length()) { ShortVector av = ShortVector.fromArray(SPECIES, a, i); diff --git a/test/jdk/jdk/incubator/vector/Short512VectorLoadStoreTests.java b/test/jdk/jdk/incubator/vector/Short512VectorLoadStoreTests.java index fb467b6ed78..a3d577afcdc 100644 --- a/test/jdk/jdk/incubator/vector/Short512VectorLoadStoreTests.java +++ b/test/jdk/jdk/incubator/vector/Short512VectorLoadStoreTests.java @@ -23,6 +23,9 @@ /* * @test + * @key randomness + * + * @library /test/lib * @modules jdk.incubator.vector java.base/jdk.internal.vm.annotation * @run testng/othervm -XX:-TieredCompilation Short512VectorLoadStoreTests * diff --git a/test/jdk/jdk/incubator/vector/Short512VectorTests.java b/test/jdk/jdk/incubator/vector/Short512VectorTests.java index 9577f22f58c..5453c19149c 100644 --- a/test/jdk/jdk/incubator/vector/Short512VectorTests.java +++ b/test/jdk/jdk/incubator/vector/Short512VectorTests.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 @@ -23,6 +23,9 @@ /* * @test + * @key randomness + * + * @library /test/lib * @modules jdk.incubator.vector * @run testng/othervm/timeout=300 -ea -esa -Xbatch -XX:-TieredCompilation Short512VectorTests */ @@ -4732,7 +4735,7 @@ static short[] sliceUnary(short[] a, int origin, int idx) { static void sliceUnaryShort512VectorTests(IntFunction fa) { short[] a = fa.apply(SPECIES.length()); short[] r = new short[a.length]; - int origin = (new java.util.Random()).nextInt(SPECIES.length()); + int origin = RAND.nextInt(SPECIES.length()); for (int ic = 0; ic < INVOC_COUNT; ic++) { for (int i = 0; i < a.length; i += SPECIES.length()) { ShortVector av = ShortVector.fromArray(SPECIES, a, i); @@ -4761,7 +4764,7 @@ static void sliceBinaryShort512VectorTestsBinary(IntFunction fa, IntFun short[] a = fa.apply(SPECIES.length()); short[] b = fb.apply(SPECIES.length()); short[] r = new short[a.length]; - int origin = (new java.util.Random()).nextInt(SPECIES.length()); + int origin = RAND.nextInt(SPECIES.length()); for (int ic = 0; ic < INVOC_COUNT; ic++) { for (int i = 0; i < a.length; i += SPECIES.length()) { ShortVector av = ShortVector.fromArray(SPECIES, a, i); @@ -4795,7 +4798,7 @@ static void sliceShort512VectorTestsMasked(IntFunction fa, IntFunction< VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); short[] r = new short[a.length]; - int origin = (new java.util.Random()).nextInt(SPECIES.length()); + int origin = RAND.nextInt(SPECIES.length()); for (int ic = 0; ic < INVOC_COUNT; ic++) { for (int i = 0; i < a.length; i += SPECIES.length()) { ShortVector av = ShortVector.fromArray(SPECIES, a, i); @@ -4824,7 +4827,7 @@ static short[] unsliceUnary(short[] a, int origin, int idx) { static void unsliceUnaryShort512VectorTests(IntFunction fa) { short[] a = fa.apply(SPECIES.length()); short[] r = new short[a.length]; - int origin = (new java.util.Random()).nextInt(SPECIES.length()); + int origin = RAND.nextInt(SPECIES.length()); for (int ic = 0; ic < INVOC_COUNT; ic++) { for (int i = 0; i < a.length; i += SPECIES.length()) { ShortVector av = ShortVector.fromArray(SPECIES, a, i); @@ -4862,8 +4865,8 @@ static void unsliceBinaryShort512VectorTestsBinary(IntFunction fa, IntF short[] a = fa.apply(SPECIES.length()); short[] b = fb.apply(SPECIES.length()); short[] r = new short[a.length]; - int origin = (new java.util.Random()).nextInt(SPECIES.length()); - int part = (new java.util.Random()).nextInt(2); + int origin = RAND.nextInt(SPECIES.length()); + int part = RAND.nextInt(2); for (int ic = 0; ic < INVOC_COUNT; ic++) { for (int i = 0; i < a.length; i += SPECIES.length()) { ShortVector av = ShortVector.fromArray(SPECIES, a, i); @@ -4919,8 +4922,8 @@ static void unsliceShort512VectorTestsMasked(IntFunction fa, IntFunctio boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); short[] r = new short[a.length]; - int origin = (new java.util.Random()).nextInt(SPECIES.length()); - int part = (new java.util.Random()).nextInt(2); + int origin = RAND.nextInt(SPECIES.length()); + int part = RAND.nextInt(2); for (int ic = 0; ic < INVOC_COUNT; ic++) { for (int i = 0; i < a.length; i += SPECIES.length()) { ShortVector av = ShortVector.fromArray(SPECIES, a, i); diff --git a/test/jdk/jdk/incubator/vector/Short64VectorLoadStoreTests.java b/test/jdk/jdk/incubator/vector/Short64VectorLoadStoreTests.java index 1b7e59bc9f9..dd420fd3613 100644 --- a/test/jdk/jdk/incubator/vector/Short64VectorLoadStoreTests.java +++ b/test/jdk/jdk/incubator/vector/Short64VectorLoadStoreTests.java @@ -23,6 +23,9 @@ /* * @test + * @key randomness + * + * @library /test/lib * @modules jdk.incubator.vector java.base/jdk.internal.vm.annotation * @run testng/othervm -XX:-TieredCompilation Short64VectorLoadStoreTests * diff --git a/test/jdk/jdk/incubator/vector/Short64VectorTests.java b/test/jdk/jdk/incubator/vector/Short64VectorTests.java index 71b3c6046b4..8ba47569595 100644 --- a/test/jdk/jdk/incubator/vector/Short64VectorTests.java +++ b/test/jdk/jdk/incubator/vector/Short64VectorTests.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 @@ -23,6 +23,9 @@ /* * @test + * @key randomness + * + * @library /test/lib * @modules jdk.incubator.vector * @run testng/othervm/timeout=300 -ea -esa -Xbatch -XX:-TieredCompilation Short64VectorTests */ @@ -4732,7 +4735,7 @@ static short[] sliceUnary(short[] a, int origin, int idx) { static void sliceUnaryShort64VectorTests(IntFunction fa) { short[] a = fa.apply(SPECIES.length()); short[] r = new short[a.length]; - int origin = (new java.util.Random()).nextInt(SPECIES.length()); + int origin = RAND.nextInt(SPECIES.length()); for (int ic = 0; ic < INVOC_COUNT; ic++) { for (int i = 0; i < a.length; i += SPECIES.length()) { ShortVector av = ShortVector.fromArray(SPECIES, a, i); @@ -4761,7 +4764,7 @@ static void sliceBinaryShort64VectorTestsBinary(IntFunction fa, IntFunc short[] a = fa.apply(SPECIES.length()); short[] b = fb.apply(SPECIES.length()); short[] r = new short[a.length]; - int origin = (new java.util.Random()).nextInt(SPECIES.length()); + int origin = RAND.nextInt(SPECIES.length()); for (int ic = 0; ic < INVOC_COUNT; ic++) { for (int i = 0; i < a.length; i += SPECIES.length()) { ShortVector av = ShortVector.fromArray(SPECIES, a, i); @@ -4795,7 +4798,7 @@ static void sliceShort64VectorTestsMasked(IntFunction fa, IntFunction vmask = VectorMask.fromArray(SPECIES, mask, 0); short[] r = new short[a.length]; - int origin = (new java.util.Random()).nextInt(SPECIES.length()); + int origin = RAND.nextInt(SPECIES.length()); for (int ic = 0; ic < INVOC_COUNT; ic++) { for (int i = 0; i < a.length; i += SPECIES.length()) { ShortVector av = ShortVector.fromArray(SPECIES, a, i); @@ -4824,7 +4827,7 @@ static short[] unsliceUnary(short[] a, int origin, int idx) { static void unsliceUnaryShort64VectorTests(IntFunction fa) { short[] a = fa.apply(SPECIES.length()); short[] r = new short[a.length]; - int origin = (new java.util.Random()).nextInt(SPECIES.length()); + int origin = RAND.nextInt(SPECIES.length()); for (int ic = 0; ic < INVOC_COUNT; ic++) { for (int i = 0; i < a.length; i += SPECIES.length()) { ShortVector av = ShortVector.fromArray(SPECIES, a, i); @@ -4862,8 +4865,8 @@ static void unsliceBinaryShort64VectorTestsBinary(IntFunction fa, IntFu short[] a = fa.apply(SPECIES.length()); short[] b = fb.apply(SPECIES.length()); short[] r = new short[a.length]; - int origin = (new java.util.Random()).nextInt(SPECIES.length()); - int part = (new java.util.Random()).nextInt(2); + int origin = RAND.nextInt(SPECIES.length()); + int part = RAND.nextInt(2); for (int ic = 0; ic < INVOC_COUNT; ic++) { for (int i = 0; i < a.length; i += SPECIES.length()) { ShortVector av = ShortVector.fromArray(SPECIES, a, i); @@ -4919,8 +4922,8 @@ static void unsliceShort64VectorTestsMasked(IntFunction fa, IntFunction boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); short[] r = new short[a.length]; - int origin = (new java.util.Random()).nextInt(SPECIES.length()); - int part = (new java.util.Random()).nextInt(2); + int origin = RAND.nextInt(SPECIES.length()); + int part = RAND.nextInt(2); for (int ic = 0; ic < INVOC_COUNT; ic++) { for (int i = 0; i < a.length; i += SPECIES.length()) { ShortVector av = ShortVector.fromArray(SPECIES, a, i); diff --git a/test/jdk/jdk/incubator/vector/ShortMaxVectorLoadStoreTests.java b/test/jdk/jdk/incubator/vector/ShortMaxVectorLoadStoreTests.java index 10621a68b6b..90070d44389 100644 --- a/test/jdk/jdk/incubator/vector/ShortMaxVectorLoadStoreTests.java +++ b/test/jdk/jdk/incubator/vector/ShortMaxVectorLoadStoreTests.java @@ -23,6 +23,9 @@ /* * @test + * @key randomness + * + * @library /test/lib * @modules jdk.incubator.vector java.base/jdk.internal.vm.annotation * @run testng/othervm --add-opens jdk.incubator.vector/jdk.incubator.vector=ALL-UNNAMED * -XX:-TieredCompilation ShortMaxVectorLoadStoreTests diff --git a/test/jdk/jdk/incubator/vector/ShortMaxVectorTests.java b/test/jdk/jdk/incubator/vector/ShortMaxVectorTests.java index 4a6adbf2c8e..7b00638878d 100644 --- a/test/jdk/jdk/incubator/vector/ShortMaxVectorTests.java +++ b/test/jdk/jdk/incubator/vector/ShortMaxVectorTests.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 @@ -23,6 +23,9 @@ /* * @test + * @key randomness + * + * @library /test/lib * @modules jdk.incubator.vector * @run testng/othervm/timeout=300 -ea -esa -Xbatch -XX:-TieredCompilation ShortMaxVectorTests */ @@ -4737,7 +4740,7 @@ static short[] sliceUnary(short[] a, int origin, int idx) { static void sliceUnaryShortMaxVectorTests(IntFunction fa) { short[] a = fa.apply(SPECIES.length()); short[] r = new short[a.length]; - int origin = (new java.util.Random()).nextInt(SPECIES.length()); + int origin = RAND.nextInt(SPECIES.length()); for (int ic = 0; ic < INVOC_COUNT; ic++) { for (int i = 0; i < a.length; i += SPECIES.length()) { ShortVector av = ShortVector.fromArray(SPECIES, a, i); @@ -4766,7 +4769,7 @@ static void sliceBinaryShortMaxVectorTestsBinary(IntFunction fa, IntFun short[] a = fa.apply(SPECIES.length()); short[] b = fb.apply(SPECIES.length()); short[] r = new short[a.length]; - int origin = (new java.util.Random()).nextInt(SPECIES.length()); + int origin = RAND.nextInt(SPECIES.length()); for (int ic = 0; ic < INVOC_COUNT; ic++) { for (int i = 0; i < a.length; i += SPECIES.length()) { ShortVector av = ShortVector.fromArray(SPECIES, a, i); @@ -4800,7 +4803,7 @@ static void sliceShortMaxVectorTestsMasked(IntFunction fa, IntFunction< VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); short[] r = new short[a.length]; - int origin = (new java.util.Random()).nextInt(SPECIES.length()); + int origin = RAND.nextInt(SPECIES.length()); for (int ic = 0; ic < INVOC_COUNT; ic++) { for (int i = 0; i < a.length; i += SPECIES.length()) { ShortVector av = ShortVector.fromArray(SPECIES, a, i); @@ -4829,7 +4832,7 @@ static short[] unsliceUnary(short[] a, int origin, int idx) { static void unsliceUnaryShortMaxVectorTests(IntFunction fa) { short[] a = fa.apply(SPECIES.length()); short[] r = new short[a.length]; - int origin = (new java.util.Random()).nextInt(SPECIES.length()); + int origin = RAND.nextInt(SPECIES.length()); for (int ic = 0; ic < INVOC_COUNT; ic++) { for (int i = 0; i < a.length; i += SPECIES.length()) { ShortVector av = ShortVector.fromArray(SPECIES, a, i); @@ -4867,8 +4870,8 @@ static void unsliceBinaryShortMaxVectorTestsBinary(IntFunction fa, IntF short[] a = fa.apply(SPECIES.length()); short[] b = fb.apply(SPECIES.length()); short[] r = new short[a.length]; - int origin = (new java.util.Random()).nextInt(SPECIES.length()); - int part = (new java.util.Random()).nextInt(2); + int origin = RAND.nextInt(SPECIES.length()); + int part = RAND.nextInt(2); for (int ic = 0; ic < INVOC_COUNT; ic++) { for (int i = 0; i < a.length; i += SPECIES.length()) { ShortVector av = ShortVector.fromArray(SPECIES, a, i); @@ -4924,8 +4927,8 @@ static void unsliceShortMaxVectorTestsMasked(IntFunction fa, IntFunctio boolean[] mask = fm.apply(SPECIES.length()); VectorMask vmask = VectorMask.fromArray(SPECIES, mask, 0); short[] r = new short[a.length]; - int origin = (new java.util.Random()).nextInt(SPECIES.length()); - int part = (new java.util.Random()).nextInt(2); + int origin = RAND.nextInt(SPECIES.length()); + int part = RAND.nextInt(2); for (int ic = 0; ic < INVOC_COUNT; ic++) { for (int i = 0; i < a.length; i += SPECIES.length()) { ShortVector av = ShortVector.fromArray(SPECIES, a, i); diff --git a/test/jdk/jdk/incubator/vector/templates/Kernel-Slice-Masked-bop.template b/test/jdk/jdk/incubator/vector/templates/Kernel-Slice-Masked-bop.template index 5d63264bc62..37dba9b6834 100644 --- a/test/jdk/jdk/incubator/vector/templates/Kernel-Slice-Masked-bop.template +++ b/test/jdk/jdk/incubator/vector/templates/Kernel-Slice-Masked-bop.template @@ -4,7 +4,7 @@ VectorMask<$Wideboxtype$> vmask = VectorMask.fromArray(SPECIES, mask, 0); $type$[] r = new $type$[a.length]; - int origin = (new java.util.Random()).nextInt(SPECIES.length()); + int origin = RAND.nextInt(SPECIES.length()); for (int ic = 0; ic < INVOC_COUNT; ic++) { for (int i = 0; i < a.length; i += SPECIES.length()) { $abstractvectortype$ av = $abstractvectortype$.fromArray(SPECIES, a, i); diff --git a/test/jdk/jdk/incubator/vector/templates/Kernel-Slice-bop.template b/test/jdk/jdk/incubator/vector/templates/Kernel-Slice-bop.template index cb05df34431..5be74dc67ff 100644 --- a/test/jdk/jdk/incubator/vector/templates/Kernel-Slice-bop.template +++ b/test/jdk/jdk/incubator/vector/templates/Kernel-Slice-bop.template @@ -1,7 +1,7 @@ $type$[] a = fa.apply(SPECIES.length()); $type$[] b = fb.apply(SPECIES.length()); $type$[] r = new $type$[a.length]; - int origin = (new java.util.Random()).nextInt(SPECIES.length()); + int origin = RAND.nextInt(SPECIES.length()); for (int ic = 0; ic < INVOC_COUNT; ic++) { for (int i = 0; i < a.length; i += SPECIES.length()) { $abstractvectortype$ av = $abstractvectortype$.fromArray(SPECIES, a, i); diff --git a/test/jdk/jdk/incubator/vector/templates/Kernel-Slice-op.template b/test/jdk/jdk/incubator/vector/templates/Kernel-Slice-op.template index ef313a90f94..82faf4afc91 100644 --- a/test/jdk/jdk/incubator/vector/templates/Kernel-Slice-op.template +++ b/test/jdk/jdk/incubator/vector/templates/Kernel-Slice-op.template @@ -1,6 +1,6 @@ $type$[] a = fa.apply(SPECIES.length()); $type$[] r = new $type$[a.length]; - int origin = (new java.util.Random()).nextInt(SPECIES.length()); + int origin = RAND.nextInt(SPECIES.length()); for (int ic = 0; ic < INVOC_COUNT; ic++) { for (int i = 0; i < a.length; i += SPECIES.length()) { $abstractvectortype$ av = $abstractvectortype$.fromArray(SPECIES, a, i); diff --git a/test/jdk/jdk/incubator/vector/templates/Kernel-Unslice-Masked-bop.template b/test/jdk/jdk/incubator/vector/templates/Kernel-Unslice-Masked-bop.template index d575f48c003..203b4ff8a2d 100644 --- a/test/jdk/jdk/incubator/vector/templates/Kernel-Unslice-Masked-bop.template +++ b/test/jdk/jdk/incubator/vector/templates/Kernel-Unslice-Masked-bop.template @@ -3,8 +3,8 @@ boolean[] mask = fm.apply(SPECIES.length()); VectorMask<$Wideboxtype$> vmask = VectorMask.fromArray(SPECIES, mask, 0); $type$[] r = new $type$[a.length]; - int origin = (new java.util.Random()).nextInt(SPECIES.length()); - int part = (new java.util.Random()).nextInt(2); + int origin = RAND.nextInt(SPECIES.length()); + int part = RAND.nextInt(2); for (int ic = 0; ic < INVOC_COUNT; ic++) { for (int i = 0; i < a.length; i += SPECIES.length()) { $abstractvectortype$ av = $abstractvectortype$.fromArray(SPECIES, a, i); diff --git a/test/jdk/jdk/incubator/vector/templates/Kernel-Unslice-bop.template b/test/jdk/jdk/incubator/vector/templates/Kernel-Unslice-bop.template index 4f39f2fce6c..ab11cdb7d2e 100644 --- a/test/jdk/jdk/incubator/vector/templates/Kernel-Unslice-bop.template +++ b/test/jdk/jdk/incubator/vector/templates/Kernel-Unslice-bop.template @@ -1,8 +1,8 @@ $type$[] a = fa.apply(SPECIES.length()); $type$[] b = fb.apply(SPECIES.length()); $type$[] r = new $type$[a.length]; - int origin = (new java.util.Random()).nextInt(SPECIES.length()); - int part = (new java.util.Random()).nextInt(2); + int origin = RAND.nextInt(SPECIES.length()); + int part = RAND.nextInt(2); for (int ic = 0; ic < INVOC_COUNT; ic++) { for (int i = 0; i < a.length; i += SPECIES.length()) { $abstractvectortype$ av = $abstractvectortype$.fromArray(SPECIES, a, i); diff --git a/test/jdk/jdk/incubator/vector/templates/Kernel-Unslice-op.template b/test/jdk/jdk/incubator/vector/templates/Kernel-Unslice-op.template index b9cd6118f58..6394e4dd2e9 100644 --- a/test/jdk/jdk/incubator/vector/templates/Kernel-Unslice-op.template +++ b/test/jdk/jdk/incubator/vector/templates/Kernel-Unslice-op.template @@ -1,6 +1,6 @@ $type$[] a = fa.apply(SPECIES.length()); $type$[] r = new $type$[a.length]; - int origin = (new java.util.Random()).nextInt(SPECIES.length()); + int origin = RAND.nextInt(SPECIES.length()); for (int ic = 0; ic < INVOC_COUNT; ic++) { for (int i = 0; i < a.length; i += SPECIES.length()) { $abstractvectortype$ av = $abstractvectortype$.fromArray(SPECIES, a, i); diff --git a/test/jdk/jdk/incubator/vector/templates/Unit-header.template b/test/jdk/jdk/incubator/vector/templates/Unit-header.template index 4d3795ea3d1..bc1ee75a5c6 100644 --- a/test/jdk/jdk/incubator/vector/templates/Unit-header.template +++ b/test/jdk/jdk/incubator/vector/templates/Unit-header.template @@ -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 @@ -23,6 +23,9 @@ /* * @test + * @key randomness + * + * @library /test/lib * @modules jdk.incubator.vector * @run testng/othervm/timeout=300 -ea -esa -Xbatch -XX:-TieredCompilation $vectorteststype$ */ diff --git a/test/jdk/jdk/incubator/vector/templates/X-LoadStoreTest.java.template b/test/jdk/jdk/incubator/vector/templates/X-LoadStoreTest.java.template index a2c642b7a86..6473016a9a0 100644 --- a/test/jdk/jdk/incubator/vector/templates/X-LoadStoreTest.java.template +++ b/test/jdk/jdk/incubator/vector/templates/X-LoadStoreTest.java.template @@ -23,6 +23,9 @@ /* * @test + * @key randomness + * + * @library /test/lib * @modules jdk.incubator.vector java.base/jdk.internal.vm.annotation #if[MaxBit] * @run testng/othervm --add-opens jdk.incubator.vector/jdk.incubator.vector=ALL-UNNAMED diff --git a/test/langtools/jdk/javadoc/doclet/testErasure/TestErasure.java b/test/langtools/jdk/javadoc/doclet/testErasure/TestErasure.java new file mode 100644 index 00000000000..3c9f9b6fd9d --- /dev/null +++ b/test/langtools/jdk/javadoc/doclet/testErasure/TestErasure.java @@ -0,0 +1,381 @@ +/* + * 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 8297879 + * @library /tools/lib ../../lib + * @modules jdk.javadoc/jdk.javadoc.internal.tool + * @build toolbox.ToolBox javadoc.tester.* + * @run main TestErasure + */ + +import java.io.IOException; +import java.nio.file.Path; + +import javadoc.tester.JavadocTester; +import toolbox.ToolBox; + +public class TestErasure extends JavadocTester { + + private final ToolBox tb = new ToolBox(); + + public static void main(String... args) throws Exception { + new TestErasure().runTests(); + } + + /* + * Create confusion between: + * - a constructor/method type parameter and a like-named class + * - similarly named but differently bounded constructor type parameters + * - similarly named but differently bounded type parameter in methods + */ + @Test + public void test1(Path base) throws IOException { + Path src = base.resolve("src"); + // - put public class first so that writeJavaFiles is not confused + // on the name of the file it should create + // + // - an _abstract_ class is used only for convenience: like an interface, + // it allows to keep the test minimal, but unlike an interface, it + // allows to test constructors + tb.writeJavaFiles(src, """ + public abstract class Foo { + public Foo(T arg) { } + public Foo(T arg) { } + public Foo(T arg) { } + public abstract T m(T arg); + public abstract T m(T arg); + public abstract T m(T arg); + } + class T { } + class X { } + class Y { } + """); + + javadoc("-d", base.resolve("out").toString(), + src.resolve("Foo.java").toString()); + + checkExit(Exit.OK); + // constructors + checkOutput("Foo.html", true, """ +

+

Constructor Summary

+
Constructors
+
+
Constructor
+
Description
+
\ + Foo(T arg)
+
 
+
\ + Foo(T arg)
+
 
+
\ + Foo(T arg)
+
 
+
+
"""); + checkOutput("Foo.html", true, """ +
  • Constructor Details +
      +
    1. Foo(T)
    2. +
    3. Foo(T)
    4. +
    5. Foo(T)
    6. +
    +
  • """); + checkOutput("index-all.html", true, """ +
    Foo(T)\ + - Constructor for class Foo
    +
     
    +
    Foo(T)\ + - Constructor for class Foo
    +
     
    +
    Foo(T)\ + - Constructor for class Foo
    +
     
    """); + checkOutput("member-search-index.js", true, """ + {"p":"","c":"Foo","l":"Foo(T)","u":"%3Cinit%3E(T)"},\ + {"p":"","c":"Foo","l":"Foo(T)","u":"%3Cinit%3E(X)"},\ + {"p":"","c":"Foo","l":"Foo(T)","u":"%3Cinit%3E(Y)"}"""); + // methods + checkOutput("Foo.html", true, """ +
    abstract T
    +
    m(T arg)
    +
     
    +
    abstract <T extends X>
    T
    +
    m(T arg)
    +
     
    +
    abstract <T extends Y>
    T
    +
    m(T arg)
    +
     
    """); + checkOutput("Foo.html", true, """ +
  • Method Details +
      +
    1. m(T)
    2. +
    3. m(T)
    4. +
    5. m(T)
    6. +
    +
  • """); + checkOutput("index-all.html", true, """ +
    m(T)\ + - Method in class Foo
    +
     
    +
    m(T)\ + - Method in class Foo
    +
     
    +
    m(T)\ + - Method in class Foo
    +
     
    """); + checkOutput("member-search-index.js", true, """ + {"p":"","c":"Foo","l":"m(T)"},\ + {"p":"","c":"Foo","l":"m(T)","u":"m(X)"},\ + {"p":"","c":"Foo","l":"m(T)","u":"m(Y)"}"""); + } + + /* + * Create confusion between the class type parameter + * and a like-named constructor/method type parameter. + */ + @Test + public void test2(Path base) throws IOException { + Path src = base.resolve("src"); + tb.writeJavaFiles(src, """ + public abstract class Foo { + public Foo(T arg) { } + public Foo(T arg) { } + public abstract T m(T arg); + public abstract T m(T arg); + } + class X { } + """); + + javadoc("-d", base.resolve("out").toString(), + src.resolve("Foo.java").toString()); + + checkExit(Exit.OK); + // constructors + checkOutput("Foo.html", true, """ +
    +

    Constructor Summary

    +
    Constructors
    +
    +
    Constructor
    +
    Description
    +
    \ + Foo\ + (T arg)
    +
     
    +
    \ + Foo(T arg)
    +
     
    +
    +
    """); + checkOutput("Foo.html", true, """ +
  • Constructor Details +
      +
    1. Foo(T)
    2. +
    3. Foo(T)
    4. +
    +
  • """); + checkOutput("index-all.html", true, """ +
    Foo(T)\ + - Constructor for class Foo
    +
     
    +
    Foo(T)\ + - Constructor for class Foo
    +
     
    """); + checkOutput("member-search-index.js", true, """ + {"p":"","c":"Foo","l":"Foo(T)","u":"%3Cinit%3E(T)"},\ + {"p":"","c":"Foo","l":"Foo(T)","u":"%3Cinit%3E(X)"}"""); + // methods + checkOutput("Foo.html", true, """ +
    abstract T
    +
    m\ + (T arg)
    +
     
    +
    abstract <T extends X>
    T
    +
    m(T arg)
    +
     
    """); + checkOutput("Foo.html", true, """ +
  • Method Details +
      +
    1. m(T)
    2. +
    3. m(T)
    4. +
    +
  • """); + checkOutput("index-all.html", true, """ +
    m(T)\ + - Method in class Foo
    +
     
    +
    m(T)\ + - Method in class Foo
    +
     
    """); + checkOutput("member-search-index.js", true, """ + {"p":"","c":"Foo","l":"m(T)"},\ + {"p":"","c":"Foo","l":"m(T)","u":"m(X)"}"""); + } + + @Test + public void testNewAndDeprecated(Path base) throws IOException { + Path src = base.resolve("src"); + tb.writeJavaFiles(src, """ + public abstract class Foo { + /** @since today */ + @Deprecated(since="tomorrow") + public Foo(T arg) { } + /** @since today */ + @Deprecated(since="tomorrow") + public Foo(T arg) { } + /** @since today */ + @Deprecated(since="tomorrow") + public Foo(T arg) { } + /** @since today */ + @Deprecated(since="tomorrow") + public abstract T m(T arg); + /** @since today */ + @Deprecated(since="tomorrow") + public abstract T m(T arg); + /** @since today */ + @Deprecated(since="tomorrow") + public abstract T m(T arg); + } + class T { } + class X { } + class Y { } + """); + + javadoc("-d", base.resolve("out").toString(), + "--since", "today", + src.resolve("Foo.java").toString()); + + checkExit(Exit.OK); + checkOutput("new-list.html", true, """ + +
    today
    +
     
    + +
    today
    +
     
    + +
    today
    +
     
    """); + checkOutput("new-list.html", true, """ + +
    today
    +
     
    + +
    today
    +
     
    + +
    today
    +
     
    """); + checkOutput("deprecated-list.html", true, """ + +
    tomorrow
    +
    + +
    tomorrow
    +
    + +
    tomorrow
    +
    """); + checkOutput("deprecated-list.html", true, """ + +
    tomorrow
    +
    + +
    tomorrow
    +
    + +
    tomorrow
    +
    """); + } + + @Test + public void testPreview(Path base) throws IOException { + // unlike that for other tests, here we cannot simulate ambiguity between + // a type parameter and a like-named class, because for that the class + // needs to be in the unnamed package, otherwise its FQN won't be T + Path src = base.resolve("src"); + tb.writeJavaFiles(src, """ + package p; + import jdk.internal.javac.PreviewFeature; + public abstract class Foo { + @PreviewFeature(feature=PreviewFeature.Feature.TEST) + public Foo(T arg) { } + @PreviewFeature(feature=PreviewFeature.Feature.TEST) + public Foo(T arg) { } + @PreviewFeature(feature=PreviewFeature.Feature.TEST) + public abstract T m(T arg); + @PreviewFeature(feature=PreviewFeature.Feature.TEST) + public abstract T m(T arg); + } + class X { } + class Y { } + """); + + javadoc("-d", base.resolve("out").toString(), + "--patch-module", "java.base=" + src.toAbsolutePath().toString(), + src.resolve("p").resolve("Foo.java").toString()); + + checkExit(Exit.OK); + checkOutput("preview-list.html", true, """ + +
    Test Feature
    +
    + +
    Test Feature
    +
    """); + checkOutput("preview-list.html", true, """ + +
    Test Feature
    +
    + +
    Test Feature
    +
    """); + } +} \ No newline at end of file diff --git a/test/langtools/tools/javac/LocalClassCtorPrologue.java b/test/langtools/tools/javac/LocalClassCtorPrologue.java new file mode 100644 index 00000000000..2a7178ed857 --- /dev/null +++ b/test/langtools/tools/javac/LocalClassCtorPrologue.java @@ -0,0 +1,32 @@ +/* + * @test /nodynamiccopyright/ + * @bug 8328649 + * @summary Verify local classes in constructor prologues don't have enclosing instances + * @compile/fail/ref=LocalClassCtorPrologue.out -XDrawDiagnostics LocalClassCtorPrologue.java + * @enablePreview + */ + +class LocalClassCtorPrologue { + + int x; + + LocalClassCtorPrologue() { + class Local { + { + x++; // this should fail + } + } + super(); + } + + public class Inner { + public Inner() { + class Local { + { + x++; // this should work + } + }; + super(); + } + } +} diff --git a/test/langtools/tools/javac/LocalClassCtorPrologue.out b/test/langtools/tools/javac/LocalClassCtorPrologue.out new file mode 100644 index 00000000000..f1a999af491 --- /dev/null +++ b/test/langtools/tools/javac/LocalClassCtorPrologue.out @@ -0,0 +1,4 @@ +LocalClassCtorPrologue.java:16:17: compiler.err.no.encl.instance.of.type.in.scope: LocalClassCtorPrologue +- compiler.note.preview.filename: LocalClassCtorPrologue.java, DEFAULT +- compiler.note.preview.recompile +1 error diff --git a/test/langtools/tools/javac/SuperInit/SuperInitGood.java b/test/langtools/tools/javac/SuperInit/SuperInitGood.java index cbcbee8fef0..f82ee6188f1 100644 --- a/test/langtools/tools/javac/SuperInit/SuperInitGood.java +++ b/test/langtools/tools/javac/SuperInit/SuperInitGood.java @@ -407,32 +407,6 @@ public int hashCode() { } } - // local class declared before super(), but not used until after super() - public static class Test20 { - public Test20() { - class Foo { - Foo() { - Test20.this.hashCode(); - } - } - super(); - new Foo(); - } - } - - // local class inside super() parameter list - public static class Test21 extends AtomicReference { - private int x; - public Test21() { - super(switch ("foo".hashCode()) { - default -> { - class Nested {{ System.out.println(x); }} // class is NOT instantiated - OK - yield "bar"; - } - }); - } - } - public static void main(String[] args) { new Test0(); new Test1(); @@ -474,7 +448,5 @@ public static void main(String[] args) { assert false : "unexpected exception: " + e; } new Test19(123); - new Test20(); - new Test21(); } } diff --git a/test/langtools/tools/javac/T8328747.java b/test/langtools/tools/javac/T8328747.java new file mode 100644 index 00000000000..4c384319ac1 --- /dev/null +++ b/test/langtools/tools/javac/T8328747.java @@ -0,0 +1,126 @@ +/* + * 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 8328747 + * @summary WrongMethodTypeException with pattern matching on switch on sealed classes + * @library /tools/lib + * @modules jdk.compiler/com.sun.tools.javac.api + * jdk.compiler/com.sun.tools.javac.main + * jdk.jdeps/com.sun.tools.javap + * @build toolbox.ToolBox toolbox.JavapTask + * @compile T8328747.java + * @run main T8328747 + */ + +import toolbox.*; + +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; + +public class T8328747 extends TestRunner { + private ToolBox tb; + + public static void main(String... args) throws Exception { + new T8328747().runTests(); + } + + T8328747() { + super(System.err); + tb = new ToolBox(); + } + + public void runTests() throws Exception { + runTests(m -> new Object[] { Paths.get(m.getName()) }); + } + + @Test + public void test(Path base) throws Exception { + Path current = base.resolve("."); + Path src = current.resolve("src"); + Path classes = current.resolve("classes"); + tb.writeJavaFiles(src, + """ + package test; + public class Test { + public static void main(String[] args) { + f(new P()); + f(new O()); + } + + private static void f(I info) { + switch (info) { + case P p -> System.err.println(p); + case O o -> System.err.println(o); + } + } + + static sealed interface I permits P, O {} + private abstract static class A {} + static final class P extends A implements I {} + static final class O extends A implements I {} + } + """); + + Files.createDirectories(classes); + + {//with --release: + new JavacTask(tb) + .options("--release", "21") + .outdir(classes) + .files(tb.findJavaFiles(src)) + .run(Task.Expect.SUCCESS) + .writeAll(); + + String javapOut = new JavapTask(tb) + .options("-v") + .classpath(classes.toString()) + .classes("test.Test") + .run() + .getOutput(Task.OutputKind.DIRECT); + + if (!javapOut.contains("#25 = InvokeDynamic #0:#26 // #0:typeSwitch:(Ljava/lang/Object;I)I")) + throw new AssertionError("typeSwitch for a version less than 23 should accept a static type of java.lang.Object"); + } + + {//without: + new JavacTask(tb) + .outdir(classes) + .files(tb.findJavaFiles(src)) + .run(Task.Expect.SUCCESS) + .writeAll(); + + String javapOut = new JavapTask(tb) + .options("-v") + .classpath(classes.toString()) + .classes("test.Test") + .run() + .getOutput(Task.OutputKind.DIRECT); + + if (!javapOut.contains("#25 = InvokeDynamic #0:#26 // #0:typeSwitch:(Ltest/Test$I;I)I")) + throw new AssertionError("typeSwitch from version 23 and beyond should accept a precise selector type"); + } + } +} diff --git a/test/langtools/tools/javac/lib/JavacTestingAbstractProcessor.java b/test/langtools/tools/javac/lib/JavacTestingAbstractProcessor.java index cf4de078e9e..7b35a0d7f5a 100644 --- a/test/langtools/tools/javac/lib/JavacTestingAbstractProcessor.java +++ b/test/langtools/tools/javac/lib/JavacTestingAbstractProcessor.java @@ -114,7 +114,8 @@ protected void addExports(String moduleName, String... packageNames) { */ @SupportedSourceVersion(RELEASE_23) - public static abstract class AbstractAnnotationValueVisitor extends AbstractAnnotationValueVisitor14 { + @SuppressWarnings("preview") + public static abstract class AbstractAnnotationValueVisitor extends AbstractAnnotationValueVisitorPreview { /** * Constructor for concrete subclasses to call. @@ -125,7 +126,8 @@ protected AbstractAnnotationValueVisitor() { } @SupportedSourceVersion(RELEASE_23) - public static abstract class AbstractElementVisitor extends AbstractElementVisitor14 { + @SuppressWarnings("preview") + public static abstract class AbstractElementVisitor extends AbstractElementVisitorPreview { /** * Constructor for concrete subclasses to call. */ @@ -135,7 +137,8 @@ protected AbstractElementVisitor(){ } @SupportedSourceVersion(RELEASE_23) - public static abstract class AbstractTypeVisitor extends AbstractTypeVisitor14 { + @SuppressWarnings("preview") + public static abstract class AbstractTypeVisitor extends AbstractTypeVisitorPreview { /** * Constructor for concrete subclasses to call. */ @@ -145,7 +148,8 @@ protected AbstractTypeVisitor() { } @SupportedSourceVersion(RELEASE_23) - public static class ElementKindVisitor extends ElementKindVisitor14 { + @SuppressWarnings("preview") + public static class ElementKindVisitor extends ElementKindVisitorPreview { /** * Constructor for concrete subclasses; uses {@code null} for the * default value. @@ -166,7 +170,8 @@ protected ElementKindVisitor(R defaultValue) { } @SupportedSourceVersion(RELEASE_23) - public static class ElementScanner extends ElementScanner14 { + @SuppressWarnings("preview") + public static class ElementScanner extends ElementScannerPreview { /** * Constructor for concrete subclasses; uses {@code null} for the * default value. @@ -185,7 +190,8 @@ protected ElementScanner(R defaultValue){ } @SupportedSourceVersion(RELEASE_23) - public static class SimpleAnnotationValueVisitor extends SimpleAnnotationValueVisitor14 { + @SuppressWarnings("preview") + public static class SimpleAnnotationValueVisitor extends SimpleAnnotationValueVisitorPreview { /** * Constructor for concrete subclasses; uses {@code null} for the * default value. @@ -206,7 +212,8 @@ protected SimpleAnnotationValueVisitor(R defaultValue) { } @SupportedSourceVersion(RELEASE_23) - public static class SimpleElementVisitor extends SimpleElementVisitor14 { + @SuppressWarnings("preview") + public static class SimpleElementVisitor extends SimpleElementVisitorPreview { /** * Constructor for concrete subclasses; uses {@code null} for the * default value. @@ -227,7 +234,8 @@ protected SimpleElementVisitor(R defaultValue){ } @SupportedSourceVersion(RELEASE_23) - public static class SimpleTypeVisitor extends SimpleTypeVisitor14 { + @SuppressWarnings("preview") + public static class SimpleTypeVisitor extends SimpleTypeVisitorPreview { /** * Constructor for concrete subclasses; uses {@code null} for the * default value. @@ -248,7 +256,8 @@ protected SimpleTypeVisitor(R defaultValue){ } @SupportedSourceVersion(RELEASE_23) - public static class TypeKindVisitor extends TypeKindVisitor14 { + @SuppressWarnings("preview") + public static class TypeKindVisitor extends TypeKindVisitorPreview { /** * Constructor for concrete subclasses to call; uses {@code null} * for the default value. diff --git a/test/micro/org/openjdk/bench/vm/compiler/AllocationMerges.java b/test/micro/org/openjdk/bench/vm/compiler/AllocationMerges.java new file mode 100644 index 00000000000..84c6c5c6483 --- /dev/null +++ b/test/micro/org/openjdk/bench/vm/compiler/AllocationMerges.java @@ -0,0 +1,1379 @@ +/* + * Copyright (c) 2023, 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.bench.vm.compiler; + +import org.openjdk.jmh.annotations.*; +import org.openjdk.jmh.infra.*; +import java.util.concurrent.TimeUnit; +import java.util.random.RandomGenerator; +import java.util.random.RandomGeneratorFactory; + +@BenchmarkMode(Mode.AverageTime) +@OutputTimeUnit(TimeUnit.MILLISECONDS) +@State(Scope.Thread) +@Warmup(iterations = 5, time = 2, timeUnit = TimeUnit.SECONDS) +@Measurement(iterations = 5, time = 2, timeUnit = TimeUnit.SECONDS) +@Fork(value = 3) +public abstract class AllocationMerges { + private static final int SIZE = 1000000; + private static final boolean cond1[] = new boolean[SIZE]; + private static final boolean cond2[] = new boolean[SIZE]; + private static final int ws[] = new int[SIZE]; + private static final int xs[] = new int[SIZE]; + private static final int ys[] = new int[SIZE]; + private static final int zs[] = new int[SIZE]; + private static Load global_escape = new Load(2022, 2023); + private RandomGenerator rng = RandomGeneratorFactory.getDefault().create(); + + // ------------------------------------------------------------------------- + + @Setup + public void setup() { + for (int i = 0; i < SIZE; i++) { + cond1[i] = i % 2 == 0; + cond2[i] = i % 2 == 1; + + ws[i] = rng.nextInt(); + xs[i] = rng.nextInt(); + ys[i] = rng.nextInt(); + zs[i] = rng.nextInt(); + } + } + + // ------------------------------------------------------------------------- + + @CompilerControl(CompilerControl.Mode.DONT_INLINE) + int testGlobalEscape(int x, int y) { + Load p = new Load(x, y); + + AllocationMerges.global_escape = p; + + return p.x * p.y; + } + + @Benchmark + public void testGlobalEscape_runner(Blackhole bh) { + int result = 0; + for (int i = 0 ; i < SIZE; i++) { + result += testGlobalEscape(xs[i], ys[i]); + } + bh.consume(result); + } + + // ------------------------------------------------------------------------- + + @CompilerControl(CompilerControl.Mode.DONT_INLINE) + int testArgEscape(int x, int y) { + Load p = new Load(x, y); + + int val = dummy(p); + + return val + p.x + p.y; + } + + @Benchmark + public void testArgEscape_runner(Blackhole bh) { + int result = 0; + for (int i = 0 ; i < SIZE; i++) { + result += testArgEscape(xs[i], ys[i]); + } + bh.consume(result); + } + + // ------------------------------------------------------------------------- + + @CompilerControl(CompilerControl.Mode.DONT_INLINE) + int testEscapeInCallAfterMerge(boolean cond, boolean cond2, int x, int y) { + Load p = new Load(x, x); + + if (cond) { + p = new Load(y, y); + } + + if (cond2) { + dummy(p); + } + + return p.x * p.y; + } + + @Benchmark + public void testEscapeInCallAfterMerge_runner(Blackhole bh) { + int result = 0; + for (int i = 0 ; i < SIZE; i++) { + result += testEscapeInCallAfterMerge(cond1[i], cond2[i], xs[i], ys[i]); + } + bh.consume(result); + } + + // ------------------------------------------------------------------------- + + @CompilerControl(CompilerControl.Mode.DONT_INLINE) + int testNoEscapeWithWriteInLoop(boolean cond, boolean cond2, int x, int y) { + Load p = new Load(x, y); + int res = 0; + + if (cond) { + p = new Load(y, x); + } + + for (int i=0; i<100; i++) { + p.x += p.y + i; + p.y += p.x + i; + } + + return res + p.x + p.y; + } + + @Benchmark + public void testNoEscapeWithWriteInLoop_runner(Blackhole bh) { + int result = 0; + for (int i = 0 ; i < SIZE; i++) { + result += testNoEscapeWithWriteInLoop(cond1[i], cond2[i], xs[i], ys[i]); + } + bh.consume(result); + } + + // ------------------------------------------------------------------------- + + @CompilerControl(CompilerControl.Mode.DONT_INLINE) + int testPollutedWithWrite(boolean cond, int l) { + Shape obj1 = new Square(l); + Shape obj2 = new Square(l); + Shape obj = null; + + if (cond) { + obj = obj1; + } else { + obj = obj2; + } + + for (int i=1; i<132; i++) { + obj.x++; + } + + return obj1.x + obj2.y; + } + + @Benchmark + public void testPollutedWithWrite_runner(Blackhole bh) { + int result = 0; + for (int i = 0 ; i < SIZE; i++) { + result += testPollutedWithWrite(cond1[i], xs[i]); + } + bh.consume(result); + } + + // ------------------------------------------------------------------------- + @CompilerControl(CompilerControl.Mode.DONT_INLINE) + int testPollutedPolymorphic(boolean cond, int l) { + Shape obj1 = new Square(l); + Shape obj2 = new Circle(l); + Shape obj = (cond ? obj1 : obj2); + int res = 0; + + for (int i=1; i<232; i++) { + res += obj.x; + } + + return res + obj1.x + obj2.y; + } + + @Benchmark + public void testPollutedPolymorphic_runner(Blackhole bh) { + int result = 0; + for (int i = 0 ; i < SIZE; i++) { + result += testPollutedPolymorphic(cond1[i], xs[i]); + } + bh.consume(result); + } + + // ------------------------------------------------------------------------- + + @CompilerControl(CompilerControl.Mode.DONT_INLINE) + int testMergedLoadAfterDirectStore(boolean cond, int x, int y) { + Load p0 = new Load(x, x); + Load p1 = new Load(y, y); + Load p = null; + + if (cond) { + p = p0; + } else { + p = p1; + } + + p0.x = x * y; + + return p.x; + } + + @Benchmark + public void testMergedLoadAfterDirectStore_runner(Blackhole bh) { + int result = 0; + for (int i = 0 ; i < SIZE; i++) { + result += testMergedLoadAfterDirectStore(cond1[i], xs[i], ys[i]); + } + bh.consume(result); + } + + // ------------------------------------------------------------------------- + + @CompilerControl(CompilerControl.Mode.DONT_INLINE) + int testMergedAccessAfterCallWithWrite(boolean cond, int x, int y) { + Load p2 = new Load(x, x); + Load p = new Load(y, y); + + p.x = p.x * y; + + if (cond) { + p = new Load(x, x); + } + + dummy(p2); + + for (int i=3; i<324; i++) { + p.x += i * x; + } + + return p.x; + } + + @Benchmark + public void testMergedAccessAfterCallWithWrite_runner(Blackhole bh) { + int result = 0; + for (int i = 0 ; i < SIZE; i++) { + result += testMergedAccessAfterCallWithWrite(cond1[i], xs[i], ys[i]); + } + bh.consume(result); + } + + // ------------------------------------------------------------------------- + + @CompilerControl(CompilerControl.Mode.DONT_INLINE) + int testLoadAfterTrap(boolean cond, int x, int y) { + Load p = null; + + if (cond) { + p = new Load(x, x); + } else { + p = new Load(y, y); + } + + dummy(x+y); + + return p.x + p.y; + } + + @Benchmark + public void testLoadAfterTrap_runner(Blackhole bh) { + int result = 0; + for (int i = 0 ; i < SIZE; i++) { + result += testLoadAfterTrap(cond1[i], xs[i], ys[i]); + } + bh.consume(result); + } + + // ------------------------------------------------------------------------- + + @CompilerControl(CompilerControl.Mode.DONT_INLINE) + int testCondAfterMergeWithNull(boolean cond1, boolean cond2, int x, int y) { + Load p = null; + + if (cond1) { + p = new Load(y, x); + } + + if (cond2 && cond1) { + return p.x; + } else { + return 321; + } + } + + @Benchmark + public void testCondAfterMergeWithNull_runner(Blackhole bh) { + int result = 0; + for (int i = 0 ; i < SIZE; i++) { + result += testCondAfterMergeWithNull(cond1[i], cond2[i], xs[i], ys[i]); + } + bh.consume(result); + } + + // ------------------------------------------------------------------------- + + @CompilerControl(CompilerControl.Mode.DONT_INLINE) + int testLoadAfterLoopAlias(boolean cond, int x, int y) { + Load a = new Load(x, y); + Load b = new Load(y, x); + Load c = a; + + for (int i=10; i<232; i++) { + if (i == x) { + c = b; + } + } + + return cond ? c.x : c.y; + } + + @Benchmark + public void testLoadAfterLoopAlias_runner(Blackhole bh) { + int result = 0; + for (int i = 0 ; i < SIZE; i++) { + result += testLoadAfterLoopAlias(cond1[i], xs[i], ys[i]); + } + bh.consume(result); + } + + // ------------------------------------------------------------------------- + + @CompilerControl(CompilerControl.Mode.DONT_INLINE) + int testCallTwoSide(boolean cond1, int x, int y) { + Load p = dummy(x, y); + + if (cond1) { + p = dummy(y, x); + } + + return (p != null) ? p.x : 0; + } + + @Benchmark + public void testCallTwoSide_runner(Blackhole bh) { + int result = 0; + for (int i = 0 ; i < SIZE; i++) { + result += testCallTwoSide(cond1[i], xs[i], ys[i]); + } + bh.consume(result); + } + + // ------------------------------------------------------------------------- + + @CompilerControl(CompilerControl.Mode.DONT_INLINE) + int testMergedAccessAfterCallNoWrite(boolean cond, int x, int y) { + Load p2 = new Load(x, x); + Load p = new Load(y, y); + int res = 0; + + p.x = p.x * y; + + if (cond) { + p = new Load(y, y); + } + + dummy(p2); + + for (int i=3; i<324; i++) { + res += p.x + i * x; + } + + return res; + } + + @Benchmark + public void testMergedAccessAfterCallNoWrite_runner(Blackhole bh) { + int result = 0; + for (int i = 0 ; i < SIZE; i++) { + result += testMergedAccessAfterCallNoWrite(cond1[i], xs[i], ys[i]); + } + bh.consume(result); + } + + // ------------------------------------------------------------------------- + + @CompilerControl(CompilerControl.Mode.DONT_INLINE) + int testCmpMergeWithNull_Second(boolean cond, int x, int y) { + Load p = null; + + if (cond) { + p = new Load(x*x, y*y); + } + + dummy(x); + + if (p != null) { + return p.x * p.y; + } else { + return 1984; + } + } + + @Benchmark + public void testCmpMergeWithNull_Second_runner(Blackhole bh) { + int result = 0; + for (int i = 0 ; i < SIZE; i++) { + result += testCmpMergeWithNull_Second(cond1[i], xs[i], ys[i]); + } + bh.consume(result); + } + + // ------------------------------------------------------------------------- + + @CompilerControl(CompilerControl.Mode.DONT_INLINE) + int testObjectIdentity(boolean cond, int x, int y) { + Load o = new Load(x, y); + + if (cond && x == 42) { + o = global_escape; + } + + return o.x + o.y; + } + + @Benchmark + public void testObjectIdentity_runner(Blackhole bh) { + int result = 0; + for (int i = 0 ; i < SIZE; i++) { + result += testObjectIdentity(cond1[i], xs[i], ys[i]); + } + bh.consume(result); + } + + // ------------------------------------------------------------------------- + + @CompilerControl(CompilerControl.Mode.DONT_INLINE) + int testSubclassesTrapping(boolean c1, boolean c2, int x, int y, int w, int z) { + new A(); + Root s = new Home(x, y); + new B(); + + if (c1) { + new C(); + s = new Etc("Hello"); + new D(); + } else { + new E(); + s = new Usr(y, x, z); + new F(); + } + + int res = s.a; + dummy(); + + return res; + } + + @Benchmark + public void testSubclassesTrapping_runner(Blackhole bh) { + int result = 0; + for (int i = 0 ; i < SIZE; i++) { + result += testSubclassesTrapping(cond1[i], cond2[i], xs[i], ys[i], ws[i], zs[i]); + } + bh.consume(result); + } + + // ------------------------------------------------------------------------- + + @CompilerControl(CompilerControl.Mode.DONT_INLINE) + int testCmpMergeWithNull(boolean cond, int x, int y) { + Load p = null; + + if (cond) { + p = new Load(x*x, y*y); + } else if (x > y) { + p = new Load(x+y, x*y); + } + + if (p != null) { + return p.x * p.y; + } else { + return 1984; + } + } + + @Benchmark + public void testCmpMergeWithNull_runner(Blackhole bh) { + int result = 0; + for (int i = 0 ; i < SIZE; i++) { + result += testCmpMergeWithNull(cond1[i], xs[i], ys[i]); + } + bh.consume(result); + } + + // ------------------------------------------------------------------------- + + @CompilerControl(CompilerControl.Mode.DONT_INLINE) + int testSubclasses(boolean c1, boolean c2, int x, int y, int w, int z) { + new A(); + Root s = new Home(x, y); + new B(); + + if (c1) { + new C(); + s = new Etc("Hello"); + new D(); + } else { + new E(); + s = new Usr(y, x, z); + new F(); + } + + new G(); + + return s.a; + } + + @Benchmark + public void testSubclasses_runner(Blackhole bh) { + int result = 0; + for (int i = 0 ; i < SIZE; i++) { + result += testSubclasses(cond1[i], cond2[i], xs[i], ys[i], ws[i], zs[i]); + } + bh.consume(result); + } + + // ------------------ Some Scalar Replacement Should Happen in The Tests Below ------------------- // + + @CompilerControl(CompilerControl.Mode.DONT_INLINE) + int testPartialPhis(boolean cond, int l, int x, int y) { + int k = l; + + if (l == 0) { + k = l + 1; + } else if (l == 2) { + k = l + 2; + } else if (l == 3) { + new Load(x, y); + } else if (l == 4) { + new Load(y, x); + } + + return k; + } + + @Benchmark + public void testPartialPhis_runner(Blackhole bh) { + int result = 0; + for (int i = 0 ; i < SIZE; i++) { + result += testPartialPhis(cond1[i], xs[i], ys[i], zs[i]); + } + bh.consume(result); + } + + // ------------------------------------------------------------------------- + + @CompilerControl(CompilerControl.Mode.DONT_INLINE) + int testPollutedNoWrite(boolean cond, int l) { + Shape obj1 = new Square(l); + Shape obj2 = new Square(l); + Shape obj = null; + int res = 0; + + if (cond) { + obj = obj1; + } else { + obj = obj2; + } + + for (int i=1; i<132; i++) { + res += obj.x; + } + + return res + obj1.x + obj2.y; + } + + @Benchmark + public void testPollutedNoWrite_runner(Blackhole bh) { + int result = 0; + for (int i = 0 ; i < SIZE; i++) { + result += testPollutedNoWrite(cond1[i], xs[i]); + } + bh.consume(result); + } + + // ------------------------------------------------------------------------- + + @CompilerControl(CompilerControl.Mode.DONT_INLINE) + int testThreeWayAliasedAlloc(boolean cond, int x, int y) { + Load p1 = new Load(x, y); + Load p2 = new Load(x+1, y+1); + Load p3 = new Load(x+2, y+2); + + if (cond) { + p3 = p1; + } else { + p3 = p2; + } + + return p3.x + p3.y; + } + + @Benchmark + public void testThreeWayAliasedAlloc_runner(Blackhole bh) { + int result = 0; + for (int i = 0 ; i < SIZE; i++) { + result += testThreeWayAliasedAlloc(cond1[i], xs[i], ys[i]); + } + bh.consume(result); + } + + // ------------------------------------------------------------------------- + + @CompilerControl(CompilerControl.Mode.DONT_INLINE) + int TestTrapAfterMerge(boolean cond, int x, int y) { + Load p = new Load(x, x); + + if (cond) { + p = new Load(y, y); + } + + for (int i=402; i<432; i+=x) { + x++; + } + + return p.x + x; + } + + @Benchmark + public void TestTrapAfterMerge_runner(Blackhole bh) { + int result = 0; + for (int i = 0 ; i < SIZE; i++) { + result += TestTrapAfterMerge(cond1[i], xs[i], ys[i]); + } + bh.consume(result); + } + + // ------------------------------------------------------------------------- + + @CompilerControl(CompilerControl.Mode.DONT_INLINE) + Load testNestedObjectsObject(boolean cond, int x, int y) { + Picture p = new Picture(x, x, y); + + if (cond) { + p = new Picture(y, y, x); + } + + return p.position; + } + + @Benchmark + public void testNestedObjectsObject_runner(Blackhole bh) { + int result = 0; + for (int i = 0 ; i < SIZE; i++) { + result += testNestedObjectsObject(cond1[i], xs[i], ys[i]).x; + } + bh.consume(result); + } + + // ------------------------------------------------------------------------- + + @CompilerControl(CompilerControl.Mode.DONT_INLINE) + int testNestedObjectsNoEscapeObject(boolean cond, int x, int y) { + Picture p = new Picture(x, x, y); + + if (cond) { + p = new Picture(y, y, x); + } + + return p.position.x; + } + + @Benchmark + public void testNestedObjectsNoEscapeObject_runner(Blackhole bh) { + int result = 0; + for (int i = 0 ; i < SIZE; i++) { + result += testNestedObjectsNoEscapeObject(cond1[i], xs[i], ys[i]); + } + bh.consume(result); + } + + // ------------------------------------------------------------------------- + + @CompilerControl(CompilerControl.Mode.DONT_INLINE) + Load[] testNestedObjectsArray(boolean cond, int x, int y) { + PicturePositions p = new PicturePositions(x, y, x+y); + + if (cond) { + p = new PicturePositions(x+1, y+1, x+y+1); + } + + return p.positions; + } + + @Benchmark + public void testNestedObjectsArray_runner(Blackhole bh) { + int result = 0; + for (int i = 0 ; i < SIZE; i++) { + Load[] partial = testNestedObjectsArray(cond1[i], xs[i], ys[i]); + result += partial[0].x; + } + bh.consume(result); + } + + // ------------------------------------------------------------------------- + + @CompilerControl(CompilerControl.Mode.DONT_INLINE) + int testTrappingAfterMerge(boolean cond, int x, int y) { + Load p = new Load(x, y); + int res = 0; + + if (cond) { + p = new Load(y, y); + } + + for (int i=832; i<932; i++) { + res += p.x; + } + + if (x > y) { + res += new Load(p.x, p.y).x; + } + + return res; + } + + @Benchmark + public void testTrappingAfterMerge_runner(Blackhole bh) { + int result = 0; + for (int i = 0 ; i < SIZE; i++) { + result += testTrappingAfterMerge(cond1[i], xs[i], ys[i]); + } + bh.consume(result); + } + + // ------------------------------------------------------------------------- + + @CompilerControl(CompilerControl.Mode.DONT_INLINE) + int testSimpleAliasedAlloc(boolean cond, int x, int y) { + Load p1 = new Load(x, y); + Load p2 = new Load(y, x); + Load p = p1; + + if (cond) { + p = p2; + } + + return p.x * p.y; + } + + @Benchmark + public void testSimpleAliasedAlloc_runner(Blackhole bh) { + int result = 0; + for (int i = 0 ; i < SIZE; i++) { + result += testSimpleAliasedAlloc(cond1[i], xs[i], ys[i]); + } + bh.consume(result); + } + + // ------------------------------------------------------------------------- + + @CompilerControl(CompilerControl.Mode.DONT_INLINE) + int testSimpleDoubleMerge(boolean cond, int x, int y) { + Load p1 = new Load(x, y); + Load p2 = new Load(x+1, y+1); + + if (cond) { + p1 = new Load(y, x); + p2 = new Load(y+1, x+1); + } + + return p1.x + p2.y; + } + + @Benchmark + public void testSimpleDoubleMerge_runner(Blackhole bh) { + int result = 0; + for (int i = 0 ; i < SIZE; i++) { + result += testSimpleDoubleMerge(cond1[i], xs[i], ys[i]); + } + bh.consume(result); + } + + // ------------------------------------------------------------------------- + + @CompilerControl(CompilerControl.Mode.DONT_INLINE) + int testConsecutiveSimpleMerge(boolean cond1, boolean cond2, int x, int y) { + Load p0 = new Load(x, x); + Load p1 = new Load(x, y); + Load pA = null; + + Load p2 = new Load(y, x); + Load p3 = new Load(y, y); + Load pB = null; + + if (cond1) { + pA = p0; + } else { + pA = p1; + } + + if (cond2) { + pB = p2; + } else { + pB = p3; + } + + return pA.x * pA.y + pB.x * pB.y; + } + + @Benchmark + public void testConsecutiveSimpleMerge_runner(Blackhole bh) { + int result = 0; + for (int i = 0 ; i < SIZE; i++) { + result += testConsecutiveSimpleMerge(cond1[i], cond2[i], xs[i], ys[i]); + } + bh.consume(result); + } + + // ------------------------------------------------------------------------- + + @CompilerControl(CompilerControl.Mode.DONT_INLINE) + int testDoubleIfElseMerge(boolean cond, int x, int y) { + Load p1 = new Load(x, y); + Load p2 = new Load(x+1, y+1); + + if (cond) { + p1 = new Load(y, x); + p2 = new Load(y, x); + } else { + p1 = new Load(x, y); + p2 = new Load(x+1, y+1); + } + + return p1.x * p2.y; + } + + @Benchmark + public void testDoubleIfElseMerge_runner(Blackhole bh) { + int result = 0; + for (int i = 0 ; i < SIZE; i++) { + result += testDoubleIfElseMerge(cond1[i], xs[i], ys[i]); + } + bh.consume(result); + } + + // ------------------------------------------------------------------------- + + @CompilerControl(CompilerControl.Mode.DONT_INLINE) + int testNoEscapeWithLoadInLoop(boolean cond, int x, int y) { + Load p = new Load(x, y); + int res = 0; + + if (cond) { + p = new Load(y, x); + } + + for (int i=3342; i<4234; i++) { + res += p.x + p.y + i; + } + + return res + p.x + p.y; + } + + @Benchmark + public void testNoEscapeWithLoadInLoop_runner(Blackhole bh) { + int result = 0; + for (int i = 0 ; i < SIZE; i++) { + result += testNoEscapeWithLoadInLoop(cond1[i], xs[i], ys[i]); + } + bh.consume(result); + } + + // ------------------------------------------------------------------------- + + @CompilerControl(CompilerControl.Mode.DONT_INLINE) + int testCmpAfterMerge(boolean cond, boolean cond2, int x, int y) { + Load a = new Load(x, y); + Load b = new Load(y, x); + Load c = null; + + if (x+2 >= y-5) { + c = a; + } else { + c = b; + } + + return cond2 ? c.x : c.y; + } + + @Benchmark + public void testCmpAfterMerge_runner(Blackhole bh) { + int result = 0; + for (int i = 0 ; i < SIZE; i++) { + result += testCmpAfterMerge(cond1[i], cond2[i], xs[i], ys[i]); + } + bh.consume(result); + } + + // ------------------------------------------------------------------------- + + @CompilerControl(CompilerControl.Mode.DONT_INLINE) + int testCondAfterMergeWithAllocate(boolean cond1, boolean cond2, int x, int y) { + Load p = new Load(x, y); + + if (cond1) { + p = new Load(y, x); + } + + if (cond2 && cond1) { + return p.x; + } else { + return 321; + } + } + + @Benchmark + public void testCondAfterMergeWithAllocate_runner(Blackhole bh) { + int result = 0; + for (int i = 0 ; i < SIZE; i++) { + result += testCondAfterMergeWithAllocate(cond1[i], cond2[i], xs[i], ys[i]); + } + bh.consume(result); + } + + // ------------------------------------------------------------------------- + + @CompilerControl(CompilerControl.Mode.DONT_INLINE) + int testCondLoadAfterMerge(boolean cond1, boolean cond2, int x, int y) { + Load p = new Load(x, y); + + if (cond1) { + p = new Load(y, x); + } + + if (cond1 == false && cond2 == false) { + return p.x + 1; + } else if (cond1 == false && cond2 == true) { + return p.x + 30; + } else if (cond1 == true && cond2 == false) { + return p.x + 40; + } else if (cond1 == true && cond2 == true) { + return p.x + 50; + } else { + return -1; + } + } + + @Benchmark + public void testCondLoadAfterMerge_runner(Blackhole bh) { + int result = 0; + for (int i = 0 ; i < SIZE; i++) { + result += testCondLoadAfterMerge(cond1[i], cond2[i], xs[i], ys[i]); + } + bh.consume(result); + } + + // ------------------------------------------------------------------------- + + @CompilerControl(CompilerControl.Mode.DONT_INLINE) + public int testIfElseInLoop(int x, int y, int w, int z) { + int res = 0; + + for (int i=x; i