diff --git a/.gitignore b/.gitignore index b6b4a1a559a..a45e2113756 100644 --- a/.gitignore +++ b/.gitignore @@ -24,8 +24,6 @@ NashornProfile.txt /.gdbinit /.lldbinit **/core.[0-9]* -*.rej -*.orig test/benchmarks/**/target /src/hotspot/CMakeLists.txt /src/hotspot/compile_commands.json diff --git a/make/autoconf/buildjdk-spec.gmk.template b/make/autoconf/buildjdk-spec.gmk.template index bb020842d59..40758436517 100644 --- a/make/autoconf/buildjdk-spec.gmk.template +++ b/make/autoconf/buildjdk-spec.gmk.template @@ -108,3 +108,4 @@ override EXTRA_LDFLAGS := # hsdis is not needed HSDIS_BACKEND := none ENABLE_HSDIS_BUNDLING := false +DEFAULT_PRINT_ASSEMBLY_OPTIONS := diff --git a/make/autoconf/lib-hsdis.m4 b/make/autoconf/lib-hsdis.m4 index 0530ef90be8..928aa021f28 100644 --- a/make/autoconf/lib-hsdis.m4 +++ b/make/autoconf/lib-hsdis.m4 @@ -417,4 +417,9 @@ AC_DEFUN_ONCE([LIB_SETUP_HSDIS], AC_MSG_RESULT([no]) fi AC_SUBST(ENABLE_HSDIS_BUNDLING) + + UTIL_ARG_WITH(NAME: print-assembly-options, TYPE: string, + DEFAULT: [], RESULT: DEFAULT_PRINT_ASSEMBLY_OPTIONS, + DESC: [default value for the PrintAssemblyOptions diagnostic flag, passed verbatim to the disassembler]) + AC_SUBST(DEFAULT_PRINT_ASSEMBLY_OPTIONS) ]) diff --git a/make/autoconf/spec.gmk.template b/make/autoconf/spec.gmk.template index c4e5a23d31a..2a3f2793a32 100644 --- a/make/autoconf/spec.gmk.template +++ b/make/autoconf/spec.gmk.template @@ -381,6 +381,7 @@ HSDIS_CFLAGS := @HSDIS_CFLAGS@ HSDIS_LDFLAGS := @HSDIS_LDFLAGS@ HSDIS_LIBS := @HSDIS_LIBS@ CAPSTONE_ARCH_AARCH64_NAME := @CAPSTONE_ARCH_AARCH64_NAME@ +DEFAULT_PRINT_ASSEMBLY_OPTIONS := @DEFAULT_PRINT_ASSEMBLY_OPTIONS@ # The boot jdk to use. This is overridden in bootcycle-spec.gmk. Make sure to keep # it in sync. diff --git a/make/hotspot/lib/CompileGtest.gmk b/make/hotspot/lib/CompileGtest.gmk index 4b21d481049..3a5fac34597 100644 --- a/make/hotspot/lib/CompileGtest.gmk +++ b/make/hotspot/lib/CompileGtest.gmk @@ -45,6 +45,15 @@ else GTEST_COPY_DEBUG_SYMBOLS := false endif +GTEST_LIBJVM_CFLAGS := $(JVM_CFLAGS) +# Decoder does not work with debuginfo of the gtest libjvm when sections are used, +# so we get wrong file names. That's why we filter out the section flags. +ifeq ($(ENABLE_LINKTIME_GC), true) + ifeq ($(TOOLCHAIN_TYPE), gcc) + GTEST_LIBJVM_CFLAGS := $(filter-out -ffunction-sections -fdata-sections, $(JVM_CFLAGS)) + endif +endif + ################################################################################ ## Build libgtest ################################################################################ @@ -99,7 +108,7 @@ $(eval $(call SetupJdkLibrary, BUILD_GTEST_LIBJVM, \ EXCLUDE_PATTERNS := $(JVM_EXCLUDE_PATTERNS), \ EXTRA_OBJECT_FILES := $(BUILD_LIBJVM_ALL_OBJS), \ DEFAULT_CFLAGS := false, \ - CFLAGS := $(JVM_CFLAGS) \ + CFLAGS := $(GTEST_LIBJVM_CFLAGS) \ -DHOTSPOT_GTEST \ -I$(GTEST_FRAMEWORK_SRC)/googletest/include \ -I$(GTEST_FRAMEWORK_SRC)/googlemock/include \ diff --git a/make/hotspot/lib/CompileJvm.gmk b/make/hotspot/lib/CompileJvm.gmk index f41693e05fb..e8db4888d3a 100644 --- a/make/hotspot/lib/CompileJvm.gmk +++ b/make/hotspot/lib/CompileJvm.gmk @@ -209,6 +209,8 @@ $(eval $(call SetupJdkLibrary, BUILD_LIBJVM, \ DISABLED_WARNINGS_gcc_jvmtiTagMap.cpp := stringop-overflow, \ DISABLED_WARNINGS_gcc_macroAssembler_ppc_sha.cpp := unused-const-variable, \ DISABLED_WARNINGS_gcc_postaloc.cpp := address, \ + DISABLED_WARNINGS_gcc_safepointMechanism.cpp := stringop-overflow, \ + DISABLED_WARNINGS_gcc_shenandoahGenerationalHeap.cpp := stringop-overflow, \ DISABLED_WARNINGS_gcc_shenandoahLock.cpp := stringop-overflow, \ DISABLED_WARNINGS_gcc_stubGenerator_s390.cpp := unused-const-variable, \ DISABLED_WARNINGS_gcc_synchronizer.cpp := stringop-overflow, \ diff --git a/make/hotspot/lib/JvmFlags.gmk b/make/hotspot/lib/JvmFlags.gmk index 27a96cc4865..121f71bfa27 100644 --- a/make/hotspot/lib/JvmFlags.gmk +++ b/make/hotspot/lib/JvmFlags.gmk @@ -102,6 +102,10 @@ ifneq ($(HOTSPOT_OVERRIDE_LIBPATH), ) JVM_CFLAGS += -DOVERRIDE_LIBPATH='"$(HOTSPOT_OVERRIDE_LIBPATH)"' endif +ifneq ($(DEFAULT_PRINT_ASSEMBLY_OPTIONS), ) + JVM_CFLAGS += -DDEFAULT_PRINT_ASSEMBLY_OPTIONS='"$(DEFAULT_PRINT_ASSEMBLY_OPTIONS)"' +endif + ifeq ($(ENABLE_COMPATIBLE_CDS_ALIGNMENT), true) JVM_CFLAGS += -DCOMPATIBLE_CDS_ALIGNMENT endif diff --git a/make/jdk/src/classes/build/tools/cldrconverter/BundleGenerator.java b/make/jdk/src/classes/build/tools/cldrconverter/BundleGenerator.java index 20e259a0ba7..be5e49f8f7d 100644 --- a/make/jdk/src/classes/build/tools/cldrconverter/BundleGenerator.java +++ b/make/jdk/src/classes/build/tools/cldrconverter/BundleGenerator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -50,7 +50,7 @@ public interface BundleGenerator { }; public void generateBundle(String packageName, String baseName, String localeID, - boolean useJava, Map map, BundleType type) throws IOException; + Map map, BundleType type) throws IOException; public void generateMetaInfo(Map> metaInfo) throws IOException; } diff --git a/make/jdk/src/classes/build/tools/cldrconverter/CLDRConverter.java b/make/jdk/src/classes/build/tools/cldrconverter/CLDRConverter.java index 9f42326ef09..18ce0c334fb 100644 --- a/make/jdk/src/classes/build/tools/cldrconverter/CLDRConverter.java +++ b/make/jdk/src/classes/build/tools/cldrconverter/CLDRConverter.java @@ -183,7 +183,6 @@ public class CLDRConverter { } } - static boolean USE_UTF8 = false; private static boolean verbose; private CLDRConverter() { @@ -232,10 +231,6 @@ public class CLDRConverter { DESTINATION_DIR = args[++i]; break; - case "-utf8": - USE_UTF8 = true; - break; - case "-verbose": verbose = true; break; @@ -336,7 +331,6 @@ public class CLDRConverter { + "\t-year year copyright year in output%n" + "\t-zntempfile template file for java.time.format.ZoneName.java%n" + "\t-tzdatadir tzdata directory for java.time.format.ZoneName.java%n" - + "\t-utf8 use UTF-8 rather than \\uxxxx (for debug)%n" + "\t-jdk-header-template %n" + "\t\t override default GPL header with contents of file%n"); } @@ -612,31 +606,31 @@ public class CLDRConverter { if (bundleTypes.contains(Bundle.Type.LOCALENAMES)) { Map localeNamesMap = extractLocaleNames(targetMap, id); if (!localeNamesMap.isEmpty() || bundle.isRoot()) { - bundleGenerator.generateBundle("util", "LocaleNames", id, true, localeNamesMap, BundleType.OPEN); + bundleGenerator.generateBundle("util", "LocaleNames", id, localeNamesMap, BundleType.OPEN); } } if (bundleTypes.contains(Bundle.Type.CURRENCYNAMES)) { Map currencyNamesMap = extractCurrencyNames(targetMap, id, bundle.getCurrencies()); if (!currencyNamesMap.isEmpty() || bundle.isRoot()) { - bundleGenerator.generateBundle("util", "CurrencyNames", id, true, currencyNamesMap, BundleType.OPEN); + bundleGenerator.generateBundle("util", "CurrencyNames", id, currencyNamesMap, BundleType.OPEN); } } if (bundleTypes.contains(Bundle.Type.TIMEZONENAMES)) { Map zoneNamesMap = extractZoneNames(targetMap, id); if (!zoneNamesMap.isEmpty() || bundle.isRoot()) { - bundleGenerator.generateBundle("util", "TimeZoneNames", id, true, zoneNamesMap, BundleType.TIMEZONE); + bundleGenerator.generateBundle("util", "TimeZoneNames", id, zoneNamesMap, BundleType.TIMEZONE); } } if (bundleTypes.contains(Bundle.Type.CALENDARDATA)) { Map calendarDataMap = extractCalendarData(targetMap, id); if (!calendarDataMap.isEmpty() || bundle.isRoot()) { - bundleGenerator.generateBundle("util", "CalendarData", id, true, calendarDataMap, BundleType.PLAIN); + bundleGenerator.generateBundle("util", "CalendarData", id, calendarDataMap, BundleType.PLAIN); } } if (bundleTypes.contains(Bundle.Type.FORMATDATA)) { Map formatDataMap = extractFormatData(targetMap, id); if (!formatDataMap.isEmpty() || bundle.isRoot()) { - bundleGenerator.generateBundle("text", "FormatData", id, true, formatDataMap, BundleType.PLAIN); + bundleGenerator.generateBundle("text", "FormatData", id, formatDataMap, BundleType.PLAIN); } } @@ -1053,28 +1047,15 @@ public class CLDRConverter { } } - // --- code below here is adapted from java.util.Properties --- - private static final String specialSaveCharsJava = "\""; - private static final String specialSaveCharsProperties = "=: \t\r\n\f#!"; - /* - * Converts unicodes to encoded \uxxxx - * and writes out any of the characters in specialSaveChars - * with a preceding slash + * Escapes control codes to ASCII escapes or encoded \uxxxx + * and writes out ASCII quotation marks with a preceding slash */ - static String saveConvert(String theString, boolean useJava) { + static String escape(String theString) { if (theString == null) { return ""; } - String specialSaveChars; - if (useJava) { - specialSaveChars = specialSaveCharsJava; - } else { - specialSaveChars = specialSaveCharsProperties; - } - boolean escapeSpace = false; - int len = theString.length(); StringBuilder outBuffer = new StringBuilder(len * 2); Formatter formatter = new Formatter(outBuffer, Locale.ROOT); @@ -1083,14 +1064,14 @@ public class CLDRConverter { char aChar = theString.charAt(x); switch (aChar) { case ' ': - if (x == 0 || escapeSpace) { + if (x == 0) { outBuffer.append('\\'); } outBuffer.append(' '); break; - case '\\': - outBuffer.append('\\'); + case '\\', '"': outBuffer.append('\\'); + outBuffer.append(aChar); break; case '\t': outBuffer.append('\\'); @@ -1109,12 +1090,9 @@ public class CLDRConverter { outBuffer.append('f'); break; default: - if (aChar < 0x0020 || (!USE_UTF8 && aChar > 0x007e)) { + if (aChar < 0x0020) { formatter.format("\\u%04x", (int)aChar); } else { - if (specialSaveChars.indexOf(aChar) != -1) { - outBuffer.append('\\'); - } outBuffer.append(aChar); } } diff --git a/make/jdk/src/classes/build/tools/cldrconverter/ResourceBundleGenerator.java b/make/jdk/src/classes/build/tools/cldrconverter/ResourceBundleGenerator.java index 8278bf6bcfa..0bc5a2bdb0d 100644 --- a/make/jdk/src/classes/build/tools/cldrconverter/ResourceBundleGenerator.java +++ b/make/jdk/src/classes/build/tools/cldrconverter/ResourceBundleGenerator.java @@ -70,9 +70,8 @@ class ResourceBundleGenerator implements BundleGenerator { private static final String META_VALUE_PREFIX = "metaValue_"; @Override - public void generateBundle(String packageName, String baseName, String localeID, boolean useJava, + public void generateBundle(String packageName, String baseName, String localeID, Map map, BundleType type) throws IOException { - String suffix = useJava ? ".java" : ".properties"; String dirName = CLDRConverter.DESTINATION_DIR + File.separator + "sun" + File.separator + packageName + File.separator + "resources" + File.separator + "cldr"; packageName = packageName + ".resources.cldr"; @@ -91,23 +90,12 @@ class ResourceBundleGenerator implements BundleGenerator { if (!dir.exists()) { dir.mkdirs(); } - File file = new File(dir, baseName + ("root".equals(localeID) ? "" : "_" + localeID) + suffix); + File file = new File(dir, baseName + ("root".equals(localeID) ? "" : "_" + localeID) + ".java"); if (!file.exists()) { file.createNewFile(); } CLDRConverter.info("\tWriting file " + file); - String encoding; - if (useJava) { - if (CLDRConverter.USE_UTF8) { - encoding = "utf-8"; - } else { - encoding = "us-ascii"; - } - } else { - encoding = "iso-8859-1"; - } - Formatter fmt = null; if (type == BundleType.TIMEZONE) { fmt = new Formatter(); @@ -119,7 +107,7 @@ class ResourceBundleGenerator implements BundleGenerator { value = (String[]) map.get(key); fmt.format(" final String[] %s = new String[] {\n", meta); for (String s : value) { - fmt.format(" \"%s\",\n", CLDRConverter.saveConvert(s, useJava)); + fmt.format(" \"%s\",\n", CLDRConverter.escape(s)); } fmt.format(" };\n"); metaKeys.add(key); @@ -159,11 +147,11 @@ class ResourceBundleGenerator implements BundleGenerator { if (val instanceof String[] values) { fmt.format(" final String[] %s = new String[] {\n", metaVal); for (String s : values) { - fmt.format(" \"%s\",\n", CLDRConverter.saveConvert(s, useJava)); + fmt.format(" \"%s\",\n", CLDRConverter.escape(s)); } fmt.format(" };\n"); } else { - fmt.format(" final String %s = \"%s\";\n", metaVal, CLDRConverter.saveConvert((String)val, useJava)); + fmt.format(" final String %s = \"%s\";\n", metaVal, CLDRConverter.escape((String)val)); } newMap.put(oldEntry.key, oldEntry.metaKey()); } @@ -173,55 +161,47 @@ class ResourceBundleGenerator implements BundleGenerator { map = newMap; } - try (PrintWriter out = new PrintWriter(file, encoding)) { + try (PrintWriter out = new PrintWriter(file, "utf-8")) { // Output copyright headers out.println(getOpenJDKCopyright()); out.println(CopyrightHeaders.getUnicodeCopyright()); - if (useJava) { - out.println("package sun." + packageName + ";\n"); - out.printf("import %s;\n\n", type.getPathName()); - out.printf("public class %s%s extends %s {\n", baseName, "root".equals(localeID) ? "" : "_" + localeID, type.getClassName()); + out.println("package sun." + packageName + ";\n"); + out.printf("import %s;\n\n", type.getPathName()); + out.printf("public class %s%s extends %s {\n", baseName, "root".equals(localeID) ? "" : "_" + localeID, type.getClassName()); - out.println(" @Override\n" + - " protected final Object[][] getContents() {"); - if (fmt != null) { - out.print(fmt.toString()); - } - out.println(" final Object[][] data = new Object[][] {"); + out.println(" @Override\n" + + " protected final Object[][] getContents() {"); + if (fmt != null) { + out.print(fmt.toString()); } + out.println(" final Object[][] data = new Object[][] {"); for (String key : map.keySet()) { - if (useJava) { - Object value = map.get(key); - if (value == null) { - CLDRConverter.warning("null value for " + key); - } else if (value instanceof String) { - String valStr = (String)value; - if (type == BundleType.TIMEZONE && - !(key.startsWith(CLDRConverter.EXEMPLAR_CITY_PREFIX) || - key.startsWith(CLDRConverter.METAZONE_DSTOFFSET_PREFIX)) || - valStr.startsWith(META_VALUE_PREFIX)) { - out.printf(" { \"%s\", %s },\n", key, CLDRConverter.saveConvert(valStr, useJava)); - } else { - out.printf(" { \"%s\", \"%s\" },\n", key, CLDRConverter.saveConvert(valStr, useJava)); - } - } else if (value instanceof String[]) { - String[] values = (String[]) value; - out.println(" { \"" + key + "\",\n new String[] {"); - for (String s : values) { - out.println(" \"" + CLDRConverter.saveConvert(s, useJava) + "\","); - } - out.println(" }\n },"); + Object value = map.get(key); + if (value == null) { + CLDRConverter.warning("null value for " + key); + } else if (value instanceof String) { + String valStr = (String)value; + if (type == BundleType.TIMEZONE && + !(key.startsWith(CLDRConverter.EXEMPLAR_CITY_PREFIX) || + key.startsWith(CLDRConverter.METAZONE_DSTOFFSET_PREFIX)) || + valStr.startsWith(META_VALUE_PREFIX)) { + out.printf(" { \"%s\", %s },\n", key, CLDRConverter.escape(valStr)); } else { - throw new RuntimeException("unknown value type: " + value.getClass().getName()); + out.printf(" { \"%s\", \"%s\" },\n", key, CLDRConverter.escape(valStr)); } + } else if (value instanceof String[]) { + String[] values = (String[]) value; + out.println(" { \"" + key + "\",\n new String[] {"); + for (String s : values) { + out.println(" \"" + CLDRConverter.escape(s) + "\","); + } + out.println(" }\n },"); } else { - out.println(key + "=" + CLDRConverter.saveConvert((String) map.get(key), useJava)); + throw new RuntimeException("unknown value type: " + value.getClass().getName()); } } - if (useJava) { - out.println(" };\n return data;\n }\n}"); - } + out.println(" };\n return data;\n }\n}"); } } diff --git a/make/modules/java.base/Gensrc.gmk b/make/modules/java.base/Gensrc.gmk index e8236f0b0e4..675038c8fd5 100644 --- a/make/modules/java.base/Gensrc.gmk +++ b/make/modules/java.base/Gensrc.gmk @@ -1,5 +1,5 @@ # -# Copyright (c) 2011, 2025, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2011, 2026, Oracle and/or its affiliates. All rights reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it @@ -47,8 +47,6 @@ CLDR_GEN_DONE := $(GENSRC_DIR)/_cldr-gensrc.marker TZ_DATA_DIR := $(MODULE_SRC)/share/data/tzdata ZONENAME_TEMPLATE := $(MODULE_SRC)/share/classes/java/time/format/ZoneName.java.template -# The `-utf8` option is used even for US English, as some names -# may contain non-ASCII characters, such as “Türkiye”. $(CLDR_GEN_DONE): $(wildcard $(CLDR_DATA_DIR)/dtd/*.dtd) \ $(wildcard $(CLDR_DATA_DIR)/main/en*.xml) \ $(wildcard $(CLDR_DATA_DIR)/supplemental/*.xml) \ @@ -64,8 +62,7 @@ $(CLDR_GEN_DONE): $(wildcard $(CLDR_DATA_DIR)/dtd/*.dtd) \ -basemodule \ -year $(COPYRIGHT_YEAR) \ -zntempfile $(ZONENAME_TEMPLATE) \ - -tzdatadir $(TZ_DATA_DIR) \ - -utf8) + -tzdatadir $(TZ_DATA_DIR)) $(TOUCH) $@ TARGETS += $(CLDR_GEN_DONE) diff --git a/make/modules/java.desktop/lib/ClientLibraries.gmk b/make/modules/java.desktop/lib/ClientLibraries.gmk index 3e37fe79643..2326505d11c 100644 --- a/make/modules/java.desktop/lib/ClientLibraries.gmk +++ b/make/modules/java.desktop/lib/ClientLibraries.gmk @@ -395,6 +395,8 @@ $(eval $(call SetupJdkLibrary, BUILD_LIBFONTMANAGER, \ AccelGlyphCache.c, \ CFLAGS := $(LIBFONTMANAGER_CFLAGS), \ CXXFLAGS := $(LIBFONTMANAGER_CFLAGS), \ + CXXFLAGS_gcc := -fno-rtti -fno-exceptions, \ + CXXFLAGS_clang := -fno-rtti -fno-exceptions, \ OPTIMIZATION := HIGHEST, \ CFLAGS_windows = -DCC_NOEX, \ EXTRA_HEADER_DIRS := $(LIBFONTMANAGER_EXTRA_HEADER_DIRS), \ diff --git a/make/modules/jdk.localedata/Gensrc.gmk b/make/modules/jdk.localedata/Gensrc.gmk index 93b863df66f..2ff972c7536 100644 --- a/make/modules/jdk.localedata/Gensrc.gmk +++ b/make/modules/jdk.localedata/Gensrc.gmk @@ -1,5 +1,5 @@ # -# Copyright (c) 2014, 2025, Oracle and/or its affiliates. All rights reserved. +# Copyright (c) 2014, 2026, Oracle and/or its affiliates. All rights reserved. # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. # # This code is free software; you can redistribute it and/or modify it @@ -45,8 +45,7 @@ $(CLDR_GEN_DONE): $(wildcard $(CLDR_DATA_DIR)/dtd/*.dtd) \ -baselocales "en-US" \ -year $(COPYRIGHT_YEAR) \ -o $(GENSRC_DIR) \ - -tzdatadir $(TZ_DATA_DIR) \ - -utf8) + -tzdatadir $(TZ_DATA_DIR)) $(TOUCH) $@ TARGETS += $(CLDR_GEN_DONE) diff --git a/src/hotspot/cpu/aarch64/aarch64.ad b/src/hotspot/cpu/aarch64/aarch64.ad index 53fa4e3066c..185d5b72013 100644 --- a/src/hotspot/cpu/aarch64/aarch64.ad +++ b/src/hotspot/cpu/aarch64/aarch64.ad @@ -7708,10 +7708,11 @@ instruct bytes_reverse_unsigned_short(iRegINoSp dst, iRegIorL2I src) %{ match(Set dst (ReverseBytesUS src)); ins_cost(INSN_COST); - format %{ "rev16w $dst, $src" %} + format %{ "rev16w $dst, $src\t# $dst -> unsigned short" %} ins_encode %{ __ rev16w(as_Register($dst$$reg), as_Register($src$$reg)); + __ narrow_subword_type(as_Register($dst$$reg), T_CHAR); %} ins_pipe(ialu_reg); diff --git a/src/hotspot/cpu/aarch64/aarch64_vector_ad.m4 b/src/hotspot/cpu/aarch64/aarch64_vector_ad.m4 index 58ed234194a..ebf73813715 100644 --- a/src/hotspot/cpu/aarch64/aarch64_vector_ad.m4 +++ b/src/hotspot/cpu/aarch64/aarch64_vector_ad.m4 @@ -567,13 +567,9 @@ instruct vloadcon(vReg dst, immI0 src) %{ BasicType bt = Matcher::vector_element_basic_type(this); if (UseSVE == 0) { uint length_in_bytes = Matcher::vector_length_in_bytes(this); + int entry_idx = __ vector_iota_entry_index(bt); assert(length_in_bytes <= 16, "must be"); - // The iota indices are ordered by type B/S/I/L/F/D, and the offset between two types is 16. - int offset = exact_log2(type2aelembytes(bt)) << 4; - if (is_floating_point_type(bt)) { - offset += 32; - } - __ lea(rscratch1, ExternalAddress(StubRoutines::aarch64::vector_iota_indices() + offset)); + __ lea(rscratch1, ExternalAddress(StubRoutines::aarch64::vector_iota_indices(entry_idx))); if (length_in_bytes == 16) { __ ldrq($dst$$FloatRegister, rscratch1); } else { diff --git a/src/hotspot/cpu/aarch64/assembler_aarch64.hpp b/src/hotspot/cpu/aarch64/assembler_aarch64.hpp index 4c1c8d9bbc8..c8d5ee2eaeb 100644 --- a/src/hotspot/cpu/aarch64/assembler_aarch64.hpp +++ b/src/hotspot/cpu/aarch64/assembler_aarch64.hpp @@ -1,6 +1,7 @@ /* * Copyright (c) 1997, 2026, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2014, 2024, Red Hat Inc. All rights reserved. + * Copyright 2026 Arm Limited and/or its affiliates. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -1254,6 +1255,13 @@ public: sz, 0b000, ordered); } + void load_store_volatile(Register data, BasicType type, Register addr, + bool is_load) { + load_store_exclusive(dummy_reg, data, dummy_reg, addr, + (Assembler::operand_size)exact_log2(type2aelembytes(type)), + is_load ? 0b110 : 0b100, /* ordered = */ true); + } + #define INSN4(NAME, sz, op, o0) /* Four registers */ \ void NAME(Register Rs, Register Rt1, Register Rt2, Register Rn) { \ guarantee(Rs != Rn && Rs != Rt1 && Rs != Rt2, "unpredictable instruction"); \ diff --git a/src/hotspot/cpu/aarch64/c1_LIRAssembler_aarch64.cpp b/src/hotspot/cpu/aarch64/c1_LIRAssembler_aarch64.cpp index 4de6237304d..4eb4e3d5ac7 100644 --- a/src/hotspot/cpu/aarch64/c1_LIRAssembler_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/c1_LIRAssembler_aarch64.cpp @@ -1,6 +1,7 @@ /* * Copyright (c) 2000, 2026, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2014, 2020, Red Hat Inc. All rights reserved. + * Copyright 2026 Arm Limited and/or its affiliates. * 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,8 +912,15 @@ void LIR_Assembler::stack2stack(LIR_Opr src, LIR_Opr dest, BasicType type) { reg2stack(temp, dest, dest->type()); } +void LIR_Assembler::mem2reg(LIR_Opr src, LIR_Opr dest, BasicType type, + LIR_PatchCode patch_code, CodeEmitInfo* info, + bool wide) { + mem2reg(src, dest, type, patch_code, info, wide, false); +} -void LIR_Assembler::mem2reg(LIR_Opr src, LIR_Opr dest, BasicType type, LIR_PatchCode patch_code, CodeEmitInfo* info, bool wide) { +void LIR_Assembler::mem2reg(LIR_Opr src, LIR_Opr dest, BasicType type, + LIR_PatchCode patch_code, CodeEmitInfo* info, + bool wide, bool is_volatile) { LIR_Address* addr = src->as_address_ptr(); LIR_Address* from_addr = src->as_address_ptr(); @@ -925,10 +933,27 @@ void LIR_Assembler::mem2reg(LIR_Opr src, LIR_Opr dest, BasicType type, LIR_Patch return; } + if (is_volatile) { + load_volatile(from_addr, dest, type, info); + } else { + load_unordered(from_addr, dest, type, wide, info); + } + + if (is_reference_type(type)) { + if (UseCompressedOops && !wide) { + __ decode_heap_oop(dest->as_register()); + } + + __ verify_oop(dest->as_register()); + } +} + +void LIR_Assembler::load_unordered(LIR_Address *from_addr, LIR_Opr dest, + BasicType type, bool wide, CodeEmitInfo* info) { if (info != nullptr) { add_debug_info_for_null_check_here(info); } - int null_check_here = code_offset(); + switch (type) { case T_FLOAT: { __ ldrs(dest->as_float_reg(), as_Address(from_addr)); @@ -986,16 +1011,44 @@ void LIR_Assembler::mem2reg(LIR_Opr src, LIR_Opr dest, BasicType type, LIR_Patch default: ShouldNotReachHere(); } - - if (is_reference_type(type)) { - if (UseCompressedOops && !wide) { - __ decode_heap_oop(dest->as_register()); - } - - __ verify_oop(dest->as_register()); - } } +void LIR_Assembler::load_volatile(LIR_Address *from_addr, LIR_Opr dest, + BasicType type, CodeEmitInfo* info) { + __ lea(rscratch1, as_Address(from_addr)); + + Register dest_reg = rscratch2; + if (!is_floating_point_type(type)) { + dest_reg = (dest->is_single_cpu() + ? dest->as_register() : dest->as_register_lo()); + } + + if (info != nullptr) { + add_debug_info_for_null_check_here(info); + } + + // Uses LDAR to ensure memory ordering. + __ load_store_volatile(dest_reg, type, rscratch1, /*is_load*/true); + + switch (type) { + // LDAR is unsigned so need to sign-extend for byte and short + case T_BYTE: + __ sxtb(dest_reg, dest_reg); + break; + case T_SHORT: + __ sxth(dest_reg, dest_reg); + break; + // need to move from GPR to FPR after LDAR with FMOV for floating types + case T_FLOAT: + __ fmovs(dest->as_float_reg(), dest_reg); + break; + case T_DOUBLE: + __ fmovd(dest->as_double_reg(), dest_reg); + break; + default: + break; + } +} int LIR_Assembler::array_element_size(BasicType type) const { int elem_size = type2aelembytes(type); @@ -2764,7 +2817,9 @@ void LIR_Assembler::rt_call(LIR_Opr result, address dest, const LIR_OprList* arg } void LIR_Assembler::volatile_move_op(LIR_Opr src, LIR_Opr dest, BasicType type, CodeEmitInfo* info) { - if (dest->is_address() || src->is_address()) { + if (src->is_address()) { + mem2reg(src, dest, type, lir_patch_none, info, /*wide*/false, /*is_volatile*/true); + } else if (dest->is_address()) { move_op(src, dest, type, lir_patch_none, info, /*wide*/false); } else { ShouldNotReachHere(); diff --git a/src/hotspot/cpu/aarch64/c1_LIRAssembler_aarch64.hpp b/src/hotspot/cpu/aarch64/c1_LIRAssembler_aarch64.hpp index 5af06fc6a1c..367256d2f69 100644 --- a/src/hotspot/cpu/aarch64/c1_LIRAssembler_aarch64.hpp +++ b/src/hotspot/cpu/aarch64/c1_LIRAssembler_aarch64.hpp @@ -57,6 +57,12 @@ friend class ArrayCopyStub; void casw(Register addr, Register newval, Register cmpval); void casl(Register addr, Register newval, Register cmpval); + void mem2reg(LIR_Opr src, LIR_Opr dest, BasicType type, + LIR_PatchCode patch_code, + CodeEmitInfo* info, bool wide, bool is_volatile); + void load_unordered(LIR_Address *from_addr, LIR_Opr dest, BasicType type, bool wide, CodeEmitInfo* info); + void load_volatile(LIR_Address *from_addr, LIR_Opr dest, BasicType type, CodeEmitInfo* info); + static const int max_tableswitches = 20; struct tableswitch switches[max_tableswitches]; int tableswitch_count; diff --git a/src/hotspot/cpu/aarch64/c1_LIRGenerator_aarch64.cpp b/src/hotspot/cpu/aarch64/c1_LIRGenerator_aarch64.cpp index f10c5197d91..7e82f410a95 100644 --- a/src/hotspot/cpu/aarch64/c1_LIRGenerator_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/c1_LIRGenerator_aarch64.cpp @@ -1398,14 +1398,5 @@ void LIRGenerator::volatile_field_store(LIR_Opr value, LIR_Address* address, void LIRGenerator::volatile_field_load(LIR_Address* address, LIR_Opr result, CodeEmitInfo* info) { - // 8179954: We need to make sure that the code generated for - // volatile accesses forms a sequentially-consistent set of - // operations when combined with STLR and LDAR. Without a leading - // membar it's possible for a simple Dekker test to fail if loads - // use LD;DMB but stores use STLR. This can happen if C2 compiles - // the stores in one method and C1 compiles the loads in another. - if (!CompilerConfig::is_c1_only_no_jvmci()) { - __ membar(); - } __ volatile_load_mem_reg(address, result, info); } diff --git a/src/hotspot/cpu/aarch64/gc/shenandoah/c1/shenandoahBarrierSetC1_aarch64.cpp b/src/hotspot/cpu/aarch64/gc/shenandoah/c1/shenandoahBarrierSetC1_aarch64.cpp index e4db8a9ab1f..e31a58243b5 100644 --- a/src/hotspot/cpu/aarch64/gc/shenandoah/c1/shenandoahBarrierSetC1_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/gc/shenandoah/c1/shenandoahBarrierSetC1_aarch64.cpp @@ -50,14 +50,10 @@ void LIR_OpShenandoahCompareAndSwap::emit_code(LIR_Assembler* masm) { ShenandoahBarrierSet::assembler()->cmpxchg_oop(masm->masm(), addr, cmpval, newval, /*acquire*/ true, /*release*/ true, /*is_cae*/ false, result); - if (CompilerConfig::is_c1_only_no_jvmci()) { - // The membar here is necessary to prevent reordering between the - // release store in the CAS above and a subsequent volatile load. - // However for tiered compilation C1 inserts a full barrier before - // volatile loads which means we don't need an additional barrier - // here (see LIRGenerator::volatile_field_load()). - __ membar(__ AnyAny); - } + // The membar here is necessary to prevent reordering between the + // release store in the CAS above and a subsequent volatile load. + // See also: LIR_Assembler::casw, LIR_Assembler::casl. + __ membar(__ AnyAny); } #undef __ diff --git a/src/hotspot/cpu/aarch64/macroAssembler_aarch64.cpp b/src/hotspot/cpu/aarch64/macroAssembler_aarch64.cpp index 7bec0a3c0ca..40f7251600a 100644 --- a/src/hotspot/cpu/aarch64/macroAssembler_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/macroAssembler_aarch64.cpp @@ -2815,6 +2815,17 @@ void MacroAssembler::store_sized_value(Address dst, Register src, size_t size_in } } +void MacroAssembler::narrow_subword_type(Register reg, BasicType bt) { + assert(is_subword_type(bt), "required"); + switch (bt) { + case T_BOOLEAN: andw(reg, reg, 1); break; + case T_BYTE: sxtbw(reg, reg); break; + case T_CHAR: uxthw(reg, reg); break; + case T_SHORT: sxthw(reg, reg); break; + default: ShouldNotReachHere(); + } +} + void MacroAssembler::decrementw(Register reg, int value) { if (value < 0) { incrementw(reg, -value); return; } diff --git a/src/hotspot/cpu/aarch64/macroAssembler_aarch64.hpp b/src/hotspot/cpu/aarch64/macroAssembler_aarch64.hpp index a6cc862d05c..e5e36d43516 100644 --- a/src/hotspot/cpu/aarch64/macroAssembler_aarch64.hpp +++ b/src/hotspot/cpu/aarch64/macroAssembler_aarch64.hpp @@ -33,6 +33,7 @@ #include "oops/compressedOops.hpp" #include "oops/compressedKlass.hpp" #include "runtime/vm_version.hpp" +#include "utilities/globalDefinitions.hpp" #include "utilities/powerOfTwo.hpp" class OopMap; @@ -719,6 +720,9 @@ public: // Support for sign-extension (hi:lo = extend_sign(lo)) void extend_sign(Register hi, Register lo); + // Clean up a subword typed value to the representation in compliance with JVMS §2.3 + void narrow_subword_type(Register reg, BasicType bt); + // Load and store values by size and signed-ness void load_sized_value(Register dst, Address src, size_t size_in_bytes, bool is_signed); void store_sized_value(Address dst, Register src, size_t size_in_bytes); diff --git a/src/hotspot/cpu/aarch64/templateTable_aarch64.cpp b/src/hotspot/cpu/aarch64/templateTable_aarch64.cpp index 69769fb8441..4c64b265d92 100644 --- a/src/hotspot/cpu/aarch64/templateTable_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/templateTable_aarch64.cpp @@ -3479,7 +3479,6 @@ void TemplateTable::invokeinterface(int byte_no) { __ bind(notVFinal); // Get receiver klass into r3 - __ restore_locals(); __ load_klass(r3, r2); Label no_such_method; diff --git a/src/hotspot/cpu/aarch64/vm_version_aarch64.cpp b/src/hotspot/cpu/aarch64/vm_version_aarch64.cpp index 441bd4859fe..9606233f3b4 100644 --- a/src/hotspot/cpu/aarch64/vm_version_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/vm_version_aarch64.cpp @@ -305,9 +305,9 @@ void VM_Version::initialize() { FLAG_SET_DEFAULT(UseSHA, false); } - CHECK_CPU_FEATURE(supports_crc32, CRC32); - CHECK_CPU_FEATURE(supports_lse, LSE); - CHECK_CPU_FEATURE(supports_aes, AES); + CHECK_CPU_FEATURE(UseCRC32, CRC32, supports_crc32(), MULTI_INST_WARNING_MSG); + CHECK_CPU_FEATURE(UseLSE, LSE, supports_lse(), MULTI_INST_WARNING_MSG); + CHECK_CPU_FEATURE(UseAES, AES, supports_aes(), MULTI_INST_WARNING_MSG); if (_cpu == CPU_ARM && model_is_in({ CPU_MODEL_ARM_NEOVERSE_V1, CPU_MODEL_ARM_NEOVERSE_V2, @@ -789,9 +789,9 @@ void VM_Version::store_cpu_features(void* buf) { *(uint64_t*)buf = _features; } -bool VM_Version::supports_features(void* features_buffer) { +bool VM_Version::verify_aot_code_cache_features(void* features_buffer) { uint64_t features_to_test = *(uint64_t*)features_buffer; - return (_features & features_to_test) == features_to_test; + return (_features == features_to_test); } #if defined(LINUX) diff --git a/src/hotspot/cpu/aarch64/vm_version_aarch64.hpp b/src/hotspot/cpu/aarch64/vm_version_aarch64.hpp index 30f1a5d86ca..ee06704b9fe 100644 --- a/src/hotspot/cpu/aarch64/vm_version_aarch64.hpp +++ b/src/hotspot/cpu/aarch64/vm_version_aarch64.hpp @@ -279,7 +279,7 @@ public: // Size of the buffer must be same as returned by cpu_features_size() static void store_cpu_features(void* buf); - static bool supports_features(void* features_to_test); + static bool verify_aot_code_cache_features(void* features_buffer); }; #endif // CPU_AARCH64_VM_VERSION_AARCH64_HPP diff --git a/src/hotspot/cpu/arm/arm.ad b/src/hotspot/cpu/arm/arm.ad index 60a0ef307b5..45ae283e05a 100644 --- a/src/hotspot/cpu/arm/arm.ad +++ b/src/hotspot/cpu/arm/arm.ad @@ -9214,10 +9214,12 @@ instruct bytes_reverse_long(iRegL dst, iRegL src) %{ instruct bytes_reverse_unsigned_short(iRegI dst, iRegI src) %{ match(Set dst (ReverseBytesUS src)); - size(4); - format %{ "REV16 $dst,$src" %} + size(8); + format %{ "REV32 $dst,$src\n\t" + "LSR $dst,$dst,#16" %} ins_encode %{ - __ rev16($dst$$Register, $src$$Register); + __ rev($dst$$Register, $src$$Register); + __ mov($dst$$Register, AsmOperand($dst$$Register, lsr, 16)); %} ins_pipe( iload_mem ); // FIXME %} diff --git a/src/hotspot/cpu/arm/c1_LIRGenerator_arm.cpp b/src/hotspot/cpu/arm/c1_LIRGenerator_arm.cpp index 4c339968f85..46ec87290ae 100644 --- a/src/hotspot/cpu/arm/c1_LIRGenerator_arm.cpp +++ b/src/hotspot/cpu/arm/c1_LIRGenerator_arm.cpp @@ -1332,7 +1332,8 @@ void LIRGenerator::volatile_field_load(LIR_Address* address, LIR_Opr result, load_addr = address; } __ volatile_load_mem_reg(load_addr, result, info); - return; + } else { + __ load(address, result, info, lir_patch_none); } - __ load(address, result, info, lir_patch_none); + __ membar_acquire(); } diff --git a/src/hotspot/cpu/ppc/c1_LIRGenerator_ppc.cpp b/src/hotspot/cpu/ppc/c1_LIRGenerator_ppc.cpp index 5f030676bcb..a652a155f62 100644 --- a/src/hotspot/cpu/ppc/c1_LIRGenerator_ppc.cpp +++ b/src/hotspot/cpu/ppc/c1_LIRGenerator_ppc.cpp @@ -1143,6 +1143,7 @@ void LIRGenerator::volatile_field_load(LIR_Address* address, LIR_Opr result, Unimplemented(); // __ volatile_load_mem_reg(address, result, info); #endif + __ membar_acquire(); } diff --git a/src/hotspot/cpu/ppc/continuationFreezeThaw_ppc.inline.hpp b/src/hotspot/cpu/ppc/continuationFreezeThaw_ppc.inline.hpp index f7704ea5b14..82167949065 100644 --- a/src/hotspot/cpu/ppc/continuationFreezeThaw_ppc.inline.hpp +++ b/src/hotspot/cpu/ppc/continuationFreezeThaw_ppc.inline.hpp @@ -540,6 +540,8 @@ template frame ThawBase::new_stack_frame(const frame& hf, frame& intptr_t* frame_sp = caller.sp() - fsize; if ((bottom && argsize > 0) || caller.is_interpreted_frame()) { + assert(!_should_patch_caller_pc, ""); + _should_patch_caller_pc = caller.is_interpreted_frame(); frame_sp -= argsize + frame::metadata_words_at_top; frame_sp = align_down(frame_sp, frame::alignment_in_bytes); caller.set_sp(frame_sp + fsize); diff --git a/src/hotspot/cpu/ppc/gc/shared/barrierSetAssembler_ppc.cpp b/src/hotspot/cpu/ppc/gc/shared/barrierSetAssembler_ppc.cpp index 3692b247989..db20439b066 100644 --- a/src/hotspot/cpu/ppc/gc/shared/barrierSetAssembler_ppc.cpp +++ b/src/hotspot/cpu/ppc/gc/shared/barrierSetAssembler_ppc.cpp @@ -354,19 +354,9 @@ int SaveLiveRegisters::iterate_over_register_mask(IterationAction action, int of Register spill_addr = R0; int spill_offset = offset - reg_save_index * BytesPerWord; if (action == ACTION_SAVE) { - if (PowerArchitecturePPC64 >= 9) { - _masm->stxv(vs_reg, spill_offset, R1_SP); - } else { - _masm->addi(spill_addr, R1_SP, spill_offset); - _masm->stxvd2x(vs_reg, spill_addr); - } + _masm->stxv(vs_reg, spill_offset, R1_SP); } else if (action == ACTION_RESTORE) { - if (PowerArchitecturePPC64 >= 9) { - _masm->lxv(vs_reg, spill_offset, R1_SP); - } else { - _masm->addi(spill_addr, R1_SP, spill_offset); - _masm->lxvd2x(vs_reg, spill_addr); - } + _masm->lxv(vs_reg, spill_offset, R1_SP); } else { assert(action == ACTION_COUNT_ONLY, "Sanity"); } diff --git a/src/hotspot/cpu/ppc/globals_ppc.hpp b/src/hotspot/cpu/ppc/globals_ppc.hpp index 927a8cc2be3..d46bb733ea7 100644 --- a/src/hotspot/cpu/ppc/globals_ppc.hpp +++ b/src/hotspot/cpu/ppc/globals_ppc.hpp @@ -116,7 +116,8 @@ define_pd_global(intx, InitArrayShortSize, 9*BytesPerLong); \ /* special instructions */ \ product(bool, SuperwordUseVSX, false, \ - "Use VSX instructions for superword optimization.") \ + "Use VSX instructions for superword optimization " \ + "(default for Power9 and later).") \ \ product(bool, UseByteReverseInstructions, false, DIAGNOSTIC, \ "Use byte reverse instructions.") \ diff --git a/src/hotspot/cpu/ppc/macroAssembler_ppc.cpp b/src/hotspot/cpu/ppc/macroAssembler_ppc.cpp index 5fbcce94029..3efedc31d8f 100644 --- a/src/hotspot/cpu/ppc/macroAssembler_ppc.cpp +++ b/src/hotspot/cpu/ppc/macroAssembler_ppc.cpp @@ -799,13 +799,7 @@ void MacroAssembler::save_nonvolatile_registers(Register dst, int offset, bool i } } else { for (int i = 20; i < 32; i++) { - if (PowerArchitecturePPC64 >= 9) { - stxv(as_VectorRegister(i)->to_vsr(), offset, dst); - } else { - Register spill_addr = R0; - addi(spill_addr, dst, offset); - stxvd2x(as_VectorRegister(i)->to_vsr(), spill_addr); - } + stxv(as_VectorRegister(i)->to_vsr(), offset, dst); offset += 16; } } @@ -838,13 +832,7 @@ void MacroAssembler::restore_nonvolatile_registers(Register src, int offset, boo } } else { for (int i = 20; i < 32; i++) { - if (PowerArchitecturePPC64 >= 9) { - lxv(as_VectorRegister(i)->to_vsr(), offset, src); - } else { - Register spill_addr = R0; - addi(spill_addr, src, offset); - lxvd2x(as_VectorRegister(i)->to_vsr(), spill_addr); - } + lxv(as_VectorRegister(i)->to_vsr(), offset, src); offset += 16; } } @@ -3214,7 +3202,7 @@ void MacroAssembler::store_klass_gap(Register dst_oop, Register val) { stw(val, oopDesc::klass_gap_offset_in_bytes(), dst_oop); } -int MacroAssembler::instr_size_for_decode_klass_not_null() { +int MacroAssembler::instr_size_for_load_klass() { static int computed_size = -1; // Not yet computed? @@ -3222,10 +3210,10 @@ int MacroAssembler::instr_size_for_decode_klass_not_null() { // Determine by scratch emit. ResourceMark rm; - int code_size = 8 * BytesPerInstWord; - CodeBuffer cb("decode_klass_not_null scratch buffer", code_size, 0); + int code_size = 16 * BytesPerInstWord; + CodeBuffer cb("load_klass scratch buffer", code_size, 0); MacroAssembler* a = new MacroAssembler(&cb); - a->decode_klass_not_null(R11_scratch1); + a->load_klass(R11_scratch1, R11_scratch1); computed_size = a->offset(); } diff --git a/src/hotspot/cpu/ppc/macroAssembler_ppc.hpp b/src/hotspot/cpu/ppc/macroAssembler_ppc.hpp index 4be62098bdf..b2f5e8f0b60 100644 --- a/src/hotspot/cpu/ppc/macroAssembler_ppc.hpp +++ b/src/hotspot/cpu/ppc/macroAssembler_ppc.hpp @@ -802,7 +802,7 @@ class MacroAssembler: public Assembler { MacroAssembler::PreservationLevel preservation_level); void load_method_holder(Register holder, Register method); - static int instr_size_for_decode_klass_not_null(); + static int instr_size_for_load_klass(); void decode_klass_not_null(Register dst, Register src = noreg); Register encode_klass_not_null(Register dst, Register src = noreg); diff --git a/src/hotspot/cpu/ppc/matcher_ppc.hpp b/src/hotspot/cpu/ppc/matcher_ppc.hpp index cbe882648b8..88a189d670e 100644 --- a/src/hotspot/cpu/ppc/matcher_ppc.hpp +++ b/src/hotspot/cpu/ppc/matcher_ppc.hpp @@ -38,10 +38,10 @@ return false; } - // The PPC implementation uses VSX lxvd2x/stxvd2x instructions (if + // The PPC implementation uses VSX lxv/stxv instructions (if // SuperwordUseVSX). They do not have alignment requirements. // Some VSX storage access instructions cannot encode arbitrary displacements - // (e.g. lxv). None of them is currently used. + // (e.g. lxv). We use memoryAlg16 for them. static constexpr bool misaligned_vectors_ok() { return true; } diff --git a/src/hotspot/cpu/ppc/ppc.ad b/src/hotspot/cpu/ppc/ppc.ad index f3d33b4305d..00549ac8508 100644 --- a/src/hotspot/cpu/ppc/ppc.ad +++ b/src/hotspot/cpu/ppc/ppc.ad @@ -1187,7 +1187,7 @@ int MachCallDynamicJavaNode::ret_addr_offset() { assert(vtable_index == Method::invalid_vtable_index, "correct sentinel value"); return 12; } else { - return 24 + MacroAssembler::instr_size_for_decode_klass_not_null(); + return 20 + MacroAssembler::instr_size_for_load_klass(); } } @@ -1818,52 +1818,26 @@ uint MachSpillCopyNode::implementation(C2_MacroAssembler *masm, PhaseRegAlloc *r // VectorRegister->Memory Spill. else if (src_lo_rc == rc_vec && dst_lo_rc == rc_stack) { VectorSRegister Rsrc = as_VectorRegister(Matcher::_regEncode[src_lo]).to_vsr(); - if (PowerArchitecturePPC64 >= 9) { - if (masm) { - __ stxv(Rsrc, dst_offset, R1_SP); // matches storeV16_Power9 - } - size += 4; - } else { - if (masm) { - __ addi(R0, R1_SP, dst_offset); - __ stxvd2x(Rsrc, R0); // matches storeV16_Power8 - } - size += 8; + if (masm) { + __ stxv(Rsrc, dst_offset, R1_SP); // matches storeV16 } + size += 4; #ifndef PRODUCT if (st != nullptr) { - if (PowerArchitecturePPC64 >= 9) { - st->print("%-7s %s, [R1_SP + #%d] \t// vector spill copy", "STXV", Matcher::regName[src_lo], dst_offset); - } else { - st->print("%-7s R0, R1_SP, %d \t// vector spill copy\n\t" - "%-7s %s, [R0] \t// vector spill copy", "ADDI", dst_offset, "STXVD2X", Matcher::regName[src_lo]); - } + st->print("%-7s %s, [R1_SP + #%d] \t// vector spill copy", "STXV", Matcher::regName[src_lo], dst_offset); } #endif // !PRODUCT } // Memory->VectorRegister Spill. else if (src_lo_rc == rc_stack && dst_lo_rc == rc_vec) { VectorSRegister Rdst = as_VectorRegister(Matcher::_regEncode[dst_lo]).to_vsr(); - if (PowerArchitecturePPC64 >= 9) { - if (masm) { - __ lxv(Rdst, src_offset, R1_SP); - } - size += 4; - } else { - if (masm) { - __ addi(R0, R1_SP, src_offset); - __ lxvd2x(Rdst, R0); - } - size += 8; + if (masm) { + __ lxv(Rdst, src_offset, R1_SP); } + size += 4; #ifndef PRODUCT if (st != nullptr) { - if (PowerArchitecturePPC64 >= 9) { - st->print("%-7s %s, [R1_SP + #%d] \t// vector spill copy", "LXV", Matcher::regName[dst_lo], src_offset); - } else { - st->print("%-7s R0, R1_SP, %d \t// vector spill copy\n\t" - "%-7s %s, [R0] \t// vector spill copy", "ADDI", src_offset, "LXVD2X", Matcher::regName[dst_lo]); - } + st->print("%-7s %s, [R1_SP + #%d] \t// vector spill copy", "LXV", Matcher::regName[dst_lo], src_offset); } #endif // !PRODUCT } @@ -2284,7 +2258,7 @@ bool Matcher::match_rule_supported_vector(int opcode, int vlen, BasicType bt) { case Op_UMaxV: return bt == T_INT || bt == T_LONG; case Op_NegVI: - return PowerArchitecturePPC64 >= 9 && bt == T_INT; + return bt == T_INT; } return true; // Per default match rules are supported. } @@ -2322,10 +2296,12 @@ OptoRegPair Matcher::vector_return_value(uint ideal_reg) { // Vector width in bytes. int Matcher::vector_width_in_bytes(BasicType bt) { if (SuperwordUseVSX) { - assert(MaxVectorSize == 16, ""); + assert(MaxVectorSize == 16, + "SuperwordUseVSX requires MaxVectorSize 16, got " INT64_FORMAT, (int64_t)MaxVectorSize); return 16; } else { - assert(MaxVectorSize == 8, ""); + assert(MaxVectorSize == 8, + "expected MaxVectorSize 8, got " INT64_FORMAT, (int64_t)MaxVectorSize); return 8; } } @@ -2333,10 +2309,14 @@ int Matcher::vector_width_in_bytes(BasicType bt) { // Vector ideal reg. uint Matcher::vector_ideal_reg(int size) { if (SuperwordUseVSX) { - assert(MaxVectorSize == 16 && size == 16, ""); + assert(MaxVectorSize == 16 && size == 16, + "SuperwordUseVSX requires MaxVectorSize 16 and size 16, got MaxVectorSize=" INT64_FORMAT ", size=%d", + (int64_t)MaxVectorSize, size); return Op_VecX; } else { - assert(MaxVectorSize == 8 && size == 8, ""); + assert(MaxVectorSize == 8 && size == 8, + "expected MaxVectorSize 8 and size 8, got MaxVectorSize=" INT64_FORMAT ", size=%d", + (int64_t)MaxVectorSize, size); return Op_RegL; } } @@ -5413,23 +5393,9 @@ instruct loadV8(iRegLdst dst, memoryAlg4 mem) %{ ins_pipe(pipe_class_memory); %} -// Load Aligned Packed Byte -// Note: The Power8 instruction loads the contents in a special order in Little Endian mode. -instruct loadV16_Power8(vecX dst, indirect mem) %{ - predicate(n->as_LoadVector()->memory_size() == 16 && PowerArchitecturePPC64 == 8); - match(Set dst (LoadVector mem)); - ins_cost(MEMORY_REF_COST); - format %{ "LXVD2X $dst, $mem \t// load 16-byte Vector" %} - size(4); - ins_encode %{ - __ lxvd2x($dst$$VectorRegister.to_vsr(), $mem$$Register); - %} - ins_pipe(pipe_class_default); -%} - -instruct loadV16_Power9(vecX dst, memoryAlg16 mem) %{ - predicate(n->as_LoadVector()->memory_size() == 16 && PowerArchitecturePPC64 >= 9); +instruct loadV16(vecX dst, memoryAlg16 mem) %{ + predicate(n->as_LoadVector()->memory_size() == 16); match(Set dst (LoadVector mem)); ins_cost(MEMORY_REF_COST); @@ -6424,23 +6390,9 @@ instruct storeA8B(memoryAlg4 mem, iRegLsrc src) %{ ins_pipe(pipe_class_memory); %} -// Store Packed Byte long register to memory -// Note: The Power8 instruction stores the contents in a special order in Little Endian mode. -instruct storeV16_Power8(indirect mem, vecX src) %{ - predicate(n->as_StoreVector()->memory_size() == 16 && PowerArchitecturePPC64 == 8); - match(Set mem (StoreVector mem src)); - ins_cost(MEMORY_REF_COST); - format %{ "STXVD2X $mem, $src \t// store 16-byte Vector" %} - size(4); - ins_encode %{ - __ stxvd2x($src$$VectorRegister.to_vsr(), $mem$$Register); - %} - ins_pipe(pipe_class_default); -%} - -instruct storeV16_Power9(memoryAlg16 mem, vecX src) %{ - predicate(n->as_StoreVector()->memory_size() == 16 && PowerArchitecturePPC64 >= 9); +instruct storeV16(memoryAlg16 mem, vecX src) %{ + predicate(n->as_StoreVector()->memory_size() == 16); match(Set mem (StoreVector mem src)); ins_cost(MEMORY_REF_COST); @@ -12480,6 +12432,19 @@ instruct countTrailingZerosL_cnttzd(iRegIdst dst, iRegLsrc src) %{ ins_pipe(pipe_class_default); %} +// Expand nodes for byte_reverse_int/ushort/short. +instruct rlwinm(iRegIdst dst, iRegIsrc src, immI16 shift, immI16 mb, immI16 me) %{ + effect(DEF dst, USE src, USE shift, USE mb, USE me); + predicate(false); + + format %{ "RLWINM $dst, $src, $shift, $mb, $me" %} + size(4); + ins_encode %{ + __ rlwinm($dst$$Register, $src$$Register, $shift$$constant, $mb$$constant, $me$$constant); + %} + ins_pipe(pipe_class_default); +%} + // Expand nodes for byte_reverse_int. instruct insrwi_a(iRegIdst dst, iRegIsrc src, immI16 n, immI16 b) %{ effect(DEF dst, USE src, USE n, USE b); @@ -12636,34 +12601,22 @@ instruct bytes_reverse_long(iRegLdst dst, iRegLsrc src) %{ ins_pipe(pipe_class_default); %} +// Need zero extend. Must not use brh only. instruct bytes_reverse_ushort_Ex(iRegIdst dst, iRegIsrc src) %{ match(Set dst (ReverseBytesUS src)); - predicate(!UseByteReverseInstructions); ins_cost(2*DEFAULT_COST); expand %{ + immI16 imm31 %{ (int) 31 %} + immI16 imm24 %{ (int) 24 %} immI16 imm16 %{ (int) 16 %} immI16 imm8 %{ (int) 8 %} - urShiftI_reg_imm(dst, src, imm8); + rlwinm(dst, src, imm24, imm24, imm31); insrwi(dst, src, imm8, imm16); %} %} -instruct bytes_reverse_ushort(iRegIdst dst, iRegIsrc src) %{ - match(Set dst (ReverseBytesUS src)); - predicate(UseByteReverseInstructions); - ins_cost(DEFAULT_COST); - size(4); - - format %{ "BRH $dst, $src" %} - - ins_encode %{ - __ brh($dst$$Register, $src$$Register); - %} - ins_pipe(pipe_class_default); -%} - instruct bytes_reverse_short_Ex(iRegIdst dst, iRegIsrc src) %{ match(Set dst (ReverseBytesS src)); predicate(!UseByteReverseInstructions); @@ -13656,7 +13609,7 @@ instruct vneg2D_reg(vecX dst, vecX src) %{ instruct vneg4I_reg(vecX dst, vecX src) %{ match(Set dst (NegVI src)); - predicate(PowerArchitecturePPC64 >= 9 && Matcher::vector_element_basic_type(n) == T_INT); + predicate(Matcher::vector_element_basic_type(n) == T_INT); format %{ "VNEGW $dst,$src\t// negate int vector" %} size(4); ins_encode %{ diff --git a/src/hotspot/cpu/ppc/sharedRuntime_ppc.cpp b/src/hotspot/cpu/ppc/sharedRuntime_ppc.cpp index 53644210415..54336e9f62b 100644 --- a/src/hotspot/cpu/ppc/sharedRuntime_ppc.cpp +++ b/src/hotspot/cpu/ppc/sharedRuntime_ppc.cpp @@ -360,7 +360,7 @@ OopMap* RegisterSaver::push_frame_reg_args_and_save_live_registers(MacroAssemble assert(RegisterSaver_LiveVecRegs[i + 1].reg_num == reg_num + 1, "or use other instructions!"); __ stxvp(as_VectorRegister(reg_num).to_vsr(), offset, R1_SP); - // Note: The contents were read in the same order (see loadV16_Power9 node in ppc.ad). + // Note: The contents were read in the same order (see loadV16 node in ppc.ad). // RegisterMap::pd_location only uses the first VMReg for each VectorRegister. if (generate_oop_map) { map->set_callee_saved(VMRegImpl::stack2reg(offset >> 2), @@ -374,13 +374,8 @@ OopMap* RegisterSaver::push_frame_reg_args_and_save_live_registers(MacroAssemble for (int i = 0; i < vecregstosave_num; i++) { int reg_num = RegisterSaver_LiveVecRegs[i].reg_num; - if (PowerArchitecturePPC64 >= 9) { - __ stxv(as_VectorRegister(reg_num)->to_vsr(), offset, R1_SP); - } else { - __ li(R31, offset); - __ stxvd2x(as_VectorRegister(reg_num)->to_vsr(), R31, R1_SP); - } - // Note: The contents were read in the same order (see loadV16_Power8 / loadV16_Power9 node in ppc.ad). + __ stxv(as_VectorRegister(reg_num)->to_vsr(), offset, R1_SP); + // Note: The contents were read in the same order (see loadV16 node in ppc.ad). // RegisterMap::pd_location only uses the first VMReg for each VectorRegister. if (generate_oop_map) { VMReg vsr = RegisterSaver_LiveVecRegs[i].vmreg; @@ -464,12 +459,7 @@ void RegisterSaver::restore_live_registers_and_pop_frame(MacroAssembler* masm, for (int i = 0; i < vecregstosave_num; i++) { int reg_num = RegisterSaver_LiveVecRegs[i].reg_num; - if (PowerArchitecturePPC64 >= 9) { - __ lxv(as_VectorRegister(reg_num).to_vsr(), offset, R1_SP); - } else { - __ li(R31, offset); - __ lxvd2x(as_VectorRegister(reg_num).to_vsr(), R31, R1_SP); - } + __ lxv(as_VectorRegister(reg_num).to_vsr(), offset, R1_SP); offset += vec_reg_size; } diff --git a/src/hotspot/cpu/ppc/vm_version_ppc.cpp b/src/hotspot/cpu/ppc/vm_version_ppc.cpp index 3e3b1103c86..be05ec1dfb3 100644 --- a/src/hotspot/cpu/ppc/vm_version_ppc.cpp +++ b/src/hotspot/cpu/ppc/vm_version_ppc.cpp @@ -109,6 +109,9 @@ void VM_Version::initialize() { if (FLAG_IS_DEFAULT(SuperwordUseVSX) && CompilerConfig::is_c2_enabled()) { FLAG_SET_ERGO(SuperwordUseVSX, true); } + } else if (SuperwordUseVSX) { + warning("SuperwordUseVSX specified, but needs at least Power9."); + FLAG_SET_DEFAULT(SuperwordUseVSX, false); } MaxVectorSize = SuperwordUseVSX ? 16 : 8; diff --git a/src/hotspot/cpu/riscv/c1_LIRGenerator_riscv.cpp b/src/hotspot/cpu/riscv/c1_LIRGenerator_riscv.cpp index f290708a231..5e0deb84a14 100644 --- a/src/hotspot/cpu/riscv/c1_LIRGenerator_riscv.cpp +++ b/src/hotspot/cpu/riscv/c1_LIRGenerator_riscv.cpp @@ -1169,4 +1169,5 @@ void LIRGenerator::volatile_field_store(LIR_Opr value, LIR_Address* address, void LIRGenerator::volatile_field_load(LIR_Address* address, LIR_Opr result, CodeEmitInfo* info) { __ volatile_load_mem_reg(address, result, info); + __ membar_acquire(); } diff --git a/src/hotspot/cpu/riscv/c2_MacroAssembler_riscv.cpp b/src/hotspot/cpu/riscv/c2_MacroAssembler_riscv.cpp index 0d06fd469de..c9cd8220551 100644 --- a/src/hotspot/cpu/riscv/c2_MacroAssembler_riscv.cpp +++ b/src/hotspot/cpu/riscv/c2_MacroAssembler_riscv.cpp @@ -3069,12 +3069,12 @@ void C2_MacroAssembler::reduce_mul_integral_v(Register dst, Register src1, Vecto // If the operation is MUL, then the identity value is one. vmv_v_i(vtmp1, 1); vmerge_vvm(vtmp2, vtmp1, src2); // vm == v0 - vslidedown_vi(vtmp1, vtmp2, vector_length); + slidedown_v(vtmp1, vtmp2, vector_length); vsetvli_helper(bt, vector_length); vmul_vv(vtmp1, vtmp1, vtmp2); } else { - vslidedown_vi(vtmp1, src2, vector_length); + slidedown_v(vtmp1, src2, vector_length); vsetvli_helper(bt, vector_length); vmul_vv(vtmp1, vtmp1, src2); @@ -3082,7 +3082,7 @@ void C2_MacroAssembler::reduce_mul_integral_v(Register dst, Register src1, Vecto while (vector_length > 1) { vector_length /= 2; - vslidedown_vi(vtmp2, vtmp1, vector_length); + slidedown_v(vtmp2, vtmp1, vector_length); vsetvli_helper(bt, vector_length); vmul_vv(vtmp1, vtmp1, vtmp2); } @@ -3281,40 +3281,44 @@ VFCVT_SAFE(vfcvt_rtz_x_f_v); // Extract a scalar element from an vector at position 'idx'. // The input elements in src are expected to be of integral type. -void C2_MacroAssembler::extract_v(Register dst, VectorRegister src, BasicType bt, - int idx, VectorRegister tmp) { +void C2_MacroAssembler::extract_v(Register dst, VectorRegister src, + BasicType bt, int idx, VectorRegister vtmp) { assert(is_integral_type(bt), "unsupported element type"); assert(idx >= 0, "idx cannot be negative"); // Only need the first element after vector slidedown vsetvli_helper(bt, 1); if (idx == 0) { vmv_x_s(dst, src); - } else if (idx <= 31) { - vslidedown_vi(tmp, src, idx); - vmv_x_s(dst, tmp); } else { - mv(t0, idx); - vslidedown_vx(tmp, src, t0); - vmv_x_s(dst, tmp); + slidedown_v(vtmp, src, idx); + vmv_x_s(dst, vtmp); } } // Extract a scalar element from an vector at position 'idx'. // The input elements in src are expected to be of floating point type. -void C2_MacroAssembler::extract_fp_v(FloatRegister dst, VectorRegister src, BasicType bt, - int idx, VectorRegister tmp) { +void C2_MacroAssembler::extract_fp_v(FloatRegister dst, VectorRegister src, + BasicType bt, int idx, VectorRegister vtmp) { assert(is_floating_point_type(bt), "unsupported element type"); assert(idx >= 0, "idx cannot be negative"); // Only need the first element after vector slidedown vsetvli_helper(bt, 1); if (idx == 0) { vfmv_f_s(dst, src); - } else if (idx <= 31) { - vslidedown_vi(tmp, src, idx); - vfmv_f_s(dst, tmp); } else { - mv(t0, idx); - vslidedown_vx(tmp, src, t0); - vfmv_f_s(dst, tmp); + slidedown_v(vtmp, src, idx); + vfmv_f_s(dst, vtmp); + } +} + +// Move elements down a vector register group. +// Offset is the start index (offset) for the source. +void C2_MacroAssembler::slidedown_v(VectorRegister dst, VectorRegister src, + uint32_t offset, Register tmp) { + if (is_uimm5(offset)) { + vslidedown_vi(dst, src, offset); + } else { + mv(tmp, offset); + vslidedown_vx(dst, src, tmp); } } diff --git a/src/hotspot/cpu/riscv/c2_MacroAssembler_riscv.hpp b/src/hotspot/cpu/riscv/c2_MacroAssembler_riscv.hpp index fa87ceba295..468d53b1a54 100644 --- a/src/hotspot/cpu/riscv/c2_MacroAssembler_riscv.hpp +++ b/src/hotspot/cpu/riscv/c2_MacroAssembler_riscv.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2026, 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. * @@ -296,7 +296,13 @@ void vfcvt_rtz_x_f_v_safe(VectorRegister dst, VectorRegister src); - void extract_v(Register dst, VectorRegister src, BasicType bt, int idx, VectorRegister tmp); - void extract_fp_v(FloatRegister dst, VectorRegister src, BasicType bt, int idx, VectorRegister tmp); + void extract_v(Register dst, VectorRegister src, + BasicType bt, int idx, VectorRegister vtmp); + + void extract_fp_v(FloatRegister dst, VectorRegister src, + BasicType bt, int idx, VectorRegister vtmp); + + void slidedown_v(VectorRegister dst, VectorRegister src, + uint32_t offset, Register tmp = t0); #endif // CPU_RISCV_C2_MACROASSEMBLER_RISCV_HPP diff --git a/src/hotspot/cpu/riscv/gc/z/zBarrierSetAssembler_riscv.cpp b/src/hotspot/cpu/riscv/gc/z/zBarrierSetAssembler_riscv.cpp index 163271a2f11..1b4e522973b 100644 --- a/src/hotspot/cpu/riscv/gc/z/zBarrierSetAssembler_riscv.cpp +++ b/src/hotspot/cpu/riscv/gc/z/zBarrierSetAssembler_riscv.cpp @@ -734,6 +734,7 @@ public: #define __ masm-> void ZBarrierSetAssembler::generate_c2_load_barrier_stub(MacroAssembler* masm, ZLoadBarrierStubC2* stub) const { + Assembler::InlineSkippedInstructionsCounter skipped_counter(masm); BLOCK_COMMENT("ZLoadBarrierStubC2"); // Stub entry @@ -753,6 +754,7 @@ void ZBarrierSetAssembler::generate_c2_load_barrier_stub(MacroAssembler* masm, Z } void ZBarrierSetAssembler::generate_c2_store_barrier_stub(MacroAssembler* masm, ZStoreBarrierStubC2* stub) const { + Assembler::InlineSkippedInstructionsCounter skipped_counter(masm); BLOCK_COMMENT("ZStoreBarrierStubC2"); // Stub entry diff --git a/src/hotspot/cpu/riscv/gc/z/z_riscv.ad b/src/hotspot/cpu/riscv/gc/z/z_riscv.ad index a408cf309d5..0078deb76e8 100644 --- a/src/hotspot/cpu/riscv/gc/z/z_riscv.ad +++ b/src/hotspot/cpu/riscv/gc/z/z_riscv.ad @@ -1,5 +1,5 @@ // -// Copyright (c) 2019, 2025, Oracle and/or its affiliates. All rights reserved. +// Copyright (c) 2019, 2026, Oracle and/or its affiliates. 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. // @@ -57,6 +57,7 @@ static void check_color(MacroAssembler* masm, Register ref, bool on_non_strong, } static void z_load_barrier(MacroAssembler* masm, const MachNode* node, Address ref_addr, Register ref, Register tmp) { + Assembler::InlineSkippedInstructionsCounter skipped_counter(masm); const bool on_non_strong = ((node->barrier_data() & ZBarrierWeak) != 0) || ((node->barrier_data() & ZBarrierPhantom) != 0); @@ -78,6 +79,7 @@ static void z_load_barrier(MacroAssembler* masm, const MachNode* node, Address r } static void z_store_barrier(MacroAssembler* masm, const MachNode* node, Address ref_addr, Register rnew_zaddress, Register rnew_zpointer, Register tmp, bool is_atomic) { + Assembler::InlineSkippedInstructionsCounter skipped_counter(masm); if (node->barrier_data() == ZBarrierElided) { z_color(masm, node, rnew_zpointer, rnew_zaddress, tmp); } else { diff --git a/src/hotspot/cpu/riscv/templateTable_riscv.cpp b/src/hotspot/cpu/riscv/templateTable_riscv.cpp index 5cc725e3af4..bae5bb7b57b 100644 --- a/src/hotspot/cpu/riscv/templateTable_riscv.cpp +++ b/src/hotspot/cpu/riscv/templateTable_riscv.cpp @@ -3389,7 +3389,6 @@ void TemplateTable::invokeinterface(int byte_no) { __ bind(notVFinal); // Get receiver klass into x13 - __ restore_locals(); __ load_klass(x13, x12); Label no_such_method; diff --git a/src/hotspot/cpu/s390/c1_LIRGenerator_s390.cpp b/src/hotspot/cpu/s390/c1_LIRGenerator_s390.cpp index 5a0fd5f9561..1ffd172df8f 100644 --- a/src/hotspot/cpu/s390/c1_LIRGenerator_s390.cpp +++ b/src/hotspot/cpu/s390/c1_LIRGenerator_s390.cpp @@ -1046,6 +1046,7 @@ void LIRGenerator::volatile_field_store(LIR_Opr value, LIR_Address* address, void LIRGenerator::volatile_field_load(LIR_Address* address, LIR_Opr result, CodeEmitInfo* info) { __ load(address, result, info); + __ membar_acquire(); } void LIRGenerator::do_update_CRC32(Intrinsic* x) { diff --git a/src/hotspot/cpu/s390/gc/g1/g1BarrierSetAssembler_s390.cpp b/src/hotspot/cpu/s390/gc/g1/g1BarrierSetAssembler_s390.cpp index 617bc7cd00c..881fb613114 100644 --- a/src/hotspot/cpu/s390/gc/g1/g1BarrierSetAssembler_s390.cpp +++ b/src/hotspot/cpu/s390/gc/g1/g1BarrierSetAssembler_s390.cpp @@ -281,6 +281,7 @@ void G1BarrierSetAssembler::load_at(MacroAssembler* masm, DecoratorSet decorator if (on_oop && on_reference && L_handle_null == nullptr) { L_handle_null = &done; } CardTableBarrierSetAssembler::load_at(masm, decorators, type, src, dst, tmp1, tmp2, L_handle_null); if (on_oop && on_reference) { + assert(tmp1 != noreg && tmp2 != noreg, "need temp registers for G1 pre-barrier"); // Generate the G1 pre-barrier code to log the value of // the referent field in an SATB buffer. g1_write_barrier_pre(masm, decorators | IS_NOT_NULL, diff --git a/src/hotspot/cpu/s390/interp_masm_s390.cpp b/src/hotspot/cpu/s390/interp_masm_s390.cpp index d5239898dd7..7327e2a13f2 100644 --- a/src/hotspot/cpu/s390/interp_masm_s390.cpp +++ b/src/hotspot/cpu/s390/interp_masm_s390.cpp @@ -411,7 +411,7 @@ void InterpreterMacroAssembler::load_resolved_reference_at_index(Register result // Load pointer for resolved_references[] objArray. z_lg(result, in_bytes(ConstantPool::cache_offset()), result); z_lg(result, in_bytes(ConstantPoolCache::resolved_references_offset()), result); - resolve_oop_handle(result); // Load resolved references array itself. + resolve_oop_handle(result, Z_R0_scratch, Z_R1_scratch); // Load resolved references array itself. #ifdef ASSERT NearLabel index_ok; z_lgf(Z_R0, Address(result, arrayOopDesc::length_offset_in_bytes())); diff --git a/src/hotspot/cpu/s390/macroAssembler_s390.cpp b/src/hotspot/cpu/s390/macroAssembler_s390.cpp index de3608e74ba..b5898648014 100644 --- a/src/hotspot/cpu/s390/macroAssembler_s390.cpp +++ b/src/hotspot/cpu/s390/macroAssembler_s390.cpp @@ -4705,16 +4705,8 @@ void MacroAssembler::oop_decoder(Register Rdst, Register Rsrc, bool maybenull, R } // ((OopHandle)result).resolve(); -void MacroAssembler::resolve_oop_handle(Register result) { - // OopHandle::resolve is an indirection. - z_lg(result, 0, result); -} - -void MacroAssembler::load_mirror_from_const_method(Register mirror, Register const_method) { - mem2reg_opt(mirror, Address(const_method, ConstMethod::constants_offset())); - mem2reg_opt(mirror, Address(mirror, ConstantPool::pool_holder_offset())); - mem2reg_opt(mirror, Address(mirror, Klass::java_mirror_offset())); - resolve_oop_handle(mirror); +void MacroAssembler::resolve_oop_handle(Register result, Register tmp1, Register tmp2) { + access_load_at(T_OBJECT, IN_NATIVE, Address(result, 0), result, tmp1, tmp2); } void MacroAssembler::load_method_holder(Register holder, Register method) { @@ -5886,6 +5878,28 @@ void MacroAssembler::asm_assert_frame_size(Register expected_size, Register tmp, #endif // ASSERT } +#ifdef ASSERT +bool is_excluded(Register excluded_register[], Register reg, int n) { + for (int i = 0; i < n; i++) { + if (excluded_register[i] == reg) { + return true; + } + } + return false; +} + +void MacroAssembler::clobber_volatile_registers(Register excluded_register[], int n) { + const int magic_number = 0x82; + + for (int i = 0; i < 6 /* R0 to R5 */; i++) { + Register reg = as_Register(i); + if (!is_excluded(excluded_register, reg, n)) { + load_const_optimized(reg, magic_number); + } + } +} +#endif // ASSERT + // Save and restore functions: Exclude Z_R0. void MacroAssembler::save_volatile_regs(Register dst, int offset, bool include_fp, bool include_flags) { z_stmg(Z_R1, Z_R5, offset, dst); offset += 5 * BytesPerWord; diff --git a/src/hotspot/cpu/s390/macroAssembler_s390.hpp b/src/hotspot/cpu/s390/macroAssembler_s390.hpp index 32e484d4790..34389917cef 100644 --- a/src/hotspot/cpu/s390/macroAssembler_s390.hpp +++ b/src/hotspot/cpu/s390/macroAssembler_s390.hpp @@ -484,6 +484,10 @@ class MacroAssembler: public Assembler { // Pop current C frame and restore return PC register (Z_R14). void pop_frame_restore_retPC(int frame_size_in_bytes); +#ifdef ASSERT + void clobber_volatile_registers(Register excluded_register[], int n); +#endif // ASSERT + // // Calls // @@ -885,8 +889,7 @@ class MacroAssembler: public Assembler { void oop_decoder(Register Rdst, Register Rsrc, bool maybenull, Register Rbase = Z_R1, int pow2_offset = -1); - void resolve_oop_handle(Register result); - void load_mirror_from_const_method(Register mirror, Register const_method); + void resolve_oop_handle(Register result, Register tmp1, Register tmp2); void load_method_holder(Register holder, Register method); //-------------------------- diff --git a/src/hotspot/cpu/s390/templateInterpreterGenerator_s390.cpp b/src/hotspot/cpu/s390/templateInterpreterGenerator_s390.cpp index 2da21f08bbc..dba04fc0e85 100644 --- a/src/hotspot/cpu/s390/templateInterpreterGenerator_s390.cpp +++ b/src/hotspot/cpu/s390/templateInterpreterGenerator_s390.cpp @@ -1113,6 +1113,7 @@ void TemplateInterpreterGenerator::generate_fixed_frame(bool native_call) { { // locals const Register local_addr = Z_ARG4; + const Register constants_addr = Z_ARG2; BLOCK_COMMENT("generate_fixed_frame: initialize interpreter state {"); @@ -1128,8 +1129,8 @@ void TemplateInterpreterGenerator::generate_fixed_frame(bool native_call) { __ z_stg(Z_R10, _z_ijava_state_neg(sender_sp), fp); // Load cp cache and save it at the end of this block. - __ z_lg(Z_R1_scratch, Address(const_method, ConstMethod::constants_offset())); - __ z_lg(Z_R1_scratch, Address(Z_R1_scratch, ConstantPool::cache_offset())); + __ z_lg(constants_addr, Address(const_method, ConstMethod::constants_offset())); + __ z_lg(Z_R1_scratch, Address(constants_addr, ConstantPool::cache_offset())); // z_ijava_state->method = method; __ z_stg(Z_method, _z_ijava_state_neg(method), fp); @@ -1192,7 +1193,9 @@ void TemplateInterpreterGenerator::generate_fixed_frame(bool native_call) { __ z_stg(Z_R1_scratch, _z_ijava_state_neg(cpoolCache), fp); // Get mirror and store it in the frame as GC root for this Method*. - __ load_mirror_from_const_method(Z_R1_scratch, const_method); + __ mem2reg_opt(Z_R1_scratch, Address(constants_addr, ConstantPool::pool_holder_offset())); + __ mem2reg_opt(Z_R1_scratch, Address(Z_R1_scratch, Klass::java_mirror_offset())); + __ resolve_oop_handle(Z_R1_scratch, Z_R0_scratch, Z_R1_scratch); __ z_stg(Z_R1_scratch, _z_ijava_state_neg(mirror), fp); BLOCK_COMMENT("} generate_fixed_frame: initialize interpreter state"); @@ -2028,7 +2031,7 @@ address TemplateInterpreterGenerator::generate_currentThread() { uint64_t entry_off = __ offset(); __ z_lg(Z_RET, Address(Z_thread, JavaThread::threadObj_offset())); - __ resolve_oop_handle(Z_RET); + __ resolve_oop_handle(Z_RET, Z_R0_scratch, Z_R1_scratch); // Restore caller sp for c2i case. __ resize_frame_absolute(Z_R10, Z_R0, true); // Cut the stack back to where the caller started. diff --git a/src/hotspot/cpu/s390/templateTable_s390.cpp b/src/hotspot/cpu/s390/templateTable_s390.cpp index 647915ef4fa..3b0929608a3 100644 --- a/src/hotspot/cpu/s390/templateTable_s390.cpp +++ b/src/hotspot/cpu/s390/templateTable_s390.cpp @@ -480,8 +480,9 @@ void TemplateTable::fast_aldc(LdcType type) { // Convert null sentinel to null. __ load_const_optimized(Z_R1_scratch, (intptr_t)Universe::the_null_sentinel_addr()); - __ resolve_oop_handle(Z_R1_scratch); - __ z_cg(Z_tos, Address(Z_R1_scratch)); + __ z_lg(Z_R1_scratch, Address(Z_R1_scratch)); + __ resolve_oop_handle(Z_R1_scratch, Z_R0_scratch, Z_R1_scratch); + __ z_cgr(Z_tos, Z_R1_scratch); __ z_brne(L_resolved); __ clear_reg(Z_tos); __ z_bru(L_resolved); @@ -2478,7 +2479,7 @@ void TemplateTable::load_resolved_field_entry(Register obj, if (is_static) { __ load_sized_value(obj, Address(cache, ResolvedFieldEntry::field_holder_offset()), sizeof(void*), false); __ load_sized_value(obj, Address(obj, in_bytes(Klass::java_mirror_offset())), sizeof(void*), false); - __ resolve_oop_handle(obj); + __ resolve_oop_handle(obj, Z_R0_scratch, Z_R1_scratch); } } diff --git a/src/hotspot/cpu/x86/assembler_x86.cpp b/src/hotspot/cpu/x86/assembler_x86.cpp index a4f2968f0d1..0c8dd85b15d 100644 --- a/src/hotspot/cpu/x86/assembler_x86.cpp +++ b/src/hotspot/cpu/x86/assembler_x86.cpp @@ -1664,14 +1664,14 @@ void Assembler::eandl(Register dst, Register src1, Register src2, bool no_flags) } void Assembler::andnl(Register dst, Register src1, Register src2) { - assert(VM_Version::supports_bmi1(), "bit manipulation instructions not supported"); + assert(VM_Version::supports_bmi1() && VM_Version::supports_avx(), "bit manipulation instructions not supported"); InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); int encode = vex_prefix_and_encode(dst->encoding(), src1->encoding(), src2->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_38, &attributes, true); emit_int16((unsigned char)0xF2, (0xC0 | encode)); } void Assembler::andnl(Register dst, Register src1, Address src2) { - assert(VM_Version::supports_bmi1(), "bit manipulation instructions not supported"); + assert(VM_Version::supports_bmi1() && VM_Version::supports_avx(), "bit manipulation instructions not supported"); InstructionMark im(this); InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); attributes.set_address_attributes(/* tuple_type */ EVEX_NOSCALE, /* input_size_in_bits */ EVEX_32bit); @@ -1696,14 +1696,14 @@ void Assembler::bswapl(Register reg) { // bswap } void Assembler::blsil(Register dst, Register src) { - assert(VM_Version::supports_bmi1(), "bit manipulation instructions not supported"); + assert(VM_Version::supports_bmi1() && VM_Version::supports_avx(), "bit manipulation instructions not supported"); InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); int encode = vex_prefix_and_encode(rbx->encoding(), dst->encoding(), src->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_38, &attributes, true); emit_int16((unsigned char)0xF3, (0xC0 | encode)); } void Assembler::blsil(Register dst, Address src) { - assert(VM_Version::supports_bmi1(), "bit manipulation instructions not supported"); + assert(VM_Version::supports_bmi1() && VM_Version::supports_avx(), "bit manipulation instructions not supported"); InstructionMark im(this); InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); attributes.set_address_attributes(/* tuple_type */ EVEX_NOSCALE, /* input_size_in_bits */ EVEX_32bit); @@ -1713,7 +1713,7 @@ void Assembler::blsil(Register dst, Address src) { } void Assembler::blsmskl(Register dst, Register src) { - assert(VM_Version::supports_bmi1(), "bit manipulation instructions not supported"); + assert(VM_Version::supports_bmi1() && VM_Version::supports_avx(), "bit manipulation instructions not supported"); InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); int encode = vex_prefix_and_encode(rdx->encoding(), dst->encoding(), src->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_38, &attributes, true); emit_int16((unsigned char)0xF3, @@ -1721,7 +1721,7 @@ void Assembler::blsmskl(Register dst, Register src) { } void Assembler::blsmskl(Register dst, Address src) { - assert(VM_Version::supports_bmi1(), "bit manipulation instructions not supported"); + assert(VM_Version::supports_bmi1() && VM_Version::supports_avx(), "bit manipulation instructions not supported"); InstructionMark im(this); InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); attributes.set_address_attributes(/* tuple_type */ EVEX_NOSCALE, /* input_size_in_bits */ EVEX_32bit); @@ -1731,14 +1731,14 @@ void Assembler::blsmskl(Register dst, Address src) { } void Assembler::blsrl(Register dst, Register src) { - assert(VM_Version::supports_bmi1(), "bit manipulation instructions not supported"); + assert(VM_Version::supports_bmi1() && VM_Version::supports_avx(), "bit manipulation instructions not supported"); InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); int encode = vex_prefix_and_encode(rcx->encoding(), dst->encoding(), src->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_38, &attributes, true); emit_int16((unsigned char)0xF3, (0xC0 | encode)); } void Assembler::blsrl(Register dst, Address src) { - assert(VM_Version::supports_bmi1(), "bit manipulation instructions not supported"); + assert(VM_Version::supports_bmi1() && VM_Version::supports_avx(), "bit manipulation instructions not supported"); InstructionMark im(this); InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); attributes.set_address_attributes(/* tuple_type */ EVEX_NOSCALE, /* input_size_in_bits */ EVEX_32bit); @@ -7275,21 +7275,21 @@ void Assembler::testl(Register dst, Address src) { } void Assembler::tzcntl(Register dst, Register src) { - assert(VM_Version::supports_bmi1(), "tzcnt instruction not supported"); + assert(UseCountTrailingZerosInstruction, "tzcnt instruction not supported"); emit_int8((unsigned char)0xF3); int encode = prefix_and_encode(dst->encoding(), src->encoding(), true /* is_map1 */); emit_opcode_prefix_and_encoding((unsigned char)0xBC, 0xC0, encode); } void Assembler::etzcntl(Register dst, Register src, bool no_flags) { - assert(VM_Version::supports_bmi1(), "tzcnt instruction not supported"); + assert(UseCountTrailingZerosInstruction, "tzcnt instruction not supported"); InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); int encode = eevex_prefix_and_encode_nf(dst->encoding(), 0, src->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_3C /* MAP4 */, &attributes, no_flags); emit_int16((unsigned char)0xF4, (0xC0 | encode)); } void Assembler::tzcntl(Register dst, Address src) { - assert(VM_Version::supports_bmi1(), "tzcnt instruction not supported"); + assert(UseCountTrailingZerosInstruction, "tzcnt instruction not supported"); InstructionMark im(this); emit_int8((unsigned char)0xF3); prefix(src, dst, false, true /* is_map1 */); @@ -7298,7 +7298,7 @@ void Assembler::tzcntl(Register dst, Address src) { } void Assembler::etzcntl(Register dst, Address src, bool no_flags) { - assert(VM_Version::supports_bmi1(), "tzcnt instruction not supported"); + assert(UseCountTrailingZerosInstruction, "tzcnt instruction not supported"); InstructionMark im(this); InstructionAttr attributes(AVX_128bit, /* vex_w */ false, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); attributes.set_address_attributes(/* tuple_type */ EVEX_NOSCALE, /* input_size_in_bits */ EVEX_32bit); @@ -7308,21 +7308,21 @@ void Assembler::etzcntl(Register dst, Address src, bool no_flags) { } void Assembler::tzcntq(Register dst, Register src) { - assert(VM_Version::supports_bmi1(), "tzcnt instruction not supported"); + assert(UseCountTrailingZerosInstruction, "tzcnt instruction not supported"); emit_int8((unsigned char)0xF3); int encode = prefixq_and_encode(dst->encoding(), src->encoding(), true /* is_map1 */); emit_opcode_prefix_and_encoding((unsigned char)0xBC, 0xC0, encode); } void Assembler::etzcntq(Register dst, Register src, bool no_flags) { - assert(VM_Version::supports_bmi1(), "tzcnt instruction not supported"); + assert(UseCountTrailingZerosInstruction, "tzcnt instruction not supported"); InstructionAttr attributes(AVX_128bit, /* vex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); int encode = eevex_prefix_and_encode_nf(dst->encoding(), 0, src->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_3C /* MAP4 */, &attributes, no_flags); emit_int16((unsigned char)0xF4, (0xC0 | encode)); } void Assembler::tzcntq(Register dst, Address src) { - assert(VM_Version::supports_bmi1(), "tzcnt instruction not supported"); + assert(UseCountTrailingZerosInstruction, "tzcnt instruction not supported"); InstructionMark im(this); emit_int8((unsigned char)0xF3); prefixq(src, dst, true /* is_map1 */); @@ -7331,7 +7331,7 @@ void Assembler::tzcntq(Register dst, Address src) { } void Assembler::etzcntq(Register dst, Address src, bool no_flags) { - assert(VM_Version::supports_bmi1(), "tzcnt instruction not supported"); + assert(UseCountTrailingZerosInstruction, "tzcnt instruction not supported"); InstructionMark im(this); InstructionAttr attributes(AVX_128bit, /* vex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); attributes.set_address_attributes(/* tuple_type */ EVEX_NOSCALE, /* input_size_in_bits */ EVEX_64bit); @@ -15000,14 +15000,14 @@ void Assembler::eandq(Register dst, Address src1, Register src2, bool no_flags) } void Assembler::andnq(Register dst, Register src1, Register src2) { - assert(VM_Version::supports_bmi1(), "bit manipulation instructions not supported"); + assert(VM_Version::supports_bmi1() && VM_Version::supports_avx(), "bit manipulation instructions not supported"); InstructionAttr attributes(AVX_128bit, /* vex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); int encode = vex_prefix_and_encode(dst->encoding(), src1->encoding(), src2->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_38, &attributes, true); emit_int16((unsigned char)0xF2, (0xC0 | encode)); } void Assembler::andnq(Register dst, Register src1, Address src2) { - assert(VM_Version::supports_bmi1(), "bit manipulation instructions not supported"); + assert(VM_Version::supports_bmi1() && VM_Version::supports_avx(), "bit manipulation instructions not supported"); InstructionMark im(this); InstructionAttr attributes(AVX_128bit, /* vex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); attributes.set_address_attributes(/* tuple_type */ EVEX_NOSCALE, /* input_size_in_bits */ EVEX_64bit); @@ -15032,14 +15032,14 @@ void Assembler::bswapq(Register reg) { } void Assembler::blsiq(Register dst, Register src) { - assert(VM_Version::supports_bmi1(), "bit manipulation instructions not supported"); + assert(VM_Version::supports_bmi1() && VM_Version::supports_avx(), "bit manipulation instructions not supported"); InstructionAttr attributes(AVX_128bit, /* vex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); int encode = vex_prefix_and_encode(rbx->encoding(), dst->encoding(), src->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_38, &attributes, true); emit_int16((unsigned char)0xF3, (0xC0 | encode)); } void Assembler::blsiq(Register dst, Address src) { - assert(VM_Version::supports_bmi1(), "bit manipulation instructions not supported"); + assert(VM_Version::supports_bmi1() && VM_Version::supports_avx(), "bit manipulation instructions not supported"); InstructionMark im(this); InstructionAttr attributes(AVX_128bit, /* vex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); attributes.set_address_attributes(/* tuple_type */ EVEX_NOSCALE, /* input_size_in_bits */ EVEX_64bit); @@ -15049,14 +15049,14 @@ void Assembler::blsiq(Register dst, Address src) { } void Assembler::blsmskq(Register dst, Register src) { - assert(VM_Version::supports_bmi1(), "bit manipulation instructions not supported"); + assert(VM_Version::supports_bmi1() && VM_Version::supports_avx(), "bit manipulation instructions not supported"); InstructionAttr attributes(AVX_128bit, /* vex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); int encode = vex_prefix_and_encode(rdx->encoding(), dst->encoding(), src->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_38, &attributes, true); emit_int16((unsigned char)0xF3, (0xC0 | encode)); } void Assembler::blsmskq(Register dst, Address src) { - assert(VM_Version::supports_bmi1(), "bit manipulation instructions not supported"); + assert(VM_Version::supports_bmi1() && VM_Version::supports_avx(), "bit manipulation instructions not supported"); InstructionMark im(this); InstructionAttr attributes(AVX_128bit, /* vex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); attributes.set_address_attributes(/* tuple_type */ EVEX_NOSCALE, /* input_size_in_bits */ EVEX_64bit); @@ -15066,14 +15066,14 @@ void Assembler::blsmskq(Register dst, Address src) { } void Assembler::blsrq(Register dst, Register src) { - assert(VM_Version::supports_bmi1(), "bit manipulation instructions not supported"); + assert(VM_Version::supports_bmi1() && VM_Version::supports_avx(), "bit manipulation instructions not supported"); InstructionAttr attributes(AVX_128bit, /* vex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); int encode = vex_prefix_and_encode(rcx->encoding(), dst->encoding(), src->encoding(), VEX_SIMD_NONE, VEX_OPCODE_0F_38, &attributes, true); emit_int16((unsigned char)0xF3, (0xC0 | encode)); } void Assembler::blsrq(Register dst, Address src) { - assert(VM_Version::supports_bmi1(), "bit manipulation instructions not supported"); + assert(VM_Version::supports_bmi1() && VM_Version::supports_avx(), "bit manipulation instructions not supported"); InstructionMark im(this); InstructionAttr attributes(AVX_128bit, /* vex_w */ true, /* legacy_mode */ false, /* no_mask_reg */ true, /* uses_vl */ false); attributes.set_address_attributes(/* tuple_type */ EVEX_NOSCALE, /* input_size_in_bits */ EVEX_64bit); diff --git a/src/hotspot/cpu/x86/c1_CodeStubs_x86.cpp b/src/hotspot/cpu/x86/c1_CodeStubs_x86.cpp index 95ce48f34db..9a4044a4f0c 100644 --- a/src/hotspot/cpu/x86/c1_CodeStubs_x86.cpp +++ b/src/hotspot/cpu/x86/c1_CodeStubs_x86.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -293,7 +293,7 @@ void PatchingStub::emit_code(LIR_Assembler* ce) { address ptr = (address)(_pc_start + i); int a_byte = (*ptr) & 0xFF; __ emit_int8(a_byte); - *ptr = 0x90; // make the site look like a nop + *ptr = NativeInstruction::nop_instruction_code; // make the site look like a nop } } @@ -342,6 +342,38 @@ void PatchingStub::emit_code(LIR_Assembler* ce) { assert(patch_info_pc - end_of_patch == bytes_to_skip, "incorrect patch info"); address entry = __ pc(); + // NativeGeneralJump::insert_unconditional will be writing a jmp rel32 at _pc_start over the existing instructions. + // There are 2 cases: + // - the existing instruction is a mov r64 imm64 from LIR_Assembler::klass2reg_with_patching + // - or there are nops there (from higher in this function). + // In the first case, since a jmp rel32 is 5-byte long, but a mov r64 imm64 is 10-byte long + // (resp. 11 if using a REX2 prefix), so we are left with the last 5 (resp. 6) bytes of the + // immediate operand (which are all 0x00). When debugging, this confuses the disassembler + // because it tries to recognize an instruction starting immediately after the jmp rel32, + // leading to wrong instructions, and possibly failure to disassemble further the whole function. + // + // To be disassembler-friendly, let's replace the leftover 0x00 with nops. + // There are 2 shapes: + // - without REX2 prefix: REX prefix | MOV r64 + // - with REX2 prefix: REX2 prefix | REX prefix | MOV r64 + // then, we know the 8 bytes after are the immediate operand. + if (NativeInstruction* ni = nativeInstruction_at(_pc_start); ni->is_mov_literal64()) { + int length_before_immediate = ni->has_rex2_prefix() ? 3 : 2; + assert(*(long long int*)(_pc_start + length_before_immediate) == 0, "imm64 must be 0 in mov r64, imm64"); + // We don't need to replace the NativeGeneralJump::instruction_size first bytes, since insert_unconditional + // will overwrite. + for (int i = NativeGeneralJump::instruction_size; i < length_before_immediate + BytesPerLong; ++i) { + _pc_start[i] = NativeInstruction::nop_instruction_code; + } + } +#ifdef ASSERT + else { // and we make sure otherwise, we indeed have just nops. + for (int i = 0; i < NativeGeneralJump::instruction_size; ++i) { + assert(_pc_start[i] == NativeInstruction::nop_instruction_code, "patching over an unexpected instruction"); + } + } +#endif + NativeGeneralJump::insert_unconditional((address)_pc_start, entry); address target = nullptr; relocInfo::relocType reloc_type = relocInfo::none; diff --git a/src/hotspot/cpu/x86/c1_LIRGenerator_x86.cpp b/src/hotspot/cpu/x86/c1_LIRGenerator_x86.cpp index f448e4ee17f..cc068cda7a9 100644 --- a/src/hotspot/cpu/x86/c1_LIRGenerator_x86.cpp +++ b/src/hotspot/cpu/x86/c1_LIRGenerator_x86.cpp @@ -1432,4 +1432,5 @@ void LIRGenerator::volatile_field_load(LIR_Address* address, LIR_Opr result, } else { __ load(address, result, info); } + __ membar_acquire(); } diff --git a/src/hotspot/cpu/x86/c2_MacroAssembler_x86.cpp b/src/hotspot/cpu/x86/c2_MacroAssembler_x86.cpp index b4d8aa10de2..e164ee37edf 100644 --- a/src/hotspot/cpu/x86/c2_MacroAssembler_x86.cpp +++ b/src/hotspot/cpu/x86/c2_MacroAssembler_x86.cpp @@ -5558,7 +5558,7 @@ void C2_MacroAssembler::vector_mask_operation_helper(int opc, Register dst, Regi } break; case Op_VectorMaskFirstTrue: - if (VM_Version::supports_bmi1()) { + if (UseCountTrailingZerosInstruction) { if (masklen < 32) { orl(tmp, 1 << masklen); tzcntl(dst, tmp); @@ -6350,7 +6350,7 @@ void C2_MacroAssembler::udivI(Register rax, Register divisor, Register rdx) { // See Hacker's Delight (2nd ed), section 9.3 which is implemented in java.lang.Long.divideUnsigned() movl(rdx, rax); subl(rdx, divisor); - if (VM_Version::supports_bmi1()) { + if (VM_Version::supports_bmi1() && VM_Version::supports_avx()) { andnl(rax, rdx, rax); } else { notl(rdx); @@ -6374,7 +6374,7 @@ void C2_MacroAssembler::umodI(Register rax, Register divisor, Register rdx) { // See Hacker's Delight (2nd ed), section 9.3 which is implemented in java.lang.Long.remainderUnsigned() movl(rdx, rax); subl(rax, divisor); - if (VM_Version::supports_bmi1()) { + if (VM_Version::supports_bmi1() && VM_Version::supports_avx()) { andnl(rax, rax, rdx); } else { notl(rax); @@ -6403,7 +6403,7 @@ void C2_MacroAssembler::udivmodI(Register rax, Register divisor, Register rdx, R // java.lang.Long.divideUnsigned() and java.lang.Long.remainderUnsigned() movl(rdx, rax); subl(rax, divisor); - if (VM_Version::supports_bmi1()) { + if (VM_Version::supports_bmi1() && VM_Version::supports_avx()) { andnl(rax, rax, rdx); } else { notl(rax); @@ -6515,7 +6515,7 @@ void C2_MacroAssembler::udivL(Register rax, Register divisor, Register rdx) { // See Hacker's Delight (2nd ed), section 9.3 which is implemented in java.lang.Long.divideUnsigned() movq(rdx, rax); subq(rdx, divisor); - if (VM_Version::supports_bmi1()) { + if (VM_Version::supports_bmi1() && VM_Version::supports_avx()) { andnq(rax, rdx, rax); } else { notq(rdx); @@ -6539,7 +6539,7 @@ void C2_MacroAssembler::umodL(Register rax, Register divisor, Register rdx) { // See Hacker's Delight (2nd ed), section 9.3 which is implemented in java.lang.Long.remainderUnsigned() movq(rdx, rax); subq(rax, divisor); - if (VM_Version::supports_bmi1()) { + if (VM_Version::supports_bmi1() && VM_Version::supports_avx()) { andnq(rax, rax, rdx); } else { notq(rax); @@ -6567,7 +6567,7 @@ void C2_MacroAssembler::udivmodL(Register rax, Register divisor, Register rdx, R // java.lang.Long.divideUnsigned() and java.lang.Long.remainderUnsigned() movq(rdx, rax); subq(rax, divisor); - if (VM_Version::supports_bmi1()) { + if (VM_Version::supports_bmi1() && VM_Version::supports_avx()) { andnq(rax, rax, rdx); } else { notq(rax); diff --git a/src/hotspot/cpu/x86/macroAssembler_x86.cpp b/src/hotspot/cpu/x86/macroAssembler_x86.cpp index 5ab3ca339aa..f64c4d3f086 100644 --- a/src/hotspot/cpu/x86/macroAssembler_x86.cpp +++ b/src/hotspot/cpu/x86/macroAssembler_x86.cpp @@ -55,6 +55,7 @@ #include "runtime/sharedRuntime.hpp" #include "runtime/stubRoutines.hpp" #include "utilities/checkedCast.hpp" +#include "utilities/globalDefinitions.hpp" #include "utilities/macros.hpp" #ifdef PRODUCT @@ -2540,6 +2541,17 @@ void MacroAssembler::sign_extend_short(Register reg) { movswl(reg, reg); // movsxw } +void MacroAssembler::narrow_subword_type(Register reg, BasicType bt) { + assert(is_subword_type(bt), "required"); + switch (bt) { + case T_BOOLEAN: andl(reg, 1); break; + case T_BYTE: movsbl(reg, reg); break; + case T_CHAR: movzwl(reg, reg); break; + case T_SHORT: movswl(reg, reg); break; + default: ShouldNotReachHere(); + } +} + void MacroAssembler::testl(Address dst, int32_t imm32) { if (imm32 >= 0 && is8bit(imm32)) { testb(dst, imm32); @@ -6955,7 +6967,7 @@ void MacroAssembler::vectorized_mismatch(Register obja, Register objb, Register xorq(result, result); if ((AVX3Threshold == 0) && (UseAVX > 2) && - VM_Version::supports_avx512vlbw()) { + VM_Version::supports_avx512vlbw() && UseCountTrailingZerosInstruction) { Label VECTOR64_LOOP, VECTOR64_NOT_EQUAL, VECTOR32_TAIL; cmpq(length, 64); diff --git a/src/hotspot/cpu/x86/macroAssembler_x86.hpp b/src/hotspot/cpu/x86/macroAssembler_x86.hpp index 021d2943ee8..b73339c217f 100644 --- a/src/hotspot/cpu/x86/macroAssembler_x86.hpp +++ b/src/hotspot/cpu/x86/macroAssembler_x86.hpp @@ -444,6 +444,9 @@ class MacroAssembler: public Assembler { void sign_extend_short(Register reg); void sign_extend_byte(Register reg); + // Clean up a subword typed value to the representation in compliance with JVMS §2.3 + void narrow_subword_type(Register reg, BasicType bt); + // Division by power of 2, rounding towards 0 void division_with_shift(Register reg, int shift_value); diff --git a/src/hotspot/cpu/x86/nativeInst_x86.hpp b/src/hotspot/cpu/x86/nativeInst_x86.hpp index aba4400515f..cbb72508cc1 100644 --- a/src/hotspot/cpu/x86/nativeInst_x86.hpp +++ b/src/hotspot/cpu/x86/nativeInst_x86.hpp @@ -97,11 +97,7 @@ class NativeInstruction { }; inline NativeInstruction* nativeInstruction_at(address address) { - NativeInstruction* inst = (NativeInstruction*)address; -#ifdef ASSERT - //inst->verify(); -#endif - return inst; + return (NativeInstruction*)address; } class NativeCall; diff --git a/src/hotspot/cpu/x86/stubGenerator_x86_64.cpp b/src/hotspot/cpu/x86/stubGenerator_x86_64.cpp index 993d1964034..b0612d21437 100644 --- a/src/hotspot/cpu/x86/stubGenerator_x86_64.cpp +++ b/src/hotspot/cpu/x86/stubGenerator_x86_64.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -4891,7 +4891,7 @@ void StubGenerator::generate_compiler_stubs() { StubRoutines::_data_cache_writeback_sync = generate_data_cache_writeback_sync(); #ifdef COMPILER2 - if ((UseAVX == 2) && EnableX86ECoreOpts) { + if ((UseAVX == 2) && EnableX86ECoreOpts && UseCountTrailingZerosInstruction) { generate_string_indexof(StubRoutines::_string_indexof_array); } #endif diff --git a/src/hotspot/cpu/x86/vm_version_x86.cpp b/src/hotspot/cpu/x86/vm_version_x86.cpp index cf9de40a237..d30db9859b8 100644 --- a/src/hotspot/cpu/x86/vm_version_x86.cpp +++ b/src/hotspot/cpu/x86/vm_version_x86.cpp @@ -942,21 +942,21 @@ void VM_Version::get_processor_features() { } if (UseSSE < 4) { - _features.clear_feature(CPU_SSE4_1); - _features.clear_feature(CPU_SSE4_2); + clear_feature(CPU_SSE4_1); + clear_feature(CPU_SSE4_2); } if (UseSSE < 3) { - _features.clear_feature(CPU_SSE3); - _features.clear_feature(CPU_SSSE3); - _features.clear_feature(CPU_SSE4A); + clear_feature(CPU_SSE3); + clear_feature(CPU_SSSE3); + clear_feature(CPU_SSE4A); } if (UseSSE < 2) - _features.clear_feature(CPU_SSE2); + clear_feature(CPU_SSE2); if (UseSSE < 1) - _features.clear_feature(CPU_SSE); + clear_feature(CPU_SSE); // ZX cpus specific settings if (is_zx() && FLAG_IS_DEFAULT(UseAVX)) { @@ -1030,102 +1030,119 @@ void VM_Version::get_processor_features() { } if (UseAVX < 3) { - _features.clear_feature(CPU_AVX512F); - _features.clear_feature(CPU_AVX512DQ); - _features.clear_feature(CPU_AVX512CD); - _features.clear_feature(CPU_AVX512BW); - _features.clear_feature(CPU_AVX512ER); - _features.clear_feature(CPU_AVX512PF); - _features.clear_feature(CPU_AVX512VL); - _features.clear_feature(CPU_AVX512_VPOPCNTDQ); - _features.clear_feature(CPU_AVX512_VPCLMULQDQ); - _features.clear_feature(CPU_AVX512_VAES); - _features.clear_feature(CPU_AVX512_VNNI); - _features.clear_feature(CPU_AVX512_VBMI); - _features.clear_feature(CPU_AVX512_VBMI2); - _features.clear_feature(CPU_AVX512_BITALG); - _features.clear_feature(CPU_AVX512_IFMA); - _features.clear_feature(CPU_APX_F); - _features.clear_feature(CPU_AVX512_FP16); - _features.clear_feature(CPU_AVX10_1); - _features.clear_feature(CPU_AVX10_2); + clear_feature(CPU_AVX512F); + clear_feature(CPU_AVX512DQ); + clear_feature(CPU_AVX512CD); + clear_feature(CPU_AVX512BW); + clear_feature(CPU_AVX512ER); + clear_feature(CPU_AVX512PF); + clear_feature(CPU_AVX512VL); + clear_feature(CPU_AVX512_VPOPCNTDQ); + clear_feature(CPU_AVX512_VPCLMULQDQ); + clear_feature(CPU_AVX512_VAES); + clear_feature(CPU_AVX512_VNNI); + clear_feature(CPU_AVX512_VBMI); + clear_feature(CPU_AVX512_VBMI2); + clear_feature(CPU_AVX512_BITALG); + clear_feature(CPU_AVX512_IFMA); + clear_feature(CPU_APX_F); + clear_feature(CPU_AVX512_FP16); + clear_feature(CPU_AVX10_1); + clear_feature(CPU_AVX10_2); } if (UseAVX < 2) { - _features.clear_feature(CPU_AVX2); - _features.clear_feature(CPU_AVX_IFMA); + clear_feature(CPU_AVX2); + clear_feature(CPU_AVX_IFMA); } if (UseAVX < 1) { - _features.clear_feature(CPU_AVX); - _features.clear_feature(CPU_VZEROUPPER); - _features.clear_feature(CPU_F16C); - _features.clear_feature(CPU_SHA512); + clear_feature(CPU_AVX); + clear_feature(CPU_VZEROUPPER); + clear_feature(CPU_F16C); + clear_feature(CPU_SHA512); } if (logical_processors_per_package() == 1) { // HT processor could be installed on a system which doesn't support HT. - _features.clear_feature(CPU_HT); + clear_feature(CPU_HT); } if (is_intel()) { // Intel cpus specific settings if (is_knights_family()) { - _features.clear_feature(CPU_VZEROUPPER); - _features.clear_feature(CPU_AVX512BW); - _features.clear_feature(CPU_AVX512VL); - _features.clear_feature(CPU_APX_F); - _features.clear_feature(CPU_AVX512DQ); - _features.clear_feature(CPU_AVX512_VNNI); - _features.clear_feature(CPU_AVX512_VAES); - _features.clear_feature(CPU_AVX512_VPOPCNTDQ); - _features.clear_feature(CPU_AVX512_VPCLMULQDQ); - _features.clear_feature(CPU_AVX512_VBMI); - _features.clear_feature(CPU_AVX512_VBMI2); - _features.clear_feature(CPU_CLWB); - _features.clear_feature(CPU_FLUSHOPT); - _features.clear_feature(CPU_GFNI); - _features.clear_feature(CPU_AVX512_BITALG); - _features.clear_feature(CPU_AVX512_IFMA); - _features.clear_feature(CPU_AVX_IFMA); - _features.clear_feature(CPU_AVX512_FP16); - _features.clear_feature(CPU_AVX10_1); - _features.clear_feature(CPU_AVX10_2); + clear_feature(CPU_VZEROUPPER); + clear_feature(CPU_AVX512BW); + clear_feature(CPU_AVX512VL); + clear_feature(CPU_APX_F); + clear_feature(CPU_AVX512DQ); + clear_feature(CPU_AVX512_VNNI); + clear_feature(CPU_AVX512_VAES); + clear_feature(CPU_AVX512_VPOPCNTDQ); + clear_feature(CPU_AVX512_VPCLMULQDQ); + clear_feature(CPU_AVX512_VBMI); + clear_feature(CPU_AVX512_VBMI2); + clear_feature(CPU_CLWB); + clear_feature(CPU_FLUSHOPT); + clear_feature(CPU_GFNI); + clear_feature(CPU_AVX512_BITALG); + clear_feature(CPU_AVX512_IFMA); + clear_feature(CPU_AVX_IFMA); + clear_feature(CPU_AVX512_FP16); + clear_feature(CPU_AVX10_1); + clear_feature(CPU_AVX10_2); } } // Currently APX support is only enabled for targets supporting AVX512VL feature. if (supports_apx_f() && os_supports_apx_egprs() && supports_avx512vl()) { if (FLAG_IS_DEFAULT(UseAPX)) { - UseAPX = false; // by default UseAPX is false - _features.clear_feature(CPU_APX_F); + FLAG_SET_DEFAULT(UseAPX, false); // by default UseAPX is false + clear_feature(CPU_APX_F); } else if (!UseAPX) { - _features.clear_feature(CPU_APX_F); + clear_feature(CPU_APX_F); } - } else if (UseAPX) { - if (!FLAG_IS_DEFAULT(UseAPX)) { - warning("APX is not supported on this CPU, setting it to false)"); + } else { + if (!os_supports_apx_egprs() || !supports_avx512vl()) { + clear_feature(CPU_APX_F); + } + if (UseAPX) { + if (!FLAG_IS_DEFAULT(UseAPX)) { + warning("APX is not supported on this CPU, setting it to false)"); + } + FLAG_SET_DEFAULT(UseAPX, false); } - FLAG_SET_DEFAULT(UseAPX, false); } - CHECK_CPU_FEATURE(supports_clmul, CLMUL); - CHECK_CPU_FEATURE(supports_aes, AES); - CHECK_CPU_FEATURE(supports_fma, FMA); + CHECK_CPU_FEATURE(UseCLMUL, CLMUL, supports_clmul(), MULTI_INST_WARNING_MSG); + CHECK_CPU_FEATURE(UseAES, AES, supports_aes(), MULTI_INST_WARNING_MSG); + CHECK_CPU_FEATURE(UseFMA, FMA, supports_fma(), MULTI_INST_WARNING_MSG); + CHECK_CPU_FEATURE(UseCountLeadingZerosInstruction, LZCNT, supports_lzcnt(), SINGLE_INST_WARNING_MSG); + // BMI instructions (except tzcnt) use an encoding with VEX prefix. + // VEX prefix is generated only when AVX > 0. + CHECK_CPU_FEATURE(UseBMI1Instructions, BMI1, supports_bmi1(), MULTI_INST_WARNING_MSG); - if (supports_sha() || (supports_avx2() && supports_bmi2())) { - if (FLAG_IS_DEFAULT(UseSHA)) { - UseSHA = true; - } else if (!UseSHA) { - _features.clear_feature(CPU_SHA); + if (supports_bmi2() && supports_avx()) { + if (FLAG_IS_DEFAULT(UseBMI2Instructions)) { + FLAG_SET_DEFAULT(UseBMI2Instructions, true); + } else if (!UseBMI2Instructions) { + clear_feature(CPU_BMI2); } - } else if (UseSHA) { - if (!FLAG_IS_DEFAULT(UseSHA)) { - warning("SHA instructions are not available on this CPU"); + } else { + if (!supports_avx()) { + clear_feature(CPU_BMI2); + } + if (UseBMI2Instructions) { + if (!FLAG_IS_DEFAULT(UseBMI2Instructions)) { + warning("BMI2 instructions are not available on this CPU (AVX is also required)"); + } + FLAG_SET_DEFAULT(UseBMI2Instructions, false); } - FLAG_SET_DEFAULT(UseSHA, false); } + CHECK_CPU_FEATURE(UsePopCountInstruction, POPCNT, supports_popcnt(), SINGLE_INST_WARNING_MSG); + CHECK_CPU_FEATURE(UseSHA, SHA, supports_sha() || (supports_avx2() && supports_bmi2()), MULTI_INST_WARNING_MSG); + if (FLAG_IS_DEFAULT(IntelJccErratumMitigation)) { _has_intel_jcc_erratum = compute_has_intel_jcc_erratum(); FLAG_SET_ERGO(IntelJccErratumMitigation, _has_intel_jcc_erratum); @@ -1716,28 +1733,11 @@ void VM_Version::get_processor_features() { FLAG_SET_DEFAULT(UseVectorizedHashCodeIntrinsic, false); } - // Use count leading zeros count instruction if available. - if (supports_lzcnt()) { - if (FLAG_IS_DEFAULT(UseCountLeadingZerosInstruction)) { - UseCountLeadingZerosInstruction = true; - } - } else if (UseCountLeadingZerosInstruction) { - if (!FLAG_IS_DEFAULT(UseCountLeadingZerosInstruction)) { - warning("lzcnt instruction is not available on this CPU"); - } - FLAG_SET_DEFAULT(UseCountLeadingZerosInstruction, false); - } - // Use count trailing zeros instruction if available if (supports_bmi1()) { // tzcnt does not require VEX prefix if (FLAG_IS_DEFAULT(UseCountTrailingZerosInstruction)) { - if (!UseBMI1Instructions && !FLAG_IS_DEFAULT(UseBMI1Instructions)) { - // Don't use tzcnt if BMI1 is switched off on command line. - UseCountTrailingZerosInstruction = false; - } else { - UseCountTrailingZerosInstruction = true; - } + UseCountTrailingZerosInstruction = true; } } else if (UseCountTrailingZerosInstruction) { if (!FLAG_IS_DEFAULT(UseCountTrailingZerosInstruction)) { @@ -1746,42 +1746,6 @@ void VM_Version::get_processor_features() { FLAG_SET_DEFAULT(UseCountTrailingZerosInstruction, false); } - // BMI instructions (except tzcnt) use an encoding with VEX prefix. - // VEX prefix is generated only when AVX > 0. - if (supports_bmi1() && supports_avx()) { - if (FLAG_IS_DEFAULT(UseBMI1Instructions)) { - UseBMI1Instructions = true; - } - } else if (UseBMI1Instructions) { - if (!FLAG_IS_DEFAULT(UseBMI1Instructions)) { - warning("BMI1 instructions are not available on this CPU (AVX is also required)"); - } - FLAG_SET_DEFAULT(UseBMI1Instructions, false); - } - - if (supports_bmi2() && supports_avx()) { - if (FLAG_IS_DEFAULT(UseBMI2Instructions)) { - UseBMI2Instructions = true; - } - } else if (UseBMI2Instructions) { - if (!FLAG_IS_DEFAULT(UseBMI2Instructions)) { - warning("BMI2 instructions are not available on this CPU (AVX is also required)"); - } - FLAG_SET_DEFAULT(UseBMI2Instructions, false); - } - - // Use population count instruction if available. - if (supports_popcnt()) { - if (FLAG_IS_DEFAULT(UsePopCountInstruction)) { - UsePopCountInstruction = true; - } - } else if (UsePopCountInstruction) { - if (!FLAG_IS_DEFAULT(UsePopCountInstruction)) { - warning("POPCNT instruction is not available on this CPU"); - } - FLAG_SET_DEFAULT(UsePopCountInstruction, false); - } - // Use fast-string operations if available. if (supports_erms()) { if (FLAG_IS_DEFAULT(UseFastStosb)) { @@ -2527,7 +2491,7 @@ const char* VM_Version::cpu_brand_string(void) { } int ret_val = cpu_extended_brand_string(_cpu_brand_string, CPU_EBS_MAX_LENGTH); if (ret_val != OS_OK) { - FREE_C_HEAP_ARRAY(char, _cpu_brand_string); + FREE_C_HEAP_ARRAY(_cpu_brand_string); _cpu_brand_string = nullptr; } } @@ -3366,12 +3330,12 @@ int VM_Version::cpu_features_size() { } void VM_Version::store_cpu_features(void* buf) { - VM_Features copy = _features; - copy.clear_feature(CPU_HT); // HT does not result in incompatibility of aot code cache + VM_Features copy = _features.aot_code_cache_features(); memcpy(buf, ©, sizeof(VM_Features)); } -bool VM_Version::supports_features(void* features_buffer) { +bool VM_Version::verify_aot_code_cache_features(void* features_buffer) { VM_Features* features_to_test = (VM_Features*)features_buffer; - return _features.supports_features(features_to_test); + VM_Features rt_features = _features.aot_code_cache_features(); + return rt_features.verify_aot_code_cache_features(features_to_test); } diff --git a/src/hotspot/cpu/x86/vm_version_x86.hpp b/src/hotspot/cpu/x86/vm_version_x86.hpp index f721635a02e..86d40442372 100644 --- a/src/hotspot/cpu/x86/vm_version_x86.hpp +++ b/src/hotspot/cpu/x86/vm_version_x86.hpp @@ -517,14 +517,21 @@ protected: return (_features_bitmap[idx] & bit_mask(feature)) != 0; } - bool supports_features(VM_Features* features_to_test) { + bool verify_aot_code_cache_features(VM_Features* features_to_test) { for (int i = 0; i < features_bitmap_element_count(); i++) { - if ((_features_bitmap[i] & features_to_test->_features_bitmap[i]) != features_to_test->_features_bitmap[i]) { + if (_features_bitmap[i] != features_to_test->_features_bitmap[i]) { return false; - } + } } return true; } + + VM_Features aot_code_cache_features() { + VM_Features copy = *this; + // HT does not result in incompatibility of aot code cache + copy.clear_feature(CPU_HT); + return copy; + } }; // CPU feature flags vector, can be affected by VM settings. @@ -1134,7 +1141,7 @@ public: // Size of the buffer must be same as returned by cpu_features_size() static void store_cpu_features(void* buf); - static bool supports_features(void* features_to_test); + static bool verify_aot_code_cache_features(void* features_buffer); }; #endif // CPU_X86_VM_VERSION_X86_HPP diff --git a/src/hotspot/cpu/x86/x86.ad b/src/hotspot/cpu/x86/x86.ad index eaa88d900c7..a029d33cdec 100644 --- a/src/hotspot/cpu/x86/x86.ad +++ b/src/hotspot/cpu/x86/x86.ad @@ -4048,7 +4048,7 @@ class FusedPatternMatcher { }; static bool is_bmi_pattern(Node* n, Node* m) { - assert(UseBMI1Instructions, "sanity"); + assert(VM_Version::supports_bmi1() && VM_Version::supports_avx(), "sanity"); if (n != nullptr && m != nullptr) { if (m->Opcode() == Op_LoadI) { FusedPatternMatcher bmii(n, m, Op_ConI); @@ -4068,7 +4068,7 @@ static bool is_bmi_pattern(Node* n, Node* m) { // Should the matcher clone input 'm' of node 'n'? bool Matcher::pd_clone_node(Node* n, Node* m, Matcher::MStack& mstack) { // If 'n' and 'm' are part of a graph for BMI instruction, clone the input 'm'. - if (UseBMI1Instructions && is_bmi_pattern(n, m)) { + if (VM_Version::supports_bmi1() && VM_Version::supports_avx() && is_bmi_pattern(n, m)) { mstack.push(m, Visit); return true; } @@ -4568,7 +4568,7 @@ encode %{ } else if (_method->intrinsic_id() == vmIntrinsicID::_ensureMaterializedForStackWalk) { // The NOP here is purely to ensure that eliding a call to // JVM_EnsureMaterializedForStackWalk doesn't change the code size. - __ addr_nop_5(); + __ nop(5); __ block_comment("call JVM_EnsureMaterializedForStackWalk (elided)"); } else { int method_index = resolved_method_index(masm); @@ -10899,10 +10899,11 @@ instruct xaddB(memory mem, rRegI newval, rFlagsReg cr) %{ predicate(!n->as_LoadStore()->result_not_used()); match(Set newval (GetAndAddB mem newval)); effect(KILL cr); - format %{ "xaddb_lock $mem, $newval" %} + format %{ "xaddb_lock $mem, $newval\t# $newval -> byte" %} ins_encode %{ __ lock(); __ xaddb($mem$$Address, $newval$$Register); + __ narrow_subword_type($newval$$Register, T_BYTE); %} ins_pipe(pipe_cmpxchg); %} @@ -10935,10 +10936,11 @@ instruct xaddS(memory mem, rRegI newval, rFlagsReg cr) %{ predicate(!n->as_LoadStore()->result_not_used()); match(Set newval (GetAndAddS mem newval)); effect(KILL cr); - format %{ "xaddw_lock $mem, $newval" %} + format %{ "xaddw_lock $mem, $newval\t# $newval -> short" %} ins_encode %{ __ lock(); __ xaddw($mem$$Address, $newval$$Register); + __ narrow_subword_type($newval$$Register, T_SHORT); %} ins_pipe(pipe_cmpxchg); %} @@ -11017,18 +11019,20 @@ instruct xaddL(memory mem, rRegL newval, rFlagsReg cr) %{ instruct xchgB( memory mem, rRegI newval) %{ match(Set newval (GetAndSetB mem newval)); - format %{ "XCHGB $newval,[$mem]" %} + format %{ "XCHGB $newval,[$mem]\t# $newval -> byte" %} ins_encode %{ __ xchgb($newval$$Register, $mem$$Address); + __ narrow_subword_type($newval$$Register, T_BYTE); %} ins_pipe( pipe_cmpxchg ); %} instruct xchgS( memory mem, rRegI newval) %{ match(Set newval (GetAndSetS mem newval)); - format %{ "XCHGW $newval,[$mem]" %} + format %{ "XCHGW $newval,[$mem]\t# $newval -> short" %} ins_encode %{ __ xchgw($newval$$Register, $mem$$Address); + __ narrow_subword_type($newval$$Register, T_SHORT); %} ins_pipe( pipe_cmpxchg ); %} @@ -13161,7 +13165,7 @@ instruct andI_mem_imm(memory dst, immI src, rFlagsReg cr) // BMI1 instructions instruct andnI_rReg_rReg_mem(rRegI dst, rRegI src1, memory src2, immI_M1 minus_1, rFlagsReg cr) %{ match(Set dst (AndI (XorI src1 minus_1) (LoadI src2))); - predicate(UseBMI1Instructions); + predicate(VM_Version::supports_bmi1() && VM_Version::supports_avx()); effect(KILL cr); flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_clears_overflow_flag, PD::Flag_clears_carry_flag); @@ -13176,7 +13180,7 @@ instruct andnI_rReg_rReg_mem(rRegI dst, rRegI src1, memory src2, immI_M1 minus_1 instruct andnI_rReg_rReg_rReg(rRegI dst, rRegI src1, rRegI src2, immI_M1 minus_1, rFlagsReg cr) %{ match(Set dst (AndI (XorI src1 minus_1) src2)); - predicate(UseBMI1Instructions); + predicate(VM_Version::supports_bmi1() && VM_Version::supports_avx()); effect(KILL cr); flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_clears_overflow_flag, PD::Flag_clears_carry_flag); @@ -13190,7 +13194,7 @@ instruct andnI_rReg_rReg_rReg(rRegI dst, rRegI src1, rRegI src2, immI_M1 minus_1 instruct blsiI_rReg_rReg(rRegI dst, rRegI src, immI_0 imm_zero, rFlagsReg cr) %{ match(Set dst (AndI (SubI imm_zero src) src)); - predicate(UseBMI1Instructions); + predicate(VM_Version::supports_bmi1() && VM_Version::supports_avx()); effect(KILL cr); flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_clears_overflow_flag); @@ -13204,7 +13208,7 @@ instruct blsiI_rReg_rReg(rRegI dst, rRegI src, immI_0 imm_zero, rFlagsReg cr) %{ instruct blsiI_rReg_mem(rRegI dst, memory src, immI_0 imm_zero, rFlagsReg cr) %{ match(Set dst (AndI (SubI imm_zero (LoadI src) ) (LoadI src) )); - predicate(UseBMI1Instructions); + predicate(VM_Version::supports_bmi1() && VM_Version::supports_avx()); effect(KILL cr); flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_clears_overflow_flag); @@ -13220,7 +13224,7 @@ instruct blsiI_rReg_mem(rRegI dst, memory src, immI_0 imm_zero, rFlagsReg cr) %{ instruct blsmskI_rReg_mem(rRegI dst, memory src, immI_M1 minus_1, rFlagsReg cr) %{ match(Set dst (XorI (AddI (LoadI src) minus_1) (LoadI src) ) ); - predicate(UseBMI1Instructions); + predicate(VM_Version::supports_bmi1() && VM_Version::supports_avx()); effect(KILL cr); flag(PD::Flag_sets_sign_flag, PD::Flag_clears_zero_flag, PD::Flag_clears_overflow_flag); @@ -13236,7 +13240,7 @@ instruct blsmskI_rReg_mem(rRegI dst, memory src, immI_M1 minus_1, rFlagsReg cr) instruct blsmskI_rReg_rReg(rRegI dst, rRegI src, immI_M1 minus_1, rFlagsReg cr) %{ match(Set dst (XorI (AddI src minus_1) src)); - predicate(UseBMI1Instructions); + predicate(VM_Version::supports_bmi1() && VM_Version::supports_avx()); effect(KILL cr); flag(PD::Flag_sets_sign_flag, PD::Flag_clears_zero_flag, PD::Flag_clears_overflow_flag); @@ -13252,7 +13256,7 @@ instruct blsmskI_rReg_rReg(rRegI dst, rRegI src, immI_M1 minus_1, rFlagsReg cr) instruct blsrI_rReg_rReg(rRegI dst, rRegI src, immI_M1 minus_1, rFlagsReg cr) %{ match(Set dst (AndI (AddI src minus_1) src) ); - predicate(UseBMI1Instructions); + predicate(VM_Version::supports_bmi1() && VM_Version::supports_avx()); effect(KILL cr); flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_clears_overflow_flag); @@ -13268,7 +13272,7 @@ instruct blsrI_rReg_rReg(rRegI dst, rRegI src, immI_M1 minus_1, rFlagsReg cr) instruct blsrI_rReg_mem(rRegI dst, memory src, immI_M1 minus_1, rFlagsReg cr) %{ match(Set dst (AndI (AddI (LoadI src) minus_1) (LoadI src) ) ); - predicate(UseBMI1Instructions); + predicate(VM_Version::supports_bmi1() && VM_Version::supports_avx()); effect(KILL cr); flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_clears_overflow_flag); @@ -13809,7 +13813,7 @@ instruct btrL_mem_imm(memory dst, immL_NotPow2 con, rFlagsReg cr) // BMI1 instructions instruct andnL_rReg_rReg_mem(rRegL dst, rRegL src1, memory src2, immL_M1 minus_1, rFlagsReg cr) %{ match(Set dst (AndL (XorL src1 minus_1) (LoadL src2))); - predicate(UseBMI1Instructions); + predicate(VM_Version::supports_bmi1() && VM_Version::supports_avx()); effect(KILL cr); flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_clears_overflow_flag, PD::Flag_clears_carry_flag); @@ -13824,7 +13828,7 @@ instruct andnL_rReg_rReg_mem(rRegL dst, rRegL src1, memory src2, immL_M1 minus_1 instruct andnL_rReg_rReg_rReg(rRegL dst, rRegL src1, rRegL src2, immL_M1 minus_1, rFlagsReg cr) %{ match(Set dst (AndL (XorL src1 minus_1) src2)); - predicate(UseBMI1Instructions); + predicate(VM_Version::supports_bmi1() && VM_Version::supports_avx()); effect(KILL cr); flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_clears_overflow_flag, PD::Flag_clears_carry_flag); @@ -13838,7 +13842,7 @@ instruct andnL_rReg_rReg_rReg(rRegL dst, rRegL src1, rRegL src2, immL_M1 minus_1 instruct blsiL_rReg_rReg(rRegL dst, rRegL src, immL0 imm_zero, rFlagsReg cr) %{ match(Set dst (AndL (SubL imm_zero src) src)); - predicate(UseBMI1Instructions); + predicate(VM_Version::supports_bmi1() && VM_Version::supports_avx()); effect(KILL cr); flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_clears_overflow_flag); @@ -13852,7 +13856,7 @@ instruct blsiL_rReg_rReg(rRegL dst, rRegL src, immL0 imm_zero, rFlagsReg cr) %{ instruct blsiL_rReg_mem(rRegL dst, memory src, immL0 imm_zero, rFlagsReg cr) %{ match(Set dst (AndL (SubL imm_zero (LoadL src) ) (LoadL src) )); - predicate(UseBMI1Instructions); + predicate(VM_Version::supports_bmi1() && VM_Version::supports_avx()); effect(KILL cr); flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_clears_overflow_flag); @@ -13868,7 +13872,7 @@ instruct blsiL_rReg_mem(rRegL dst, memory src, immL0 imm_zero, rFlagsReg cr) %{ instruct blsmskL_rReg_mem(rRegL dst, memory src, immL_M1 minus_1, rFlagsReg cr) %{ match(Set dst (XorL (AddL (LoadL src) minus_1) (LoadL src) ) ); - predicate(UseBMI1Instructions); + predicate(VM_Version::supports_bmi1() && VM_Version::supports_avx()); effect(KILL cr); flag(PD::Flag_sets_sign_flag, PD::Flag_clears_zero_flag, PD::Flag_clears_overflow_flag); @@ -13884,7 +13888,7 @@ instruct blsmskL_rReg_mem(rRegL dst, memory src, immL_M1 minus_1, rFlagsReg cr) instruct blsmskL_rReg_rReg(rRegL dst, rRegL src, immL_M1 minus_1, rFlagsReg cr) %{ match(Set dst (XorL (AddL src minus_1) src)); - predicate(UseBMI1Instructions); + predicate(VM_Version::supports_bmi1() && VM_Version::supports_avx()); effect(KILL cr); flag(PD::Flag_sets_sign_flag, PD::Flag_clears_zero_flag, PD::Flag_clears_overflow_flag); @@ -13900,7 +13904,7 @@ instruct blsmskL_rReg_rReg(rRegL dst, rRegL src, immL_M1 minus_1, rFlagsReg cr) instruct blsrL_rReg_rReg(rRegL dst, rRegL src, immL_M1 minus_1, rFlagsReg cr) %{ match(Set dst (AndL (AddL src minus_1) src) ); - predicate(UseBMI1Instructions); + predicate(VM_Version::supports_bmi1() && VM_Version::supports_avx()); effect(KILL cr); flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_clears_overflow_flag); @@ -13916,7 +13920,7 @@ instruct blsrL_rReg_rReg(rRegL dst, rRegL src, immL_M1 minus_1, rFlagsReg cr) instruct blsrL_rReg_mem(rRegL dst, memory src, immL_M1 minus_1, rFlagsReg cr) %{ match(Set dst (AndL (AddL (LoadL src) minus_1) (LoadL src)) ); - predicate(UseBMI1Instructions); + predicate(VM_Version::supports_bmi1() && VM_Version::supports_avx()); effect(KILL cr); flag(PD::Flag_sets_sign_flag, PD::Flag_sets_zero_flag, PD::Flag_clears_overflow_flag); @@ -24920,11 +24924,11 @@ instruct mask_not_imm(kReg dst, kReg src, immI_M1 cnt) %{ ins_pipe( pipe_slow ); %} -instruct long_to_maskLE8_avx(vec dst, rRegL src, rRegL rtmp1, rRegL rtmp2, vec xtmp) %{ +instruct long_to_maskLE8_avx(vec dst, rRegL src, rRegL rtmp1, rRegL rtmp2) %{ predicate(n->bottom_type()->isa_vectmask() == nullptr && Matcher::vector_length(n) <= 8); match(Set dst (VectorLongToMask src)); - effect(TEMP dst, TEMP rtmp1, TEMP rtmp2, TEMP xtmp); - format %{ "long_to_mask_avx $dst, $src\t! using $rtmp1, $rtmp2, $xtmp as TEMP" %} + effect(TEMP dst, TEMP rtmp1, TEMP rtmp2); + format %{ "long_to_mask_avx $dst, $src\t! using $rtmp1, $rtmp2" %} ins_encode %{ int mask_len = Matcher::vector_length(this); int vec_enc = vector_length_encoding(mask_len); @@ -25317,6 +25321,7 @@ instruct reinterpretHF2S(rRegI dst, regF src) format %{ "evmovw $dst, $src" %} ins_encode %{ __ evmovw($dst$$Register, $src$$XMMRegister); + __ narrow_subword_type($dst$$Register, T_SHORT); %} ins_pipe(pipe_slow); %} diff --git a/src/hotspot/os/aix/os_aix.cpp b/src/hotspot/os/aix/os_aix.cpp index 3cad24d388c..32d845b2b6d 100644 --- a/src/hotspot/os/aix/os_aix.cpp +++ b/src/hotspot/os/aix/os_aix.cpp @@ -578,13 +578,13 @@ void os::init_system_properties_values() { char *ld_library_path = NEW_C_HEAP_ARRAY(char, pathsize, mtInternal); os::snprintf_checked(ld_library_path, pathsize, "%s%s" DEFAULT_LIBPATH, v, v_colon); Arguments::set_library_path(ld_library_path); - FREE_C_HEAP_ARRAY(char, ld_library_path); + FREE_C_HEAP_ARRAY(ld_library_path); // Extensions directories. os::snprintf_checked(buf, bufsize, "%s" EXTENSIONS_DIR, Arguments::get_java_home()); Arguments::set_ext_dirs(buf); - FREE_C_HEAP_ARRAY(char, buf); + FREE_C_HEAP_ARRAY(buf); #undef DEFAULT_LIBPATH #undef EXTENSIONS_DIR diff --git a/src/hotspot/os/aix/os_perf_aix.cpp b/src/hotspot/os/aix/os_perf_aix.cpp index cbf78083483..3668ac6ba3f 100644 --- a/src/hotspot/os/aix/os_perf_aix.cpp +++ b/src/hotspot/os/aix/os_perf_aix.cpp @@ -258,10 +258,10 @@ bool CPUPerformanceInterface::CPUPerformance::initialize() { CPUPerformanceInterface::CPUPerformance::~CPUPerformance() { if (_lcpu_names) { - FREE_C_HEAP_ARRAY(perfstat_id_t, _lcpu_names); + FREE_C_HEAP_ARRAY(_lcpu_names); } if (_prev_ticks) { - FREE_C_HEAP_ARRAY(cpu_tick_store_t, _prev_ticks); + FREE_C_HEAP_ARRAY(_prev_ticks); } } @@ -511,12 +511,12 @@ CPUInformationInterface::~CPUInformationInterface() { if (_cpu_info != nullptr) { if (_cpu_info->cpu_name() != nullptr) { const char* cpu_name = _cpu_info->cpu_name(); - FREE_C_HEAP_ARRAY(char, cpu_name); + FREE_C_HEAP_ARRAY(cpu_name); _cpu_info->set_cpu_name(nullptr); } if (_cpu_info->cpu_description() != nullptr) { const char* cpu_desc = _cpu_info->cpu_description(); - FREE_C_HEAP_ARRAY(char, cpu_desc); + FREE_C_HEAP_ARRAY(cpu_desc); _cpu_info->set_cpu_description(nullptr); } delete _cpu_info; @@ -576,7 +576,7 @@ int NetworkPerformanceInterface::NetworkPerformance::network_utilization(Network // check for error if (n_records < 0) { - FREE_C_HEAP_ARRAY(perfstat_netinterface_t, net_stats); + FREE_C_HEAP_ARRAY(net_stats); return OS_ERR; } @@ -593,7 +593,7 @@ int NetworkPerformanceInterface::NetworkPerformance::network_utilization(Network *network_interfaces = new_interface; } - FREE_C_HEAP_ARRAY(perfstat_netinterface_t, net_stats); + FREE_C_HEAP_ARRAY(net_stats); return OS_OK; } diff --git a/src/hotspot/os/bsd/os_bsd.cpp b/src/hotspot/os/bsd/os_bsd.cpp index a4d9a2197a5..b46cc644393 100644 --- a/src/hotspot/os/bsd/os_bsd.cpp +++ b/src/hotspot/os/bsd/os_bsd.cpp @@ -106,6 +106,14 @@ #include #include #include + + // needed by current_stack_base_and_size() workaround for Mavericks + #define DEFAULT_MAIN_THREAD_STACK_PAGES 2048 + #define OS_X_10_9_0_KERNEL_MAJOR_VERSION 13 +#endif + +#if !defined(__APPLE__) && !defined(__NetBSD__) + #include #endif #ifndef MAP_ANONYMOUS @@ -444,14 +452,14 @@ void os::init_system_properties_values() { char *ld_library_path = NEW_C_HEAP_ARRAY(char, ld_library_path_size, mtInternal); os::snprintf_checked(ld_library_path, ld_library_path_size, "%s%s" SYS_EXT_DIR "/lib/%s:" DEFAULT_LIBPATH, v, v_colon, cpu_arch); Arguments::set_library_path(ld_library_path); - FREE_C_HEAP_ARRAY(char, ld_library_path); + FREE_C_HEAP_ARRAY(ld_library_path); } // Extensions directories. os::snprintf_checked(buf, bufsize, "%s" EXTENSIONS_DIR ":" SYS_EXT_DIR EXTENSIONS_DIR, Arguments::get_java_home()); Arguments::set_ext_dirs(buf); - FREE_C_HEAP_ARRAY(char, buf); + FREE_C_HEAP_ARRAY(buf); #else // __APPLE__ @@ -538,7 +546,7 @@ void os::init_system_properties_values() { os::snprintf_checked(ld_library_path, ld_library_path_size, "%s%s%s%s%s" SYS_EXTENSIONS_DIR ":" SYS_EXTENSIONS_DIRS ":.", v, v_colon, l, l_colon, user_home_dir); Arguments::set_library_path(ld_library_path); - FREE_C_HEAP_ARRAY(char, ld_library_path); + FREE_C_HEAP_ARRAY(ld_library_path); } // Extensions directories. @@ -550,7 +558,7 @@ void os::init_system_properties_values() { user_home_dir, Arguments::get_java_home()); Arguments::set_ext_dirs(buf); - FREE_C_HEAP_ARRAY(char, buf); + FREE_C_HEAP_ARRAY(buf); #undef SYS_EXTENSIONS_DIR #undef SYS_EXTENSIONS_DIRS @@ -2545,6 +2553,106 @@ bool os::start_debugging(char *buf, int buflen) { return yes; } +// Java thread: +// +// Low memory addresses +// +------------------------+ +// | |\ Java thread created by VM does not have glibc +// | glibc guard page | - guard, attached Java thread usually has +// | |/ 1 glibc guard page. +// P1 +------------------------+ Thread::stack_base() - Thread::stack_size() +// | |\ +// | HotSpot Guard Pages | - red, yellow and reserved pages +// | |/ +// +------------------------+ StackOverflow::stack_reserved_zone_base() +// | |\ +// | Normal Stack | - +// | |/ +// P2 +------------------------+ Thread::stack_base() +// +// Non-Java thread: +// +// Low memory addresses +// +------------------------+ +// | |\ +// | glibc guard page | - usually 1 page +// | |/ +// P1 +------------------------+ Thread::stack_base() - Thread::stack_size() +// | |\ +// | Normal Stack | - +// | |/ +// P2 +------------------------+ Thread::stack_base() +// +// ** P1 (aka bottom) and size are the address and stack size +// returned from pthread_attr_getstack(). +// ** P2 (aka stack top or base) = P1 + size + +void os::current_stack_base_and_size(address* base, size_t* size) { + address bottom; +#ifdef __APPLE__ + pthread_t self = pthread_self(); + *base = (address) pthread_get_stackaddr_np(self); + *size = pthread_get_stacksize_np(self); +# ifdef __x86_64__ + // workaround for OS X 10.9.0 (Mavericks) + // pthread_get_stacksize_np returns 128 pages even though the actual size is 2048 pages + if (pthread_main_np() == 1) { + // At least on Mac OS 10.12 we have observed stack sizes not aligned + // to pages boundaries. This can be provoked by e.g. setrlimit() (ulimit -s xxxx in the + // shell). Apparently Mac OS actually rounds upwards to next multiple of page size, + // however, we round downwards here to be on the safe side. + *size = align_down(*size, getpagesize()); + + if ((*size) < (DEFAULT_MAIN_THREAD_STACK_PAGES * (size_t)getpagesize())) { + char kern_osrelease[256]; + size_t kern_osrelease_size = sizeof(kern_osrelease); + int ret = sysctlbyname("kern.osrelease", kern_osrelease, &kern_osrelease_size, nullptr, 0); + if (ret == 0) { + // get the major number, atoi will ignore the minor amd micro portions of the version string + if (atoi(kern_osrelease) >= OS_X_10_9_0_KERNEL_MAJOR_VERSION) { + *size = (DEFAULT_MAIN_THREAD_STACK_PAGES*getpagesize()); + } + } + } + } +# endif + bottom = *base - *size; +#elif defined(__OpenBSD__) + stack_t ss; + int rslt = pthread_stackseg_np(pthread_self(), &ss); + + if (rslt != 0) + fatal("pthread_stackseg_np failed with error = %d", rslt); + + *base = (address) ss.ss_sp; + *size = ss.ss_size; + bottom = *base - *size; +#else + pthread_attr_t attr; + + int rslt = pthread_attr_init(&attr); + + // JVM needs to know exact stack location, abort if it fails + if (rslt != 0) + fatal("pthread_attr_init failed with error = %d", rslt); + + rslt = pthread_attr_get_np(pthread_self(), &attr); + + if (rslt != 0) + fatal("pthread_attr_get_np failed with error = %d", rslt); + + if (pthread_attr_getstackaddr(&attr, (void **)&bottom) != 0 || + pthread_attr_getstacksize(&attr, size) != 0) { + fatal("Can not locate current stack attributes!"); + } + + *base = bottom + *size; + + pthread_attr_destroy(&attr); +#endif + assert(os::current_stack_pointer() >= bottom && + os::current_stack_pointer() < *base, "just checking"); +} void os::print_memory_mappings(char* addr, size_t bytes, outputStream* st) {} #if INCLUDE_JFR diff --git a/src/hotspot/os/bsd/os_perf_bsd.cpp b/src/hotspot/os/bsd/os_perf_bsd.cpp index 78d9519c3a7..47fe3a0d7e9 100644 --- a/src/hotspot/os/bsd/os_perf_bsd.cpp +++ b/src/hotspot/os/bsd/os_perf_bsd.cpp @@ -301,7 +301,7 @@ int SystemProcessInterface::SystemProcesses::system_processes(SystemProcess** sy pids_bytes = proc_listpids(PROC_ALL_PIDS, 0, pids, pids_bytes); if (pids_bytes <= 0) { // couldn't fit buffer, retry. - FREE_RESOURCE_ARRAY(pid_t, pids, pid_count); + FREE_RESOURCE_ARRAY(pids, pid_count); pids = nullptr; try_count++; if (try_count > 3) { @@ -381,12 +381,12 @@ CPUInformationInterface::~CPUInformationInterface() { if (_cpu_info != nullptr) { if (_cpu_info->cpu_name() != nullptr) { const char* cpu_name = _cpu_info->cpu_name(); - FREE_C_HEAP_ARRAY(char, cpu_name); + FREE_C_HEAP_ARRAY(cpu_name); _cpu_info->set_cpu_name(nullptr); } if (_cpu_info->cpu_description() != nullptr) { const char* cpu_desc = _cpu_info->cpu_description(); - FREE_C_HEAP_ARRAY(char, cpu_desc); + FREE_C_HEAP_ARRAY(cpu_desc); _cpu_info->set_cpu_description(nullptr); } delete _cpu_info; diff --git a/src/hotspot/os/linux/cgroupSubsystem_linux.cpp b/src/hotspot/os/linux/cgroupSubsystem_linux.cpp index 4a2d75ecdf3..1c183a9bbab 100644 --- a/src/hotspot/os/linux/cgroupSubsystem_linux.cpp +++ b/src/hotspot/os/linux/cgroupSubsystem_linux.cpp @@ -649,7 +649,7 @@ bool CgroupSubsystem::active_processor_count(int (*cpu_bound_func)(), double& va return true; } - int cpu_count = cpu_bound_func(); + double cpu_count = static_cast(cpu_bound_func()); double result = -1; if (!CgroupUtil::processor_count(contrl->controller(), cpu_count, result)) { return false; diff --git a/src/hotspot/os/linux/cgroupUtil_linux.cpp b/src/hotspot/os/linux/cgroupUtil_linux.cpp index f166f6cd5e4..1f7775acfc3 100644 --- a/src/hotspot/os/linux/cgroupUtil_linux.cpp +++ b/src/hotspot/os/linux/cgroupUtil_linux.cpp @@ -25,7 +25,7 @@ #include "cgroupUtil_linux.hpp" -bool CgroupUtil::processor_count(CgroupCpuController* cpu_ctrl, int upper_bound, double& value) { +bool CgroupUtil::processor_count(CgroupCpuController* cpu_ctrl, double upper_bound, double& value) { assert(upper_bound > 0, "upper bound of cpus must be positive"); int quota = -1; int period = -1; @@ -68,8 +68,8 @@ physical_memory_size_type CgroupUtil::get_updated_mem_limit(CgroupMemoryControll // Get an updated cpu limit. The return value is strictly less than or equal to the // passed in 'lowest' value. double CgroupUtil::get_updated_cpu_limit(CgroupCpuController* cpu, - int lowest, - int upper_bound) { + double lowest, + double upper_bound) { assert(lowest > 0 && lowest <= upper_bound, "invariant"); double cpu_limit_val = -1; if (CgroupUtil::processor_count(cpu, upper_bound, cpu_limit_val) && cpu_limit_val != upper_bound) { @@ -145,7 +145,7 @@ void CgroupUtil::adjust_controller(CgroupMemoryController* mem, physical_memory_ os::free(limit_cg_path); } -void CgroupUtil::adjust_controller(CgroupCpuController* cpu, int upper_bound) { +void CgroupUtil::adjust_controller(CgroupCpuController* cpu, double upper_bound) { assert(cpu->cgroup_path() != nullptr, "invariant"); if (strstr(cpu->cgroup_path(), "../") != nullptr) { log_warning(os, container)("Cgroup cpu controller path at '%s' seems to have moved " @@ -163,9 +163,9 @@ void CgroupUtil::adjust_controller(CgroupCpuController* cpu, int upper_bound) { char* cg_path = os::strdup(orig); char* last_slash; assert(cg_path[0] == '/', "cgroup path must start with '/'"); - int lowest_limit = upper_bound; + double lowest_limit = upper_bound; double cpus = get_updated_cpu_limit(cpu, lowest_limit, upper_bound); - int orig_limit = lowest_limit != upper_bound ? lowest_limit : upper_bound; + double orig_limit = lowest_limit != upper_bound ? lowest_limit : upper_bound; char* limit_cg_path = nullptr; while ((last_slash = strrchr(cg_path, '/')) != cg_path) { *last_slash = '\0'; // strip path @@ -193,10 +193,10 @@ void CgroupUtil::adjust_controller(CgroupCpuController* cpu, int upper_bound) { assert(limit_cg_path != nullptr, "limit path must be set"); cpu->set_subsystem_path(limit_cg_path); log_trace(os, container)("Adjusted controller path for cpu to: %s. " - "Lowest limit was: %d", + "Lowest limit was: %.2f", cpu->subsystem_path(), lowest_limit); } else { - log_trace(os, container)("Lowest limit was: %d", lowest_limit); + log_trace(os, container)("Lowest limit was: %.2f", lowest_limit); log_trace(os, container)("No lower limit found for cpu in hierarchy %s, " "adjusting to original path %s", cpu->mount_point(), orig); diff --git a/src/hotspot/os/linux/cgroupUtil_linux.hpp b/src/hotspot/os/linux/cgroupUtil_linux.hpp index 68585c22c2d..c5df7e8efa9 100644 --- a/src/hotspot/os/linux/cgroupUtil_linux.hpp +++ b/src/hotspot/os/linux/cgroupUtil_linux.hpp @@ -32,18 +32,18 @@ class CgroupUtil: AllStatic { public: - static bool processor_count(CgroupCpuController* cpu, int upper_bound, double& value); + static bool processor_count(CgroupCpuController* cpu, double upper_bound, double& value); // Given a memory controller, adjust its path to a point in the hierarchy // that represents the closest memory limit. static void adjust_controller(CgroupMemoryController* m, physical_memory_size_type upper_bound); // Given a cpu controller, adjust its path to a point in the hierarchy // that represents the closest cpu limit. - static void adjust_controller(CgroupCpuController* c, int upper_bound); + static void adjust_controller(CgroupCpuController* c, double upper_bound); private: static physical_memory_size_type get_updated_mem_limit(CgroupMemoryController* m, physical_memory_size_type lowest, physical_memory_size_type upper_bound); - static double get_updated_cpu_limit(CgroupCpuController* c, int lowest, int upper_bound); + static double get_updated_cpu_limit(CgroupCpuController* c, double lowest, double upper_bound); }; #endif // CGROUP_UTIL_LINUX_HPP diff --git a/src/hotspot/os/linux/osContainer_linux.cpp b/src/hotspot/os/linux/osContainer_linux.cpp index da2cbf381e6..511c7bebff7 100644 --- a/src/hotspot/os/linux/osContainer_linux.cpp +++ b/src/hotspot/os/linux/osContainer_linux.cpp @@ -79,9 +79,12 @@ void OSContainer::init() { * that limits enforced by other means (e.g. systemd slice) are properly * detected. */ - const char *reason; - bool any_mem_cpu_limit_present = false; + const char* reason; bool controllers_read_only = cgroup_subsystem->is_containerized(); + + bool any_mem_limit_present = false; + bool cpu_limit_present = false; + if (controllers_read_only) { // in-container case reason = " because all controllers are mounted read-only (container case)"; @@ -89,19 +92,30 @@ void OSContainer::init() { // We can be in one of two cases: // 1.) On a physical Linux system without any limit // 2.) On a physical Linux system with a limit enforced by other means (like systemd slice) + physical_memory_size_type mem_limit_val = value_unlimited; - (void)memory_limit_in_bytes(mem_limit_val); // discard error and use default - double host_cpus = os::Linux::active_processor_count(); + any_mem_limit_present = any_mem_limit_present || (memory_limit_in_bytes(mem_limit_val) && + mem_limit_val != value_unlimited); + + physical_memory_size_type throttle_limit_val = value_unlimited; + any_mem_limit_present = any_mem_limit_present || (memory_throttle_limit_in_bytes(throttle_limit_val) && + throttle_limit_val != value_unlimited); + + physical_memory_size_type soft_limit_val = value_unlimited; + any_mem_limit_present = any_mem_limit_present || (memory_soft_limit_in_bytes(soft_limit_val) && + (soft_limit_val != value_unlimited && soft_limit_val != 0)); + + const double host_cpus = os::Linux::active_processor_count(); double cpus = host_cpus; - (void)active_processor_count(cpus); // discard error and use default - any_mem_cpu_limit_present = mem_limit_val != value_unlimited || host_cpus != cpus; - if (any_mem_cpu_limit_present) { + cpu_limit_present = active_processor_count(cpus) && host_cpus != cpus; + + if (any_mem_limit_present || cpu_limit_present) { reason = " because either a cpu or a memory limit is present"; } else { reason = " because no cpu or memory limit is present"; } } - _is_containerized = controllers_read_only || any_mem_cpu_limit_present; + _is_containerized = controllers_read_only || any_mem_limit_present || cpu_limit_present; log_debug(os, container)("OSContainer::init: is_containerized() = %s%s", _is_containerized ? "true" : "false", reason); diff --git a/src/hotspot/os/linux/os_linux.cpp b/src/hotspot/os/linux/os_linux.cpp index a87c0ab33fa..6927f5108ac 100644 --- a/src/hotspot/os/linux/os_linux.cpp +++ b/src/hotspot/os/linux/os_linux.cpp @@ -710,14 +710,14 @@ void os::init_system_properties_values() { char *ld_library_path = NEW_C_HEAP_ARRAY(char, pathsize, mtInternal); os::snprintf_checked(ld_library_path, pathsize, "%s%s" SYS_EXT_DIR "/lib:" DEFAULT_LIBPATH, v, v_colon); Arguments::set_library_path(ld_library_path); - FREE_C_HEAP_ARRAY(char, ld_library_path); + FREE_C_HEAP_ARRAY(ld_library_path); } // Extensions directories. os::snprintf_checked(buf, bufsize, "%s" EXTENSIONS_DIR ":" SYS_EXT_DIR EXTENSIONS_DIR, Arguments::get_java_home()); Arguments::set_ext_dirs(buf); - FREE_C_HEAP_ARRAY(char, buf); + FREE_C_HEAP_ARRAY(buf); #undef DEFAULT_LIBPATH #undef SYS_EXT_DIR @@ -3435,7 +3435,7 @@ void os::Linux::rebuild_cpu_to_node_map() { } } } - FREE_C_HEAP_ARRAY(unsigned long, cpu_map); + FREE_C_HEAP_ARRAY(cpu_map); } int os::Linux::numa_node_to_cpus(int node, unsigned long *buffer, int bufferlen) { diff --git a/src/hotspot/os/linux/os_perf_linux.cpp b/src/hotspot/os/linux/os_perf_linux.cpp index 9f91f3b4c0d..c0e863ed2a2 100644 --- a/src/hotspot/os/linux/os_perf_linux.cpp +++ b/src/hotspot/os/linux/os_perf_linux.cpp @@ -545,7 +545,7 @@ bool CPUPerformanceInterface::CPUPerformance::initialize() { CPUPerformanceInterface::CPUPerformance::~CPUPerformance() { if (_counters.cpus != nullptr) { - FREE_C_HEAP_ARRAY(char, _counters.cpus); + FREE_C_HEAP_ARRAY(_counters.cpus); } } @@ -811,7 +811,7 @@ int SystemProcessInterface::SystemProcesses::ProcessIterator::current(SystemProc cmdline = get_cmdline(); if (cmdline != nullptr) { process_info->set_command_line(allocate_string(cmdline)); - FREE_C_HEAP_ARRAY(char, cmdline); + FREE_C_HEAP_ARRAY(cmdline); } return OS_OK; @@ -937,12 +937,12 @@ CPUInformationInterface::~CPUInformationInterface() { if (_cpu_info != nullptr) { if (_cpu_info->cpu_name() != nullptr) { const char* cpu_name = _cpu_info->cpu_name(); - FREE_C_HEAP_ARRAY(char, cpu_name); + FREE_C_HEAP_ARRAY(cpu_name); _cpu_info->set_cpu_name(nullptr); } if (_cpu_info->cpu_description() != nullptr) { const char* cpu_desc = _cpu_info->cpu_description(); - FREE_C_HEAP_ARRAY(char, cpu_desc); + FREE_C_HEAP_ARRAY(cpu_desc); _cpu_info->set_cpu_description(nullptr); } delete _cpu_info; diff --git a/src/hotspot/os/linux/procMapsParser.cpp b/src/hotspot/os/linux/procMapsParser.cpp index 0663cae61f3..00675683e34 100644 --- a/src/hotspot/os/linux/procMapsParser.cpp +++ b/src/hotspot/os/linux/procMapsParser.cpp @@ -45,7 +45,7 @@ ProcSmapsParser::ProcSmapsParser(FILE* f) : } ProcSmapsParser::~ProcSmapsParser() { - FREE_C_HEAP_ARRAY(char, _line); + FREE_C_HEAP_ARRAY(_line); } bool ProcSmapsParser::read_line() { diff --git a/src/hotspot/os/posix/perfMemory_posix.cpp b/src/hotspot/os/posix/perfMemory_posix.cpp index c5046797e02..300c86ffc47 100644 --- a/src/hotspot/os/posix/perfMemory_posix.cpp +++ b/src/hotspot/os/posix/perfMemory_posix.cpp @@ -118,7 +118,7 @@ static void save_memory_to_file(char* addr, size_t size) { } } } - FREE_C_HEAP_ARRAY(char, destfile); + FREE_C_HEAP_ARRAY(destfile); } @@ -483,14 +483,14 @@ static char* get_user_name(uid_t uid) { p->pw_name == nullptr ? "pw_name = null" : "pw_name zero length"); } } - FREE_C_HEAP_ARRAY(char, pwbuf); + FREE_C_HEAP_ARRAY(pwbuf); return nullptr; } char* user_name = NEW_C_HEAP_ARRAY(char, strlen(p->pw_name) + 1, mtInternal); strcpy(user_name, p->pw_name); - FREE_C_HEAP_ARRAY(char, pwbuf); + FREE_C_HEAP_ARRAY(pwbuf); return user_name; } @@ -572,7 +572,7 @@ static char* get_user_name_slow(int vmid, int nspid, TRAPS) { DIR* subdirp = open_directory_secure(usrdir_name); if (subdirp == nullptr) { - FREE_C_HEAP_ARRAY(char, usrdir_name); + FREE_C_HEAP_ARRAY(usrdir_name); continue; } @@ -583,7 +583,7 @@ static char* get_user_name_slow(int vmid, int nspid, TRAPS) { // symlink can be exploited. // if (!is_directory_secure(usrdir_name)) { - FREE_C_HEAP_ARRAY(char, usrdir_name); + FREE_C_HEAP_ARRAY(usrdir_name); os::closedir(subdirp); continue; } @@ -607,13 +607,13 @@ static char* get_user_name_slow(int vmid, int nspid, TRAPS) { // don't follow symbolic links for the file RESTARTABLE(::lstat(filename, &statbuf), result); if (result == OS_ERR) { - FREE_C_HEAP_ARRAY(char, filename); + FREE_C_HEAP_ARRAY(filename); continue; } // skip over files that are not regular files. if (!S_ISREG(statbuf.st_mode)) { - FREE_C_HEAP_ARRAY(char, filename); + FREE_C_HEAP_ARRAY(filename); continue; } @@ -623,7 +623,7 @@ static char* get_user_name_slow(int vmid, int nspid, TRAPS) { if (statbuf.st_ctime > oldest_ctime) { char* user = strchr(dentry->d_name, '_') + 1; - FREE_C_HEAP_ARRAY(char, oldest_user); + FREE_C_HEAP_ARRAY(oldest_user); oldest_user = NEW_C_HEAP_ARRAY(char, strlen(user)+1, mtInternal); strcpy(oldest_user, user); @@ -631,11 +631,11 @@ static char* get_user_name_slow(int vmid, int nspid, TRAPS) { } } - FREE_C_HEAP_ARRAY(char, filename); + FREE_C_HEAP_ARRAY(filename); } } os::closedir(subdirp); - FREE_C_HEAP_ARRAY(char, usrdir_name); + FREE_C_HEAP_ARRAY(usrdir_name); } os::closedir(tmpdirp); @@ -1105,11 +1105,11 @@ static char* mmap_create_shared(size_t size) { log_info(perf, memops)("Trying to open %s/%s", dirname, short_filename); fd = create_sharedmem_file(dirname, short_filename, size); - FREE_C_HEAP_ARRAY(char, user_name); - FREE_C_HEAP_ARRAY(char, dirname); + FREE_C_HEAP_ARRAY(user_name); + FREE_C_HEAP_ARRAY(dirname); if (fd == -1) { - FREE_C_HEAP_ARRAY(char, filename); + FREE_C_HEAP_ARRAY(filename); return nullptr; } @@ -1121,7 +1121,7 @@ static char* mmap_create_shared(size_t size) { if (mapAddress == MAP_FAILED) { log_debug(perf)("mmap failed - %s", os::strerror(errno)); remove_file(filename); - FREE_C_HEAP_ARRAY(char, filename); + FREE_C_HEAP_ARRAY(filename); return nullptr; } @@ -1171,7 +1171,7 @@ static void delete_shared_memory(char* addr, size_t size) { remove_file(backing_store_file_name); // Don't.. Free heap memory could deadlock os::abort() if it is called // from signal handler. OS will reclaim the heap memory. - // FREE_C_HEAP_ARRAY(char, backing_store_file_name); + // FREE_C_HEAP_ARRAY(backing_store_file_name); backing_store_file_name = nullptr; } } @@ -1223,8 +1223,8 @@ static void mmap_attach_shared(int vmid, char** addr, size_t* sizep, TRAPS) { // store file, we don't follow them when attaching either. // if (!is_directory_secure(dirname)) { - FREE_C_HEAP_ARRAY(char, dirname); - FREE_C_HEAP_ARRAY(char, luser); + FREE_C_HEAP_ARRAY(dirname); + FREE_C_HEAP_ARRAY(luser); THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(), "Process not found"); } @@ -1236,9 +1236,9 @@ static void mmap_attach_shared(int vmid, char** addr, size_t* sizep, TRAPS) { int fd = open_sharedmem_file(filename, file_flags, THREAD); // free the c heap resources that are no longer needed - FREE_C_HEAP_ARRAY(char, luser); - FREE_C_HEAP_ARRAY(char, dirname); - FREE_C_HEAP_ARRAY(char, filename); + FREE_C_HEAP_ARRAY(luser); + FREE_C_HEAP_ARRAY(dirname); + FREE_C_HEAP_ARRAY(filename); if (HAS_PENDING_EXCEPTION) { assert(fd == OS_ERR, "open_sharedmem_file always return OS_ERR on exceptions"); diff --git a/src/hotspot/os/windows/os_perf_windows.cpp b/src/hotspot/os/windows/os_perf_windows.cpp index 9d04ae65954..59ea83b9148 100644 --- a/src/hotspot/os/windows/os_perf_windows.cpp +++ b/src/hotspot/os/windows/os_perf_windows.cpp @@ -178,9 +178,9 @@ static void destroy(MultiCounterQueryP query) { for (int i = 0; i < query->noOfCounters; ++i) { close_query(nullptr, &query->counters[i]); } - FREE_C_HEAP_ARRAY(char, query->counters); + FREE_C_HEAP_ARRAY(query->counters); close_query(&query->query.pdh_query_handle, nullptr); - FREE_C_HEAP_ARRAY(MultiCounterQueryS, query); + FREE_C_HEAP_ARRAY(query); } } @@ -189,15 +189,15 @@ static void destroy_query_set(MultiCounterQuerySetP query_set) { for (int j = 0; j < query_set->queries[i].noOfCounters; ++j) { close_query(nullptr, &query_set->queries[i].counters[j]); } - FREE_C_HEAP_ARRAY(char, query_set->queries[i].counters); + FREE_C_HEAP_ARRAY(query_set->queries[i].counters); close_query(&query_set->queries[i].query.pdh_query_handle, nullptr); } - FREE_C_HEAP_ARRAY(MultiCounterQueryS, query_set->queries); + FREE_C_HEAP_ARRAY(query_set->queries); } static void destroy(MultiCounterQuerySetP query) { destroy_query_set(query); - FREE_C_HEAP_ARRAY(MultiCounterQuerySetS, query); + FREE_C_HEAP_ARRAY(query); } static void destroy(ProcessQueryP query) { @@ -229,7 +229,7 @@ static void allocate_counters(ProcessQueryP query, size_t nofCounters) { } static void deallocate_counters(MultiCounterQueryP query) { - FREE_C_HEAP_ARRAY(char, query->counters); + FREE_C_HEAP_ARRAY(query->counters); query->counters = nullptr; query->noOfCounters = 0; } @@ -710,11 +710,11 @@ static const char* pdh_process_image_name() { } static void deallocate_pdh_constants() { - FREE_C_HEAP_ARRAY(char, process_image_name); + FREE_C_HEAP_ARRAY(process_image_name); process_image_name = nullptr; - FREE_C_HEAP_ARRAY(char, pdh_process_instance_IDProcess_counter_fmt); + FREE_C_HEAP_ARRAY(pdh_process_instance_IDProcess_counter_fmt); pdh_process_instance_IDProcess_counter_fmt = nullptr; - FREE_C_HEAP_ARRAY(char, pdh_process_instance_wildcard_IDProcess_counter); + FREE_C_HEAP_ARRAY(pdh_process_instance_wildcard_IDProcess_counter); pdh_process_instance_wildcard_IDProcess_counter = nullptr; } @@ -1445,9 +1445,9 @@ bool CPUInformationInterface::initialize() { CPUInformationInterface::~CPUInformationInterface() { if (_cpu_info != nullptr) { - FREE_C_HEAP_ARRAY(char, _cpu_info->cpu_name()); + FREE_C_HEAP_ARRAY(_cpu_info->cpu_name()); _cpu_info->set_cpu_name(nullptr); - FREE_C_HEAP_ARRAY(char, _cpu_info->cpu_description()); + FREE_C_HEAP_ARRAY(_cpu_info->cpu_description()); _cpu_info->set_cpu_description(nullptr); delete _cpu_info; } diff --git a/src/hotspot/os/windows/os_windows.cpp b/src/hotspot/os/windows/os_windows.cpp index 9d8fb45f0d1..9a987bf3762 100644 --- a/src/hotspot/os/windows/os_windows.cpp +++ b/src/hotspot/os/windows/os_windows.cpp @@ -334,14 +334,14 @@ void os::init_system_properties_values() { home_path = NEW_C_HEAP_ARRAY(char, strlen(home_dir) + 1, mtInternal); strcpy(home_path, home_dir); Arguments::set_java_home(home_path); - FREE_C_HEAP_ARRAY(char, home_path); + FREE_C_HEAP_ARRAY(home_path); dll_path = NEW_C_HEAP_ARRAY(char, strlen(home_dir) + strlen(bin) + 1, mtInternal); strcpy(dll_path, home_dir); strcat(dll_path, bin); Arguments::set_dll_dir(dll_path); - FREE_C_HEAP_ARRAY(char, dll_path); + FREE_C_HEAP_ARRAY(dll_path); if (!set_boot_path('\\', ';')) { vm_exit_during_initialization("Failed setting boot class path.", nullptr); @@ -396,7 +396,7 @@ void os::init_system_properties_values() { strcat(library_path, ";."); Arguments::set_library_path(library_path); - FREE_C_HEAP_ARRAY(char, library_path); + FREE_C_HEAP_ARRAY(library_path); } // Default extensions directory @@ -1079,7 +1079,7 @@ void os::set_native_thread_name(const char *name) { HRESULT hr = _SetThreadDescription(current, unicode_name); if (FAILED(hr)) { log_debug(os, thread)("set_native_thread_name: SetThreadDescription failed - falling back to debugger method"); - FREE_C_HEAP_ARRAY(WCHAR, unicode_name); + FREE_C_HEAP_ARRAY(unicode_name); } else { log_trace(os, thread)("set_native_thread_name: SetThreadDescription succeeded - new name: %s", name); @@ -1102,7 +1102,7 @@ void os::set_native_thread_name(const char *name) { LocalFree(thread_name); } #endif - FREE_C_HEAP_ARRAY(WCHAR, unicode_name); + FREE_C_HEAP_ARRAY(unicode_name); return; } } else { @@ -2897,7 +2897,7 @@ class NUMANodeListHolder { int _numa_used_node_count; void free_node_list() { - FREE_C_HEAP_ARRAY(int, _numa_used_node_list); + FREE_C_HEAP_ARRAY(_numa_used_node_list); } public: @@ -4744,7 +4744,7 @@ static wchar_t* wide_abs_unc_path(char const* path, errno_t & err, int additiona LPWSTR unicode_path = nullptr; err = convert_to_unicode(buf, &unicode_path); - FREE_C_HEAP_ARRAY(char, buf); + FREE_C_HEAP_ARRAY(buf); if (err != ERROR_SUCCESS) { return nullptr; } @@ -4772,9 +4772,9 @@ static wchar_t* wide_abs_unc_path(char const* path, errno_t & err, int additiona } if (converted_path != unicode_path) { - FREE_C_HEAP_ARRAY(WCHAR, converted_path); + FREE_C_HEAP_ARRAY(converted_path); } - FREE_C_HEAP_ARRAY(WCHAR, unicode_path); + FREE_C_HEAP_ARRAY(unicode_path); return static_cast(result); // LPWSTR and wchat_t* are the same type on Windows. } @@ -5827,7 +5827,7 @@ int os::fork_and_exec(const char* cmd) { exit_code = -1; } - FREE_C_HEAP_ARRAY(char, cmd_string); + FREE_C_HEAP_ARRAY(cmd_string); return (int)exit_code; } diff --git a/src/hotspot/os/windows/perfMemory_windows.cpp b/src/hotspot/os/windows/perfMemory_windows.cpp index dad2804f18a..8e698c53d28 100644 --- a/src/hotspot/os/windows/perfMemory_windows.cpp +++ b/src/hotspot/os/windows/perfMemory_windows.cpp @@ -113,7 +113,7 @@ static void save_memory_to_file(char* addr, size_t size) { } } - FREE_C_HEAP_ARRAY(char, destfile); + FREE_C_HEAP_ARRAY(destfile); } // Shared Memory Implementation Details @@ -319,7 +319,7 @@ static char* get_user_name_slow(int vmid) { DIR* subdirp = os::opendir(usrdir_name); if (subdirp == nullptr) { - FREE_C_HEAP_ARRAY(char, usrdir_name); + FREE_C_HEAP_ARRAY(usrdir_name); continue; } @@ -330,7 +330,7 @@ static char* get_user_name_slow(int vmid) { // symlink can be exploited. // if (!is_directory_secure(usrdir_name)) { - FREE_C_HEAP_ARRAY(char, usrdir_name); + FREE_C_HEAP_ARRAY(usrdir_name); os::closedir(subdirp); continue; } @@ -350,13 +350,13 @@ static char* get_user_name_slow(int vmid) { strcat(filename, udentry->d_name); if (::stat(filename, &statbuf) == OS_ERR) { - FREE_C_HEAP_ARRAY(char, filename); + FREE_C_HEAP_ARRAY(filename); continue; } // skip over files that are not regular files. if ((statbuf.st_mode & S_IFMT) != S_IFREG) { - FREE_C_HEAP_ARRAY(char, filename); + FREE_C_HEAP_ARRAY(filename); continue; } @@ -378,18 +378,18 @@ static char* get_user_name_slow(int vmid) { if (statbuf.st_ctime > latest_ctime) { char* user = strchr(dentry->d_name, '_') + 1; - FREE_C_HEAP_ARRAY(char, latest_user); + FREE_C_HEAP_ARRAY(latest_user); latest_user = NEW_C_HEAP_ARRAY(char, strlen(user)+1, mtInternal); strcpy(latest_user, user); latest_ctime = statbuf.st_ctime; } - FREE_C_HEAP_ARRAY(char, filename); + FREE_C_HEAP_ARRAY(filename); } } os::closedir(subdirp); - FREE_C_HEAP_ARRAY(char, usrdir_name); + FREE_C_HEAP_ARRAY(usrdir_name); } os::closedir(tmpdirp); @@ -481,7 +481,7 @@ static void remove_file(const char* dirname, const char* filename) { } } - FREE_C_HEAP_ARRAY(char, path); + FREE_C_HEAP_ARRAY(path); } // returns true if the process represented by pid is alive, otherwise @@ -708,11 +708,11 @@ static void free_security_desc(PSECURITY_DESCRIPTOR pSD) { // be an ACL we enlisted. free the resources. // if (success && exists && pACL != nullptr && !isdefault) { - FREE_C_HEAP_ARRAY(char, pACL); + FREE_C_HEAP_ARRAY(pACL); } // free the security descriptor - FREE_C_HEAP_ARRAY(char, pSD); + FREE_C_HEAP_ARRAY(pSD); } } @@ -768,7 +768,7 @@ static PSID get_user_sid(HANDLE hProcess) { if (!GetTokenInformation(hAccessToken, TokenUser, token_buf, rsize, &rsize)) { log_debug(perf)("GetTokenInformation failure: lasterror = %d, rsize = %d", GetLastError(), rsize); - FREE_C_HEAP_ARRAY(char, token_buf); + FREE_C_HEAP_ARRAY(token_buf); CloseHandle(hAccessToken); return nullptr; } @@ -779,15 +779,15 @@ static PSID get_user_sid(HANDLE hProcess) { if (!CopySid(nbytes, pSID, token_buf->User.Sid)) { log_debug(perf)("GetTokenInformation failure: lasterror = %d, rsize = %d", GetLastError(), rsize); - FREE_C_HEAP_ARRAY(char, token_buf); - FREE_C_HEAP_ARRAY(char, pSID); + FREE_C_HEAP_ARRAY(token_buf); + FREE_C_HEAP_ARRAY(pSID); CloseHandle(hAccessToken); return nullptr; } // close the access token. CloseHandle(hAccessToken); - FREE_C_HEAP_ARRAY(char, token_buf); + FREE_C_HEAP_ARRAY(token_buf); return pSID; } @@ -865,7 +865,7 @@ static bool add_allow_aces(PSECURITY_DESCRIPTOR pSD, if (!InitializeAcl(newACL, newACLsize, ACL_REVISION)) { log_debug(perf)("InitializeAcl failure: lasterror = %d", GetLastError()); - FREE_C_HEAP_ARRAY(char, newACL); + FREE_C_HEAP_ARRAY(newACL); return false; } @@ -876,7 +876,7 @@ static bool add_allow_aces(PSECURITY_DESCRIPTOR pSD, LPVOID ace; if (!GetAce(oldACL, ace_index, &ace)) { log_debug(perf)("InitializeAcl failure: lasterror = %d", GetLastError()); - FREE_C_HEAP_ARRAY(char, newACL); + FREE_C_HEAP_ARRAY(newACL); return false; } if (((ACCESS_ALLOWED_ACE *)ace)->Header.AceFlags && INHERITED_ACE) { @@ -901,7 +901,7 @@ static bool add_allow_aces(PSECURITY_DESCRIPTOR pSD, if (!AddAce(newACL, ACL_REVISION, MAXDWORD, ace, ((PACE_HEADER)ace)->AceSize)) { log_debug(perf)("AddAce failure: lasterror = %d", GetLastError()); - FREE_C_HEAP_ARRAY(char, newACL); + FREE_C_HEAP_ARRAY(newACL); return false; } } @@ -915,7 +915,7 @@ static bool add_allow_aces(PSECURITY_DESCRIPTOR pSD, aces[i].mask, aces[i].pSid)) { log_debug(perf)("AddAccessAllowedAce failure: lasterror = %d", GetLastError()); - FREE_C_HEAP_ARRAY(char, newACL); + FREE_C_HEAP_ARRAY(newACL); return false; } } @@ -928,13 +928,13 @@ static bool add_allow_aces(PSECURITY_DESCRIPTOR pSD, LPVOID ace; if (!GetAce(oldACL, ace_index, &ace)) { log_debug(perf)("InitializeAcl failure: lasterror = %d", GetLastError()); - FREE_C_HEAP_ARRAY(char, newACL); + FREE_C_HEAP_ARRAY(newACL); return false; } if (!AddAce(newACL, ACL_REVISION, MAXDWORD, ace, ((PACE_HEADER)ace)->AceSize)) { log_debug(perf)("AddAce failure: lasterror = %d", GetLastError()); - FREE_C_HEAP_ARRAY(char, newACL); + FREE_C_HEAP_ARRAY(newACL); return false; } ace_index++; @@ -944,7 +944,7 @@ static bool add_allow_aces(PSECURITY_DESCRIPTOR pSD, // add the new ACL to the security descriptor. if (!SetSecurityDescriptorDacl(pSD, TRUE, newACL, FALSE)) { log_debug(perf)("SetSecurityDescriptorDacl failure: lasterror = %d", GetLastError()); - FREE_C_HEAP_ARRAY(char, newACL); + FREE_C_HEAP_ARRAY(newACL); return false; } @@ -952,7 +952,7 @@ static bool add_allow_aces(PSECURITY_DESCRIPTOR pSD, // protected prevents that. if (!SetSecurityDescriptorControl(pSD, SE_DACL_PROTECTED, SE_DACL_PROTECTED)) { log_debug(perf)("SetSecurityDescriptorControl failure: lasterror = %d", GetLastError()); - FREE_C_HEAP_ARRAY(char, newACL); + FREE_C_HEAP_ARRAY(newACL); return false; } @@ -1057,7 +1057,7 @@ static LPSECURITY_ATTRIBUTES make_user_everybody_admin_security_attr( // create a security attributes structure with access control // entries as initialized above. LPSECURITY_ATTRIBUTES lpSA = make_security_attr(aces, 3); - FREE_C_HEAP_ARRAY(char, aces[0].pSid); + FREE_C_HEAP_ARRAY(aces[0].pSid); FreeSid(everybodySid); FreeSid(administratorsSid); return(lpSA); @@ -1341,8 +1341,8 @@ static char* mapping_create_shared(size_t size) { // check that the file system is secure - i.e. it supports ACLs. if (!is_filesystem_secure(dirname)) { - FREE_C_HEAP_ARRAY(char, dirname); - FREE_C_HEAP_ARRAY(char, user); + FREE_C_HEAP_ARRAY(dirname); + FREE_C_HEAP_ARRAY(user); return nullptr; } @@ -1358,15 +1358,15 @@ static char* mapping_create_shared(size_t size) { assert(((size != 0) && (size % os::vm_page_size() == 0)), "unexpected PerfMemry region size"); - FREE_C_HEAP_ARRAY(char, user); + FREE_C_HEAP_ARRAY(user); // create the shared memory resources sharedmem_fileMapHandle = create_sharedmem_resources(dirname, filename, objectname, size); - FREE_C_HEAP_ARRAY(char, filename); - FREE_C_HEAP_ARRAY(char, objectname); - FREE_C_HEAP_ARRAY(char, dirname); + FREE_C_HEAP_ARRAY(filename); + FREE_C_HEAP_ARRAY(objectname); + FREE_C_HEAP_ARRAY(dirname); if (sharedmem_fileMapHandle == nullptr) { return nullptr; @@ -1480,8 +1480,8 @@ static void open_file_mapping(int vmid, char** addrp, size_t* sizep, TRAPS) { // store file, we also don't following them when attaching // if (!is_directory_secure(dirname)) { - FREE_C_HEAP_ARRAY(char, dirname); - FREE_C_HEAP_ARRAY(char, luser); + FREE_C_HEAP_ARRAY(dirname); + FREE_C_HEAP_ARRAY(luser); THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(), "Process not found"); } @@ -1498,10 +1498,10 @@ static void open_file_mapping(int vmid, char** addrp, size_t* sizep, TRAPS) { char* robjectname = ResourceArea::strdup(THREAD, objectname); // free the c heap resources that are no longer needed - FREE_C_HEAP_ARRAY(char, luser); - FREE_C_HEAP_ARRAY(char, dirname); - FREE_C_HEAP_ARRAY(char, filename); - FREE_C_HEAP_ARRAY(char, objectname); + FREE_C_HEAP_ARRAY(luser); + FREE_C_HEAP_ARRAY(dirname); + FREE_C_HEAP_ARRAY(filename); + FREE_C_HEAP_ARRAY(objectname); size_t size; if (*sizep == 0) { 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 49d879731ff..6f31bc284e3 100644 --- a/src/hotspot/os_cpu/bsd_aarch64/os_bsd_aarch64.cpp +++ b/src/hotspot/os_cpu/bsd_aarch64/os_bsd_aarch64.cpp @@ -81,10 +81,6 @@ # include #endif -#if !defined(__APPLE__) && !defined(__NetBSD__) -# include -#endif - #define SPELL_REG_SP "sp" #ifdef __APPLE__ @@ -415,49 +411,6 @@ size_t os::Posix::default_stack_size(os::ThreadType thr_type) { size_t s = (thr_type == os::compiler_thread ? 4 * M : 1 * M); return s; } -void os::current_stack_base_and_size(address* base, size_t* size) { - address bottom; -#ifdef __APPLE__ - pthread_t self = pthread_self(); - *base = (address) pthread_get_stackaddr_np(self); - *size = pthread_get_stacksize_np(self); - bottom = *base - *size; -#elif defined(__OpenBSD__) - stack_t ss; - int rslt = pthread_stackseg_np(pthread_self(), &ss); - - if (rslt != 0) - fatal("pthread_stackseg_np failed with error = %d", rslt); - - *base = (address) ss.ss_sp; - *size = ss.ss_size; - bottom = *base - *size; -#else - pthread_attr_t attr; - - int rslt = pthread_attr_init(&attr); - - // JVM needs to know exact stack location, abort if it fails - if (rslt != 0) - fatal("pthread_attr_init failed with error = %d", rslt); - - rslt = pthread_attr_get_np(pthread_self(), &attr); - - if (rslt != 0) - fatal("pthread_attr_get_np failed with error = %d", rslt); - - if (pthread_attr_getstackaddr(&attr, (void **)&bottom) != 0 || - pthread_attr_getstacksize(&attr, size) != 0) { - fatal("Can not locate current stack attributes!"); - } - - *base = bottom + *size; - - pthread_attr_destroy(&attr); -#endif - assert(os::current_stack_pointer() >= bottom && - os::current_stack_pointer() < *base, "just checking"); -} ///////////////////////////////////////////////////////////////////////////// // helper functions for fatal error handler 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 f1c80594eaf..8668f20e371 100644 --- a/src/hotspot/os_cpu/bsd_x86/os_bsd_x86.cpp +++ b/src/hotspot/os_cpu/bsd_x86/os_bsd_x86.cpp @@ -55,6 +55,7 @@ // put OS-includes here # include # include +# include # include # include # include @@ -73,19 +74,6 @@ # include #endif -#if !defined(__APPLE__) && !defined(__NetBSD__) -# include -#endif - -// needed by current_stack_base_and_size() workaround for Mavericks -#if defined(__APPLE__) -# include -# include -# include -# define DEFAULT_MAIN_THREAD_STACK_PAGES 2048 -# define OS_X_10_9_0_KERNEL_MAJOR_VERSION 13 -#endif - #define SPELL_REG_SP "rsp" #define SPELL_REG_FP "rbp" #define REG_BCP context_r13 @@ -499,104 +487,6 @@ size_t os::Posix::default_stack_size(os::ThreadType thr_type) { } -// Java thread: -// -// Low memory addresses -// +------------------------+ -// | |\ Java thread created by VM does not have glibc -// | glibc guard page | - guard, attached Java thread usually has -// | |/ 1 glibc guard page. -// P1 +------------------------+ Thread::stack_base() - Thread::stack_size() -// | |\ -// | HotSpot Guard Pages | - red, yellow and reserved pages -// | |/ -// +------------------------+ StackOverflow::stack_reserved_zone_base() -// | |\ -// | Normal Stack | - -// | |/ -// P2 +------------------------+ Thread::stack_base() -// -// Non-Java thread: -// -// Low memory addresses -// +------------------------+ -// | |\ -// | glibc guard page | - usually 1 page -// | |/ -// P1 +------------------------+ Thread::stack_base() - Thread::stack_size() -// | |\ -// | Normal Stack | - -// | |/ -// P2 +------------------------+ Thread::stack_base() -// -// ** P1 (aka bottom) and size are the address and stack size -// returned from pthread_attr_getstack(). -// ** P2 (aka stack top or base) = P1 + size - -void os::current_stack_base_and_size(address* base, size_t* size) { - address bottom; -#ifdef __APPLE__ - pthread_t self = pthread_self(); - *base = (address) pthread_get_stackaddr_np(self); - *size = pthread_get_stacksize_np(self); - // workaround for OS X 10.9.0 (Mavericks) - // pthread_get_stacksize_np returns 128 pages even though the actual size is 2048 pages - if (pthread_main_np() == 1) { - // At least on Mac OS 10.12 we have observed stack sizes not aligned - // to pages boundaries. This can be provoked by e.g. setrlimit() (ulimit -s xxxx in the - // shell). Apparently Mac OS actually rounds upwards to next multiple of page size, - // however, we round downwards here to be on the safe side. - *size = align_down(*size, getpagesize()); - - if ((*size) < (DEFAULT_MAIN_THREAD_STACK_PAGES * (size_t)getpagesize())) { - char kern_osrelease[256]; - size_t kern_osrelease_size = sizeof(kern_osrelease); - int ret = sysctlbyname("kern.osrelease", kern_osrelease, &kern_osrelease_size, nullptr, 0); - if (ret == 0) { - // get the major number, atoi will ignore the minor amd micro portions of the version string - if (atoi(kern_osrelease) >= OS_X_10_9_0_KERNEL_MAJOR_VERSION) { - *size = (DEFAULT_MAIN_THREAD_STACK_PAGES*getpagesize()); - } - } - } - } - bottom = *base - *size; -#elif defined(__OpenBSD__) - stack_t ss; - int rslt = pthread_stackseg_np(pthread_self(), &ss); - - if (rslt != 0) - fatal("pthread_stackseg_np failed with error = %d", rslt); - - *base = (address) ss.ss_sp; - *size = ss.ss_size; - bottom = *base - *size; -#else - pthread_attr_t attr; - - int rslt = pthread_attr_init(&attr); - - // JVM needs to know exact stack location, abort if it fails - if (rslt != 0) - fatal("pthread_attr_init failed with error = %d", rslt); - - rslt = pthread_attr_get_np(pthread_self(), &attr); - - if (rslt != 0) - fatal("pthread_attr_get_np failed with error = %d", rslt); - - if (pthread_attr_getstackaddr(&attr, (void **)&bottom) != 0 || - pthread_attr_getstacksize(&attr, size) != 0) { - fatal("Can not locate current stack attributes!"); - } - - *base = bottom + *size; - - pthread_attr_destroy(&attr); -#endif - assert(os::current_stack_pointer() >= bottom && - os::current_stack_pointer() < *base, "just checking"); -} ///////////////////////////////////////////////////////////////////////////// // helper functions for fatal error handler diff --git a/src/hotspot/os_cpu/bsd_zero/os_bsd_zero.cpp b/src/hotspot/os_cpu/bsd_zero/os_bsd_zero.cpp index facad184426..a089d5981ca 100644 --- a/src/hotspot/os_cpu/bsd_zero/os_bsd_zero.cpp +++ b/src/hotspot/os_cpu/bsd_zero/os_bsd_zero.cpp @@ -52,7 +52,6 @@ #if !defined(__APPLE__) && !defined(__NetBSD__) #include -# include /* For pthread_attr_get_np */ #endif address os::current_stack_pointer() { @@ -179,52 +178,6 @@ size_t os::Posix::default_stack_size(os::ThreadType thr_type) { return s; } -void os::current_stack_base_and_size(address* base, size_t* size) { - address bottom; - -#ifdef __APPLE__ - pthread_t self = pthread_self(); - *base = (address) pthread_get_stackaddr_np(self); - *size = pthread_get_stacksize_np(self); - bottom = *base - *size; -#elif defined(__OpenBSD__) - stack_t ss; - int rslt = pthread_stackseg_np(pthread_self(), &ss); - - if (rslt != 0) - fatal("pthread_stackseg_np failed with error = %d", rslt); - - *base = (address) ss.ss_sp; - *size = ss.ss_size; - bottom = *base - *size; -#else - pthread_attr_t attr; - - int rslt = pthread_attr_init(&attr); - - // JVM needs to know exact stack location, abort if it fails - if (rslt != 0) - fatal("pthread_attr_init failed with error = %d", rslt); - - rslt = pthread_attr_get_np(pthread_self(), &attr); - - if (rslt != 0) - fatal("pthread_attr_get_np failed with error = %d", rslt); - - if (pthread_attr_getstackaddr(&attr, (void **) &bottom) != 0 || - pthread_attr_getstacksize(&attr, size) != 0) { - fatal("Can not locate current stack attributes!"); - } - - *base = bottom + *size; - - pthread_attr_destroy(&attr); - -#endif - assert(os::current_stack_pointer() >= bottom && - os::current_stack_pointer() < *base, "just checking"); -} - ///////////////////////////////////////////////////////////////////////////// // helper functions for fatal error handler diff --git a/src/hotspot/os_cpu/windows_aarch64/sve_windows_aarch64.S b/src/hotspot/os_cpu/windows_aarch64/sve_windows_aarch64.S index e0c85830bd4..137cd0f7753 100644 --- a/src/hotspot/os_cpu/windows_aarch64/sve_windows_aarch64.S +++ b/src/hotspot/os_cpu/windows_aarch64/sve_windows_aarch64.S @@ -24,19 +24,26 @@ ; Support for int get_sve_vector_length(); ; ; Returns the current SVE vector length in bytes. - ; This function uses the INCB instruction which increments a register - ; by the number of bytes in an SVE vector register. + ; This function uses the RDVL instruction which reads a multiple of the + ; vector register size into a scalar register. ; - ; Note: This function will fault if SVE is not available or enabled. - ; The caller must ensure SVE support is detected before calling. + ; Note: This function will fault if SVE is not available or enabled. The + ; caller must ensure SVE support is detected before calling. ALIGN 4 EXPORT get_sve_vector_length AREA sve_text, CODE get_sve_vector_length - mov x0, #0 - incb x0 + ; Older versions of Visual Studio aren't aware of SVE mnemonics, so we use + ; the raw instruction encoding to satisfy the compiler. This function call + ; is gated by `VM_Version::supports_sve()`, so this instruction will never + ; run on non-SVE hardware. + ; + ; See https://www.scs.stanford.edu/~zyedidia/arm64/rdvl_r_i.html for a quick + ; reference to the instruction encoding. + + DCD 0x04BF5020 ; rdvl x0, #1 (i.e. x0 = 1 * vector_length_in_bytes) ret END diff --git a/src/hotspot/os_cpu/windows_aarch64/vm_version_windows_aarch64.cpp b/src/hotspot/os_cpu/windows_aarch64/vm_version_windows_aarch64.cpp index e78a37b4178..e485ae6b8c2 100644 --- a/src/hotspot/os_cpu/windows_aarch64/vm_version_windows_aarch64.cpp +++ b/src/hotspot/os_cpu/windows_aarch64/vm_version_windows_aarch64.cpp @@ -26,19 +26,52 @@ #include "runtime/os.hpp" #include "runtime/vm_version.hpp" -// Assembly function to get SVE vector length using INCB instruction +// Since PF_ARM_SVE_INSTRUCTIONS_AVAILABLE and related constants were added in +// Windows 11 (version 24H2) and in Windows Server 2025, we define them here for +// compatibility with older SDK versions. +#ifndef PF_ARM_SVE_INSTRUCTIONS_AVAILABLE +#define PF_ARM_SVE_INSTRUCTIONS_AVAILABLE 46 +#endif + +#ifndef PF_ARM_SVE2_INSTRUCTIONS_AVAILABLE +#define PF_ARM_SVE2_INSTRUCTIONS_AVAILABLE 47 +#endif + +#ifndef PF_ARM_SVE_BITPERM_INSTRUCTIONS_AVAILABLE +#define PF_ARM_SVE_BITPERM_INSTRUCTIONS_AVAILABLE 51 +#endif + +#ifndef PF_ARM_SHA3_INSTRUCTIONS_AVAILABLE +#define PF_ARM_SHA3_INSTRUCTIONS_AVAILABLE 64 +#endif + +#ifndef PF_ARM_SHA512_INSTRUCTIONS_AVAILABLE +#define PF_ARM_SHA512_INSTRUCTIONS_AVAILABLE 65 +#endif + +#ifndef PF_ARM_V82_FP16_INSTRUCTIONS_AVAILABLE +#define PF_ARM_V82_FP16_INSTRUCTIONS_AVAILABLE 67 +#endif + +// Assembly function to get SVE vector length using RDVL instruction extern "C" int get_sve_vector_length(); int VM_Version::get_current_sve_vector_length() { assert(VM_Version::supports_sve(), "should not call this"); - // Use assembly instruction to get the actual SVE vector length - return VM_Version::supports_sve() ? get_sve_vector_length() : 0; // This value is in bytes + return VM_Version::supports_sve() ? get_sve_vector_length() : 0; } int VM_Version::set_and_get_current_sve_vector_length(int length) { assert(VM_Version::supports_sve(), "should not call this"); - // Use assembly instruction to get the SVE vector length - return VM_Version::supports_sve() ? get_sve_vector_length() : 0; // This value is in bytes + + // Unlike Linux, Windows does not present a way to modify the VL (the + // rationale is that the OS expects the application to use the maximum vector + // length supported by the hardware), so we simply return the current VL. If + // the user sets `MaxVectorSize` that is not the same as the maximum possible + // vector length, then the caller (`VM_Version::initialize()`) will print a + // warning, set `MaxVectorSize` to the value returned by this function, and + // move on. + return VM_Version::supports_sve() ? get_sve_vector_length() : 0; } void VM_Version::get_os_cpu_info() { @@ -67,6 +100,10 @@ void VM_Version::get_os_cpu_info() { if (IsProcessorFeaturePresent(PF_ARM_SVE_BITPERM_INSTRUCTIONS_AVAILABLE)) { set_feature(CPU_SVEBITPERM); } + if (IsProcessorFeaturePresent(PF_ARM_V82_FP16_INSTRUCTIONS_AVAILABLE)) { + set_feature(CPU_FPHP); + set_feature(CPU_ASIMDHP); + } if (IsProcessorFeaturePresent(PF_ARM_SHA3_INSTRUCTIONS_AVAILABLE)) { set_feature(CPU_SHA3); } diff --git a/src/hotspot/share/asm/codeBuffer.cpp b/src/hotspot/share/asm/codeBuffer.cpp index 854cf73049b..c6475050592 100644 --- a/src/hotspot/share/asm/codeBuffer.cpp +++ b/src/hotspot/share/asm/codeBuffer.cpp @@ -417,7 +417,7 @@ void CodeSection::expand_locs(int new_capacity) { new_capacity = old_capacity * 2; relocInfo* locs_start; if (_locs_own) { - locs_start = REALLOC_RESOURCE_ARRAY(relocInfo, _locs_start, old_capacity, new_capacity); + locs_start = REALLOC_RESOURCE_ARRAY(_locs_start, old_capacity, new_capacity); } else { locs_start = NEW_RESOURCE_ARRAY(relocInfo, new_capacity); Copy::conjoint_jbytes(_locs_start, locs_start, old_capacity * sizeof(relocInfo)); diff --git a/src/hotspot/share/c1/c1_LIRGenerator.hpp b/src/hotspot/share/c1/c1_LIRGenerator.hpp index ec0ea5dc047..8e30d05af6d 100644 --- a/src/hotspot/share/c1/c1_LIRGenerator.hpp +++ b/src/hotspot/share/c1/c1_LIRGenerator.hpp @@ -330,8 +330,9 @@ class LIRGenerator: public InstructionVisitor, public BlockClosure { // volatile field operations are never patchable because a klass // must be loaded to know it's volatile which means that the offset - // it always known as well. + // is always known as well. void volatile_field_store(LIR_Opr value, LIR_Address* address, CodeEmitInfo* info); + // volatile_field_load provides trailing membar semantics void volatile_field_load(LIR_Address* address, LIR_Opr result, CodeEmitInfo* info); void put_Object_unsafe(LIR_Opr src, LIR_Opr offset, LIR_Opr data, BasicType type, bool is_volatile); diff --git a/src/hotspot/share/cds/aotMetaspace.hpp b/src/hotspot/share/cds/aotMetaspace.hpp index 4607a936abe..2236bae91f3 100644 --- a/src/hotspot/share/cds/aotMetaspace.hpp +++ b/src/hotspot/share/cds/aotMetaspace.hpp @@ -105,7 +105,9 @@ public: // Return true if given address is in the shared metaspace regions (i.e., excluding the // mapped heap region.) static bool in_aot_cache(const void* p) { - return MetaspaceObj::in_aot_cache((const MetaspaceObj*)p); + // This function is called only after the AOT metaspace is initialized, so + // we can skip init checks. + return MetaspaceObj::is_pointer_in_aot_cache_no_init_check(p); } static void set_aot_metaspace_range(void* base, void *static_top, void* top) NOT_CDS_RETURN; diff --git a/src/hotspot/share/cds/aotStreamedHeapLoader.cpp b/src/hotspot/share/cds/aotStreamedHeapLoader.cpp index 39f735543cd..7f9f8cf0628 100644 --- a/src/hotspot/share/cds/aotStreamedHeapLoader.cpp +++ b/src/hotspot/share/cds/aotStreamedHeapLoader.cpp @@ -797,7 +797,7 @@ void AOTStreamedHeapLoader::cleanup() { Universe::vm_global()->release(&handles[num_null_handles], num_handles - num_null_handles); } - FREE_C_HEAP_ARRAY(void*, _object_index_to_heap_object_table); + FREE_C_HEAP_ARRAY(_object_index_to_heap_object_table); // Unmap regions FileMapInfo::current_info()->unmap_region(AOTMetaspace::hp); diff --git a/src/hotspot/share/cds/archiveBuilder.cpp b/src/hotspot/share/cds/archiveBuilder.cpp index 21eef3d7b0b..cf51897c2f1 100644 --- a/src/hotspot/share/cds/archiveBuilder.cpp +++ b/src/hotspot/share/cds/archiveBuilder.cpp @@ -1171,7 +1171,7 @@ void ArchiveBuilder::write_archive(FileMapInfo* mapinfo, AOTMappedHeapInfo* mapp AOTMapLogger::dumptime_log(this, mapinfo, mapped_heap_info, streamed_heap_info, bitmap, bitmap_size_in_bytes); } CDS_JAVA_HEAP_ONLY(HeapShared::destroy_archived_object_cache()); - FREE_C_HEAP_ARRAY(char, bitmap); + FREE_C_HEAP_ARRAY(bitmap); } void ArchiveBuilder::write_region(FileMapInfo* mapinfo, int region_idx, DumpRegion* dump_region, bool read_only, bool allow_exec) { diff --git a/src/hotspot/share/cds/cdsConfig.cpp b/src/hotspot/share/cds/cdsConfig.cpp index ecf3c6d2231..21066f76932 100644 --- a/src/hotspot/share/cds/cdsConfig.cpp +++ b/src/hotspot/share/cds/cdsConfig.cpp @@ -520,7 +520,7 @@ static void substitute_aot_filename(JVMFlagsEnum flag_enum) { JVMFlag::Error err = JVMFlagAccess::set_ccstr(flag, &new_filename, JVMFlagOrigin::ERGONOMIC); assert(err == JVMFlag::SUCCESS, "must never fail"); } - FREE_C_HEAP_ARRAY(char, new_filename); + FREE_C_HEAP_ARRAY(new_filename); } void CDSConfig::check_aotmode_record() { diff --git a/src/hotspot/share/cds/cds_globals.hpp b/src/hotspot/share/cds/cds_globals.hpp index 447914b3101..7df498ca5b9 100644 --- a/src/hotspot/share/cds/cds_globals.hpp +++ b/src/hotspot/share/cds/cds_globals.hpp @@ -163,7 +163,7 @@ \ product(uint, AOTCodeMaxSize, 10*M, DIAGNOSTIC, \ "Buffer size in bytes for AOT code caching") \ - range(1*M, max_jint) \ + range(1*M, CODE_CACHE_SIZE_LIMIT) \ \ product(bool, AbortVMOnAOTCodeFailure, false, DIAGNOSTIC, \ "Abort VM on the first occurrence of AOT code load or store " \ diff --git a/src/hotspot/share/cds/classListWriter.cpp b/src/hotspot/share/cds/classListWriter.cpp index 8e1f298e8e3..c90e233df73 100644 --- a/src/hotspot/share/cds/classListWriter.cpp +++ b/src/hotspot/share/cds/classListWriter.cpp @@ -49,7 +49,7 @@ void ClassListWriter::init() { _classlist_file->print_cr("# This file is generated via the -XX:DumpLoadedClassList= option"); _classlist_file->print_cr("# and is used at CDS archive dump time (see -Xshare:dump)."); _classlist_file->print_cr("#"); - FREE_C_HEAP_ARRAY(char, list_name); + FREE_C_HEAP_ARRAY(list_name); } } diff --git a/src/hotspot/share/cds/filemap.cpp b/src/hotspot/share/cds/filemap.cpp index 38502b2b2d8..1ed9979ff85 100644 --- a/src/hotspot/share/cds/filemap.cpp +++ b/src/hotspot/share/cds/filemap.cpp @@ -402,7 +402,7 @@ public: ~FileHeaderHelper() { if (_header != nullptr) { - FREE_C_HEAP_ARRAY(char, _header); + FREE_C_HEAP_ARRAY(_header); } if (_fd != -1) { ::close(_fd); @@ -1362,6 +1362,13 @@ bool FileMapInfo::map_aot_code_region(ReservedSpace rs) { return false; } else { assert(mapped_base == requested_base, "must be"); + + if (VerifySharedSpaces && !r->check_region_crc(mapped_base)) { + aot_log_error(aot)("region %d CRC error", AOTMetaspace::ac); + os::unmap_memory(mapped_base, r->used_aligned()); + return false; + } + r->set_mapped_from_file(true); r->set_mapped_base(mapped_base); aot_log_info(aot)("Mapped static region #%d at base " INTPTR_FORMAT " top " INTPTR_FORMAT " (%s)", @@ -1464,14 +1471,14 @@ size_t FileMapInfo::read_bytes(void* buffer, size_t count) { return count; } -// Get the total size in bytes of a read only region +// Get the total size in bytes of all mapped read only region size_t FileMapInfo::readonly_total() { size_t total = 0; - if (current_info() != nullptr) { + if (current_info() != nullptr && current_info()->is_mapped()) { FileMapRegion* r = FileMapInfo::current_info()->region_at(AOTMetaspace::ro); if (r->read_only()) total += r->used(); } - if (dynamic_info() != nullptr) { + if (dynamic_info() != nullptr && current_info()->is_mapped()) { FileMapRegion* r = FileMapInfo::dynamic_info()->region_at(AOTMetaspace::ro); if (r->read_only()) total += r->used(); } diff --git a/src/hotspot/share/ci/ciReplay.cpp b/src/hotspot/share/ci/ciReplay.cpp index 6266c024260..35522e75877 100644 --- a/src/hotspot/share/ci/ciReplay.cpp +++ b/src/hotspot/share/ci/ciReplay.cpp @@ -600,7 +600,7 @@ class CompileReplay : public StackObj { _nesting.check(); // Check if a reallocation in the resource arena is safe int new_length = _buffer_length * 2; // Next call will throw error in case of OOM. - _buffer = REALLOC_RESOURCE_ARRAY(char, _buffer, _buffer_length, new_length); + _buffer = REALLOC_RESOURCE_ARRAY(_buffer, _buffer_length, new_length); _buffer_length = new_length; } if (c == '\n') { diff --git a/src/hotspot/share/classfile/classFileParser.cpp b/src/hotspot/share/classfile/classFileParser.cpp index a9ea6fbea11..d5ee16fec32 100644 --- a/src/hotspot/share/classfile/classFileParser.cpp +++ b/src/hotspot/share/classfile/classFileParser.cpp @@ -2363,8 +2363,8 @@ Method* ClassFileParser::parse_method(const ClassFileStream* const cfs, } if (lvt_cnt == max_lvt_cnt) { max_lvt_cnt <<= 1; - localvariable_table_length = REALLOC_RESOURCE_ARRAY(u2, localvariable_table_length, lvt_cnt, max_lvt_cnt); - localvariable_table_start = REALLOC_RESOURCE_ARRAY(const unsafe_u2*, localvariable_table_start, lvt_cnt, max_lvt_cnt); + localvariable_table_length = REALLOC_RESOURCE_ARRAY(localvariable_table_length, lvt_cnt, max_lvt_cnt); + localvariable_table_start = REALLOC_RESOURCE_ARRAY(localvariable_table_start, lvt_cnt, max_lvt_cnt); } localvariable_table_start[lvt_cnt] = parse_localvariable_table(cfs, @@ -2393,8 +2393,8 @@ Method* ClassFileParser::parse_method(const ClassFileStream* const cfs, // Parse local variable type table if (lvtt_cnt == max_lvtt_cnt) { max_lvtt_cnt <<= 1; - localvariable_type_table_length = REALLOC_RESOURCE_ARRAY(u2, localvariable_type_table_length, lvtt_cnt, max_lvtt_cnt); - localvariable_type_table_start = REALLOC_RESOURCE_ARRAY(const unsafe_u2*, localvariable_type_table_start, lvtt_cnt, max_lvtt_cnt); + localvariable_type_table_length = REALLOC_RESOURCE_ARRAY(localvariable_type_table_length, lvtt_cnt, max_lvtt_cnt); + localvariable_type_table_start = REALLOC_RESOURCE_ARRAY(localvariable_type_table_start, lvtt_cnt, max_lvtt_cnt); } localvariable_type_table_start[lvtt_cnt] = parse_localvariable_table(cfs, diff --git a/src/hotspot/share/classfile/classLoader.cpp b/src/hotspot/share/classfile/classLoader.cpp index eced83577cb..6d25e460688 100644 --- a/src/hotspot/share/classfile/classLoader.cpp +++ b/src/hotspot/share/classfile/classLoader.cpp @@ -251,7 +251,7 @@ const char* ClassPathEntry::copy_path(const char* path) { } ClassPathDirEntry::~ClassPathDirEntry() { - FREE_C_HEAP_ARRAY(char, _dir); + FREE_C_HEAP_ARRAY(_dir); } ClassFileStream* ClassPathDirEntry::open_stream(JavaThread* current, const char* name) { @@ -280,7 +280,7 @@ ClassFileStream* ClassPathDirEntry::open_stream(JavaThread* current, const char* #ifdef ASSERT // Freeing path is a no-op here as buffer prevents it from being reclaimed. But we keep it for // debug builds so that we guard against use-after-free bugs. - FREE_RESOURCE_ARRAY_IN_THREAD(current, char, path, path_len); + FREE_RESOURCE_ARRAY_IN_THREAD(current, path, path_len); #endif // We don't verify the length of the classfile stream fits in an int, but this is the // bootloader so we have control of this. @@ -291,7 +291,7 @@ ClassFileStream* ClassPathDirEntry::open_stream(JavaThread* current, const char* } } } - FREE_RESOURCE_ARRAY_IN_THREAD(current, char, path, path_len); + FREE_RESOURCE_ARRAY_IN_THREAD(current, path, path_len); return nullptr; } @@ -302,7 +302,7 @@ ClassPathZipEntry::ClassPathZipEntry(jzfile* zip, const char* zip_name) : ClassP ClassPathZipEntry::~ClassPathZipEntry() { ZipLibrary::close(_zip); - FREE_C_HEAP_ARRAY(char, _zip_name); + FREE_C_HEAP_ARRAY(_zip_name); } bool ClassPathZipEntry::has_entry(JavaThread* current, const char* name) { @@ -707,6 +707,7 @@ ClassPathEntry* ClassLoader::create_class_path_entry(JavaThread* current, if (zip != nullptr && error_msg == nullptr) { new_entry = new ClassPathZipEntry(zip, path); } else { + log_info(class, path)("failed: %s, err: %s", path, error_msg); return nullptr; } log_info(class, path)("opened: %s", path); @@ -1438,7 +1439,7 @@ bool ClassLoader::is_module_observable(const char* module_name) { struct stat st; const char *path = get_exploded_module_path(module_name, true); bool res = os::stat(path, &st) == 0; - FREE_C_HEAP_ARRAY(char, path); + FREE_C_HEAP_ARRAY(path); return res; } jlong size; diff --git a/src/hotspot/share/classfile/compactHashtable.cpp b/src/hotspot/share/classfile/compactHashtable.cpp index de67971c403..f06f1986d8b 100644 --- a/src/hotspot/share/classfile/compactHashtable.cpp +++ b/src/hotspot/share/classfile/compactHashtable.cpp @@ -69,7 +69,7 @@ CompactHashtableWriter::~CompactHashtableWriter() { delete bucket; } - FREE_C_HEAP_ARRAY(GrowableArray*, _buckets); + FREE_C_HEAP_ARRAY(_buckets); } // Add an entry to the temporary hash table diff --git a/src/hotspot/share/classfile/resolutionErrors.cpp b/src/hotspot/share/classfile/resolutionErrors.cpp index c41d5d2f052..958d4812cbb 100644 --- a/src/hotspot/share/classfile/resolutionErrors.cpp +++ b/src/hotspot/share/classfile/resolutionErrors.cpp @@ -114,15 +114,15 @@ ResolutionErrorEntry::~ResolutionErrorEntry() { Symbol::maybe_decrement_refcount(_cause); if (_message != nullptr) { - FREE_C_HEAP_ARRAY(char, _message); + FREE_C_HEAP_ARRAY(_message); } if (_cause_msg != nullptr) { - FREE_C_HEAP_ARRAY(char, _cause_msg); + FREE_C_HEAP_ARRAY(_cause_msg); } if (nest_host_error() != nullptr) { - FREE_C_HEAP_ARRAY(char, nest_host_error()); + FREE_C_HEAP_ARRAY(nest_host_error()); } } diff --git a/src/hotspot/share/classfile/systemDictionaryShared.cpp b/src/hotspot/share/classfile/systemDictionaryShared.cpp index fd30fc6766f..330b8e81d7f 100644 --- a/src/hotspot/share/classfile/systemDictionaryShared.cpp +++ b/src/hotspot/share/classfile/systemDictionaryShared.cpp @@ -1277,7 +1277,7 @@ unsigned int SystemDictionaryShared::hash_for_shared_dictionary(address ptr) { uintx offset = ArchiveBuilder::current()->any_to_offset(ptr); unsigned int hash = primitive_hash(offset); DEBUG_ONLY({ - if (MetaspaceObj::in_aot_cache((const MetaspaceObj*)ptr)) { + if (AOTMetaspace::in_aot_cache(ptr)) { assert(hash == SystemDictionaryShared::hash_for_shared_dictionary_quick(ptr), "must be"); } }); diff --git a/src/hotspot/share/classfile/systemDictionaryShared.hpp b/src/hotspot/share/classfile/systemDictionaryShared.hpp index c837a386344..740c7370d28 100644 --- a/src/hotspot/share/classfile/systemDictionaryShared.hpp +++ b/src/hotspot/share/classfile/systemDictionaryShared.hpp @@ -25,6 +25,7 @@ #ifndef SHARE_CLASSFILE_SYSTEMDICTIONARYSHARED_HPP #define SHARE_CLASSFILE_SYSTEMDICTIONARYSHARED_HPP +#include "cds/aotMetaspace.hpp" #include "cds/cds_globals.hpp" #include "cds/dumpTimeClassInfo.hpp" #include "cds/filemap.hpp" @@ -312,7 +313,7 @@ public: template static unsigned int hash_for_shared_dictionary_quick(T* ptr) { - assert(MetaspaceObj::in_aot_cache((const MetaspaceObj*)ptr), "must be"); + assert(AOTMetaspace::in_aot_cache(ptr), "must be"); assert(ptr > (T*)SharedBaseAddress, "must be"); uintx offset = uintx(ptr) - uintx(SharedBaseAddress); return primitive_hash(offset); diff --git a/src/hotspot/share/code/aotCodeCache.cpp b/src/hotspot/share/code/aotCodeCache.cpp index d4f12936e96..1ef1142d5e7 100644 --- a/src/hotspot/share/code/aotCodeCache.cpp +++ b/src/hotspot/share/code/aotCodeCache.cpp @@ -83,15 +83,24 @@ const char* aot_code_entry_kind_name[] = { static LogStream& load_failure_log() { static LogStream err_stream(LogLevel::Error, LogTagSetMapping::tagset()); static LogStream dbg_stream(LogLevel::Debug, LogTagSetMapping::tagset()); - if (RequireSharedSpaces) { + if (RequireSharedSpaces || AbortVMOnAOTCodeFailure) { return err_stream; } else { return dbg_stream; } } +// Report AOT code cache failure and exit VM +// if (AOTMode is `on` and AbortVMOnAOTCodeFailure is default) +// or AbortVMOnAOTCodeFailure is `true`. +// +// Note, specifying -XX:-AbortVMOnAOTCodeFailure on command line +// will prevent aborting VM when AOTMode is `on`. It is used for testing. + static void report_load_failure() { - if (AbortVMOnAOTCodeFailure) { + bool abort_vm = AbortVMOnAOTCodeFailure || + (FLAG_IS_DEFAULT(AbortVMOnAOTCodeFailure) && RequireSharedSpaces); + if (abort_vm) { vm_exit_during_initialization("Unable to use AOT Code Cache.", nullptr); } load_failure_log().print_cr("Unable to use AOT Code Cache."); @@ -482,25 +491,25 @@ bool AOTCodeCache::Config::verify_cpu_features(AOTCodeCache* cache) const { log.print_cr("CPU features recorded in AOTCodeCache: %s", ss.as_string()); } - if (VM_Version::supports_features(cached_cpu_features_buffer)) { - if (log.is_enabled()) { - ResourceMark rm; // required for stringStream::as_string() - stringStream ss; - char* runtime_cpu_features = NEW_RESOURCE_ARRAY(char, VM_Version::cpu_features_size()); - VM_Version::store_cpu_features(runtime_cpu_features); - VM_Version::get_missing_features_name(runtime_cpu_features, cached_cpu_features_buffer, ss); - if (!ss.is_empty()) { - log.print_cr("Additional runtime CPU features: %s", ss.as_string()); - } - } - } else { + if (!VM_Version::verify_aot_code_cache_features(cached_cpu_features_buffer)) { if (load_failure_log().is_enabled()) { ResourceMark rm; // required for stringStream::as_string() - stringStream ss; + load_failure_log().print_cr("AOT Code Cache disabled: cpu features are incompatible"); char* runtime_cpu_features = NEW_RESOURCE_ARRAY(char, VM_Version::cpu_features_size()); VM_Version::store_cpu_features(runtime_cpu_features); - VM_Version::get_missing_features_name(cached_cpu_features_buffer, runtime_cpu_features, ss); - load_failure_log().print_cr("AOT Code Cache disabled: required cpu features are missing: %s", ss.as_string()); + + stringStream missing_features; + VM_Version::get_missing_features_name(cached_cpu_features_buffer, runtime_cpu_features, missing_features); + if (!missing_features.is_empty()) { + load_failure_log().print_cr("cpu features that are required: \"%s\"", missing_features.as_string()); + } + + stringStream additional_features; + VM_Version::get_missing_features_name(runtime_cpu_features, cached_cpu_features_buffer, additional_features); + if (!additional_features.is_empty()) { + load_failure_log().print("cpu features that are additional: \"%s\"", additional_features.as_string()); + } + load_failure_log().print_cr(""); } return false; } @@ -652,6 +661,10 @@ void AOTCodeReader::set_read_position(uint pos) { _read_position = pos; } +uint AOTCodeReader::align_read_int() { + return align_up(_read_position, sizeof(int)); +} + bool AOTCodeCache::set_write_position(uint pos) { if (pos == _write_position) { return true; @@ -666,21 +679,29 @@ bool AOTCodeCache::set_write_position(uint pos) { static char align_buffer[256] = { 0 }; -bool AOTCodeCache::align_write() { - // We are not executing code from cache - we copy it by bytes first. - // No need for big alignment (or at all). - uint padding = DATA_ALIGNMENT - (_write_position & (DATA_ALIGNMENT - 1)); - if (padding == DATA_ALIGNMENT) { +bool AOTCodeCache::align_write_bytes(uint alignment) { + uint padding = alignment - (_write_position & (alignment - 1)); + if (padding == alignment) { return true; } uint n = write_bytes((const void*)&align_buffer, padding); if (n != padding) { return false; } - log_trace(aot, codecache)("Adjust write alignment in AOT Code Cache"); + log_trace(aot, codecache)("Adjust write alignment to %d bytes in AOT Code Cache", alignment); return true; } +bool AOTCodeCache::align_write() { + // We are not executing code from cache - we copy it by bytes first. + // No need for big alignment (or at all). + return align_write_bytes(DATA_ALIGNMENT); +} + +bool AOTCodeCache::align_write_int() { + return align_write_bytes(sizeof(int)); +} + // Check to see if AOT code cache has required space to store "nbytes" of data address AOTCodeCache::reserve_bytes(uint nbytes) { assert(for_dump(), "Code Cache file is not created"); @@ -876,7 +897,7 @@ bool AOTCodeCache::finish_write() { current += size; uint n = write_bytes(&(entries_address[i]), sizeof(AOTCodeEntry)); if (n != sizeof(AOTCodeEntry)) { - FREE_C_HEAP_ARRAY(uint, search); + FREE_C_HEAP_ARRAY(search); return false; } search[entries_count*2 + 0] = entries_address[i].id(); @@ -897,7 +918,7 @@ bool AOTCodeCache::finish_write() { } if (entries_count == 0) { log_info(aot, codecache, exit)("AOT Code Cache was not created: no entires"); - FREE_C_HEAP_ARRAY(uint, search); + FREE_C_HEAP_ARRAY(search); return true; // Nothing to write } assert(entries_count <= store_count, "%d > %d", entries_count, store_count); @@ -913,7 +934,7 @@ bool AOTCodeCache::finish_write() { qsort(search, entries_count, 2*sizeof(uint), uint_cmp); search_size = 2 * entries_count * sizeof(uint); copy_bytes((const char*)search, (address)current, search_size); - FREE_C_HEAP_ARRAY(uint, search); + FREE_C_HEAP_ARRAY(search); current += search_size; // Write entries @@ -1012,19 +1033,8 @@ bool AOTCodeCache::store_code_blob(CodeBlob& blob, AOTCodeEntry::Kind entry_kind } uint entry_position = cache->_write_position; - // Write name - uint name_offset = cache->_write_position - entry_position; - uint name_size = (uint)strlen(name) + 1; // Includes '/0' - uint n = cache->write_bytes(name, name_size); - if (n != name_size) { - return false; - } - - // Write CodeBlob - if (!cache->align_write()) { - return false; - } uint blob_offset = cache->_write_position - entry_position; + // Code blob's size is aligned to oopSize address archive_buffer = cache->reserve_bytes(blob.size()); if (archive_buffer == nullptr) { return false; @@ -1056,7 +1066,7 @@ bool AOTCodeCache::store_code_blob(CodeBlob& blob, AOTCodeEntry::Kind entry_kind reloc_count = blob.relocation_size() / sizeof(relocInfo); reloc_data = (address)blob.relocation_begin(); } - n = cache->write_bytes(&reloc_count, sizeof(int)); + uint n = cache->write_bytes(&reloc_count, sizeof(int)); if (n != sizeof(int)) { return false; } @@ -1123,6 +1133,14 @@ bool AOTCodeCache::store_code_blob(CodeBlob& blob, AOTCodeEntry::Kind entry_kind } #endif /* PRODUCT */ + // Write name after code comments + uint name_offset = cache->_write_position - entry_position; + uint name_size = (uint)strlen(name) + 1; // Includes '/0' + n = cache->write_bytes(name, name_size); + if (n != name_size) { + return false; + } + uint entry_size = cache->_write_position - entry_position; AOTCodeEntry* entry = new(cache) AOTCodeEntry(entry_kind, encode_id(entry_kind, id), @@ -1151,6 +1169,9 @@ bool AOTCodeCache::store_code_blob(CodeBlob& blob, AOTCodeEntry::Kind entry_kind } bool AOTCodeCache::write_stub_data(CodeBlob &blob, AOTStubData *stub_data) { + if (!align_write_int()) { + return false; + } BlobId blob_id = stub_data->blob_id(); StubId stub_id = StubInfo::stub_base(blob_id); address blob_base = blob.code_begin(); @@ -1320,7 +1341,8 @@ CodeBlob* AOTCodeReader::compile_code_blob(const char* name, AOTCodeEntry::Kind CodeBlob* archived_blob = (CodeBlob*)addr(offset); offset += archived_blob->size(); - _reloc_count = *(int*)addr(offset); offset += sizeof(int); + _reloc_count = *(int*)addr(offset); + offset += sizeof(int); if (AOTCodeEntry::is_multi_stub_blob(entry_kind)) { // position of relocs will have been aligned to heap word size so // we can install them into a code buffer @@ -1443,7 +1465,7 @@ void AOTCodeReader::read_stub_data(CodeBlob* code_blob, AOTStubData* stub_data) address blob_base = code_blob->code_begin(); uint blob_size = (uint)(code_blob->code_end() - blob_base); - int offset = read_position(); + uint offset = align_read_int(); LogStreamHandle(Trace, aot, codecache, stubs) log; if (log.is_enabled()) { log.print_cr("======== Stub data starts at offset %d", offset); @@ -1571,6 +1593,9 @@ void AOTCodeCache::publish_stub_addresses(CodeBlob &code_blob, BlobId blob_id, A #define BAD_ADDRESS_ID -2 bool AOTCodeCache::write_relocations(CodeBlob& code_blob, RelocIterator& iter) { + if (!align_write_int()) { + return false; + } GrowableArray reloc_data; LogStreamHandle(Trace, aot, codecache, reloc) log; while (iter.next()) { @@ -1653,7 +1678,7 @@ bool AOTCodeCache::write_relocations(CodeBlob& code_blob, RelocIterator& iter) { } void AOTCodeReader::fix_relocations(CodeBlob *code_blob, RelocIterator& iter) { - uint offset = read_position(); + uint offset = align_read_int(); int reloc_count = *(int*)addr(offset); offset += sizeof(int); uint* reloc_data = (uint*)addr(offset); @@ -1726,6 +1751,9 @@ void AOTCodeReader::fix_relocations(CodeBlob *code_blob, RelocIterator& iter) { } bool AOTCodeCache::write_oop_map_set(CodeBlob& cb) { + if (!align_write_int()) { + return false; + } ImmutableOopMapSet* oopmaps = cb.oop_maps(); int oopmaps_size = oopmaps->nr_of_bytes(); if (!write_bytes(&oopmaps_size, sizeof(int))) { @@ -1739,7 +1767,7 @@ bool AOTCodeCache::write_oop_map_set(CodeBlob& cb) { } ImmutableOopMapSet* AOTCodeReader::read_oop_map_set() { - uint offset = read_position(); + uint offset = align_read_int(); int size = *(int *)addr(offset); offset += sizeof(int); ImmutableOopMapSet* oopmaps = (ImmutableOopMapSet *)addr(offset); @@ -1750,6 +1778,9 @@ ImmutableOopMapSet* AOTCodeReader::read_oop_map_set() { #ifndef PRODUCT bool AOTCodeCache::write_asm_remarks(CodeBlob& cb) { + if (!align_write_int()) { + return false; + } // Write asm remarks uint* count_ptr = (uint *)reserve_bytes(sizeof(uint)); if (count_ptr == nullptr) { @@ -1778,7 +1809,7 @@ bool AOTCodeCache::write_asm_remarks(CodeBlob& cb) { void AOTCodeReader::read_asm_remarks(AsmRemarks& asm_remarks) { // Read asm remarks - uint offset = read_position(); + uint offset = align_read_int(); uint count = *(uint *)addr(offset); offset += sizeof(uint); for (uint i = 0; i < count; i++) { @@ -1793,6 +1824,9 @@ void AOTCodeReader::read_asm_remarks(AsmRemarks& asm_remarks) { } bool AOTCodeCache::write_dbg_strings(CodeBlob& cb) { + if (!align_write_int()) { + return false; + } // Write dbg strings uint* count_ptr = (uint *)reserve_bytes(sizeof(uint)); if (count_ptr == nullptr) { @@ -1817,7 +1851,7 @@ bool AOTCodeCache::write_dbg_strings(CodeBlob& cb) { void AOTCodeReader::read_dbg_strings(DbgStrings& dbg_strings) { // Read dbg strings - uint offset = read_position(); + uint offset = align_read_int(); uint count = *(uint *)addr(offset); offset += sizeof(uint); for (uint i = 0; i < count; i++) { diff --git a/src/hotspot/share/code/aotCodeCache.hpp b/src/hotspot/share/code/aotCodeCache.hpp index 5b773a986f1..296464533f0 100644 --- a/src/hotspot/share/code/aotCodeCache.hpp +++ b/src/hotspot/share/code/aotCodeCache.hpp @@ -252,7 +252,7 @@ private: public: AOTStubData(BlobId blob_id) NOT_CDS({}); - ~AOTStubData() CDS_ONLY({FREE_C_HEAP_ARRAY(StubAddrRange, _ranges);}) NOT_CDS({}) + ~AOTStubData() CDS_ONLY({FREE_C_HEAP_ARRAY(_ranges);}) NOT_CDS({}) bool is_open() CDS_ONLY({ return (_flags & OPEN) != 0; }) NOT_CDS_RETURN_(false); bool is_using() CDS_ONLY({ return (_flags & USING) != 0; }) NOT_CDS_RETURN_(false); @@ -478,6 +478,8 @@ private: bool set_write_position(uint pos); bool align_write(); + bool align_write_int(); + bool align_write_bytes(uint alignment); address reserve_bytes(uint nbytes); uint write_bytes(const void* buffer, uint nbytes); const char* addr(uint offset) const { return _load_buffer + offset; } @@ -643,6 +645,7 @@ private: uint _read_position; // Position in _load_buffer uint read_position() const { return _read_position; } void set_read_position(uint pos); + uint align_read_int(); const char* addr(uint offset) const { return _load_buffer + offset; } bool _lookup_failed; // Failed to lookup for info (skip only this code load) diff --git a/src/hotspot/share/code/codeBlob.cpp b/src/hotspot/share/code/codeBlob.cpp index e0c286937d0..d69ae40be19 100644 --- a/src/hotspot/share/code/codeBlob.cpp +++ b/src/hotspot/share/code/codeBlob.cpp @@ -357,9 +357,12 @@ void RuntimeBlob::trace_new_stub(RuntimeBlob* stub, const char* name1, const cha if (stub != nullptr && (PrintStubCode || Forte::is_enabled() || JvmtiExport::should_post_dynamic_code_generated())) { - char stub_id[256]; - assert(strlen(name1) + strlen(name2) < sizeof(stub_id), ""); - jio_snprintf(stub_id, sizeof(stub_id), "%s%s", name1, name2); + ResourceMark rm; + const size_t name1_len = strlen(name1); + const size_t name2_len = strlen(name2); + const size_t stub_id_size = name1_len + name2_len + 1; + char* stub_id = NEW_RESOURCE_ARRAY(char, stub_id_size); + jio_snprintf(stub_id, stub_id_size, "%s%s", name1, name2); if (PrintStubCode) { ttyLocker ttyl; tty->print_cr("- - - [BEGIN] - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -"); diff --git a/src/hotspot/share/code/codeCache.cpp b/src/hotspot/share/code/codeCache.cpp index c0b4918102e..2aaa061dca3 100644 --- a/src/hotspot/share/code/codeCache.cpp +++ b/src/hotspot/share/code/codeCache.cpp @@ -1715,7 +1715,7 @@ void CodeCache::print_internals() { } } - FREE_C_HEAP_ARRAY(int, buckets); + FREE_C_HEAP_ARRAY(buckets); print_memory_overhead(); } @@ -1838,11 +1838,15 @@ void CodeCache::print() { } void CodeCache::print_summary(outputStream* st, bool detailed) { + int total_blob_count = 0; + int total_nmethod_count = 0; + int total_adapter_count = 0; int full_count = 0; julong total_used = 0; julong total_max_used = 0; julong total_free = 0; julong total_size = 0; + FOR_ALL_HEAPS(heap_iterator) { CodeHeap* heap = (*heap_iterator); size_t total = (heap->high_boundary() - heap->low_boundary()); @@ -1868,8 +1872,13 @@ void CodeCache::print_summary(outputStream* st, bool detailed) { p2i(heap->low_boundary()), p2i(heap->high()), p2i(heap->high_boundary())); - - full_count += get_codemem_full_count(heap->code_blob_type()); + st->print_cr(" blobs=" UINT32_FORMAT ", nmethods=" UINT32_FORMAT + ", adapters=" UINT32_FORMAT ", full_count=" UINT32_FORMAT, + heap->blob_count(), heap->nmethod_count(), heap->adapter_count(), heap->full_count()); + total_blob_count += heap->blob_count(); + total_nmethod_count += heap->nmethod_count(); + total_adapter_count += heap->adapter_count(); + full_count += heap->full_count(); } } @@ -1879,10 +1888,10 @@ void CodeCache::print_summary(outputStream* st, bool detailed) { st->print_cr(" size=" JULONG_FORMAT "Kb, used=" JULONG_FORMAT "Kb, max_used=" JULONG_FORMAT "Kb, free=" JULONG_FORMAT "Kb", total_size, total_used, total_max_used, total_free); + st->print_cr(" total blobs=" UINT32_FORMAT ", nmethods=" UINT32_FORMAT + ", adapters=" UINT32_FORMAT ", full_count=" UINT32_FORMAT, + total_blob_count, total_nmethod_count, total_adapter_count, full_count); } - st->print_cr(" total_blobs=" UINT32_FORMAT ", nmethods=" UINT32_FORMAT - ", adapters=" UINT32_FORMAT ", full_count=" UINT32_FORMAT, - blob_count(), nmethod_count(), adapter_count(), full_count); st->print_cr("Compilation: %s, stopped_count=%d, restarted_count=%d", CompileBroker::should_compile_new_jobs() ? "enabled" : Arguments::mode() == Arguments::_int ? diff --git a/src/hotspot/share/code/exceptionHandlerTable.cpp b/src/hotspot/share/code/exceptionHandlerTable.cpp index a295d1271aa..f0ad9921cd0 100644 --- a/src/hotspot/share/code/exceptionHandlerTable.cpp +++ b/src/hotspot/share/code/exceptionHandlerTable.cpp @@ -32,7 +32,7 @@ void ExceptionHandlerTable::add_entry(HandlerTableEntry entry) { // not enough space => grow the table (amortized growth, double its size) guarantee(_size > 0, "no space allocated => cannot grow the table since it is part of nmethod"); int new_size = _size * 2; - _table = REALLOC_RESOURCE_ARRAY(HandlerTableEntry, _table, _size, new_size); + _table = REALLOC_RESOURCE_ARRAY(_table, _size, new_size); _size = new_size; } assert(_length < _size, "sanity check"); @@ -178,7 +178,7 @@ void ImplicitExceptionTable::append( uint exec_off, uint cont_off ) { if (_size == 0) _size = 4; _size *= 2; uint new_size_in_elements = _size*2; - _data = REALLOC_RESOURCE_ARRAY(uint, _data, old_size_in_elements, new_size_in_elements); + _data = REALLOC_RESOURCE_ARRAY(_data, old_size_in_elements, new_size_in_elements); } *(adr(l) ) = exec_off; *(adr(l)+1) = cont_off; diff --git a/src/hotspot/share/compiler/cHeapStringHolder.cpp b/src/hotspot/share/compiler/cHeapStringHolder.cpp index 261658e04eb..5a9c124688e 100644 --- a/src/hotspot/share/compiler/cHeapStringHolder.cpp +++ b/src/hotspot/share/compiler/cHeapStringHolder.cpp @@ -36,7 +36,7 @@ void CHeapStringHolder::set(const char* string) { void CHeapStringHolder::clear() { if (_string != nullptr) { - FREE_C_HEAP_ARRAY(char, _string); + FREE_C_HEAP_ARRAY(_string); _string = nullptr; } } diff --git a/src/hotspot/share/compiler/compilationMemoryStatistic.cpp b/src/hotspot/share/compiler/compilationMemoryStatistic.cpp index 1951fd066fc..82bd4c160d2 100644 --- a/src/hotspot/share/compiler/compilationMemoryStatistic.cpp +++ b/src/hotspot/share/compiler/compilationMemoryStatistic.cpp @@ -487,7 +487,7 @@ public: void clean_details() { if (_detail_stats != nullptr) { - FREE_C_HEAP_ARRAY(Details, _detail_stats); + FREE_C_HEAP_ARRAY(_detail_stats); _detail_stats = nullptr; } } diff --git a/src/hotspot/share/compiler/compileBroker.cpp b/src/hotspot/share/compiler/compileBroker.cpp index 7b236ed3589..2e7a50f7846 100644 --- a/src/hotspot/share/compiler/compileBroker.cpp +++ b/src/hotspot/share/compiler/compileBroker.cpp @@ -345,6 +345,8 @@ void CompileQueue::add(CompileTask* task) { // Mark the method as being in the compile queue. task->method()->set_queued_for_compilation(); + task->mark_queued(os::elapsed_counter()); + if (CIPrintCompileQueue) { print_tty(); } @@ -2363,11 +2365,10 @@ void CompileBroker::invoke_compiler_on_method(CompileTask* task) { if (!ci_env.failing() && !task->is_success()) { - assert(ci_env.failure_reason() != nullptr, "expect failure reason"); - assert(false, "compiler should always document failure: %s", ci_env.failure_reason()); - // The compiler elected, without comment, not to register a result. + const char* reason = task->failure_reason(); + assert(reason != nullptr, "compiler should always document failure"); // Do not attempt further compilations of this method. - ci_env.record_method_not_compilable("compile failed"); + ci_env.record_method_not_compilable(reason != nullptr ? reason : "compile failed: reason unknown"); } // Copy this bit to the enclosing block: @@ -2402,7 +2403,7 @@ void CompileBroker::invoke_compiler_on_method(CompileTask* task) { } } - DirectivesStack::release(directive); + task->mark_finished(os::elapsed_counter()); methodHandle method(thread, task->method()); @@ -2410,15 +2411,11 @@ void CompileBroker::invoke_compiler_on_method(CompileTask* task) { collect_statistics(thread, time, task); - if (PrintCompilation && PrintCompilation2) { - tty->print("%7d ", (int) tty->time_stamp().milliseconds()); // print timestamp - tty->print("%4d ", compile_id); // print compilation number - tty->print("%s ", (is_osr ? "%" : " ")); - if (task->is_success()) { - tty->print("size: %d(%d) ", task->nm_total_size(), task->nm_insts_size()); - } - tty->print_cr("time: %d inlined: %d bytes", (int)time.milliseconds(), task->num_inlined_bytecodes()); + if (PrintCompilation2 || directive->PrintCompilation2Option) { + ResourceMark rm; + task->print_post(tty); } + DirectivesStack::release(directive); Log(compilation, codecache) log; if (log.is_debug()) { @@ -2614,7 +2611,7 @@ void CompileBroker::collect_statistics(CompilerThread* thread, elapsedTimer time } // Collect statistic per compiler - AbstractCompiler* comp = compiler(comp_level); + AbstractCompiler* comp = task->compiler(); if (comp) { CompilerStatistics* stats = comp->stats(); if (is_osr) { diff --git a/src/hotspot/share/compiler/compileLog.cpp b/src/hotspot/share/compiler/compileLog.cpp index d0ea80d6019..d0833fbe7fa 100644 --- a/src/hotspot/share/compiler/compileLog.cpp +++ b/src/hotspot/share/compiler/compileLog.cpp @@ -64,8 +64,8 @@ CompileLog::~CompileLog() { _out = nullptr; // Remove partial file after merging in CompileLog::finish_log_on_error unlink(_file); - FREE_C_HEAP_ARRAY(char, _identities); - FREE_C_HEAP_ARRAY(char, _file); + FREE_C_HEAP_ARRAY(_identities); + FREE_C_HEAP_ARRAY(_file); } @@ -96,7 +96,7 @@ int CompileLog::identify(ciBaseObject* obj) { if (id >= _identities_capacity) { int new_cap = _identities_capacity * 2; if (new_cap <= id) new_cap = id + 100; - _identities = REALLOC_C_HEAP_ARRAY(char, _identities, new_cap, mtCompiler); + _identities = REALLOC_C_HEAP_ARRAY(_identities, new_cap, mtCompiler); _identities_capacity = new_cap; } while (id >= _identities_limit) { diff --git a/src/hotspot/share/compiler/compileTask.cpp b/src/hotspot/share/compiler/compileTask.cpp index 536d81045d7..5b01105c707 100644 --- a/src/hotspot/share/compiler/compileTask.cpp +++ b/src/hotspot/share/compiler/compileTask.cpp @@ -51,8 +51,6 @@ CompileTask::CompileTask(int compile_id, _method_holder = JNIHandles::make_weak_global(Handle(thread, method->method_holder()->klass_holder())); _osr_bci = osr_bci; _is_blocking = is_blocking; - JVMCI_ONLY(_has_waiter = CompileBroker::compiler(comp_level)->is_jvmci();) - JVMCI_ONLY(_blocking_jvmci_compile_state = nullptr;) _comp_level = comp_level; _num_inlined_bytecodes = 0; @@ -60,17 +58,24 @@ CompileTask::CompileTask(int compile_id, _is_success = false; _hot_count = hot_count; - _time_queued = os::elapsed_counter(); + _time_created = os::elapsed_counter(); + _time_queued = 0; _time_started = 0; + _time_finished = 0; _compile_reason = compile_reason; _nm_content_size = 0; - AbstractCompiler* comp = compiler(); - _directive = DirectivesStack::getMatchingDirective(method, comp); _nm_insts_size = 0; _nm_total_size = 0; _failure_reason = nullptr; _failure_reason_on_C_heap = false; _training_data = nullptr; + + AbstractCompiler* comp = CompileBroker::compiler(comp_level); + _compiler = comp; + _directive = DirectivesStack::getMatchingDirective(method, comp); + + JVMCI_ONLY(_has_waiter = comp->is_jvmci();) + JVMCI_ONLY(_blocking_jvmci_compile_state = nullptr;) _arena_bytes = 0; _next = nullptr; @@ -108,7 +113,8 @@ void CompileTask::wait_for_no_active_tasks() { * Returns the compiler for this task. */ AbstractCompiler* CompileTask::compiler() const { - return CompileBroker::compiler(_comp_level); + assert(_compiler != nullptr, "should be set"); + return _compiler; } // Replace weak handles by strong handles to avoid unloading during compilation. @@ -157,7 +163,7 @@ void CompileTask::metadata_do(MetadataClosure* f) { // void CompileTask::print_line_on_error(outputStream* st, char* buf, int buflen) { // print compiler name - st->print("%s:", CompileBroker::compiler_name(comp_level())); + st->print("%s:", compiler()->name()); print(st); } @@ -168,29 +174,71 @@ void CompileTask::print_tty() { print(tty); } +void CompileTask::print_post(outputStream* st) { + bool is_osr_method = osr_bci() != InvocationEntryBci; + print_impl(st, is_unloaded() ? nullptr : method(), compile_id(), comp_level(), + is_osr_method, osr_bci(), is_blocking(), + compiler()->name(), nullptr, false /* short_form */, true /* cr */, + true /* after_compile_details */, + _num_inlined_bytecodes, _nm_total_size, _nm_insts_size, + _time_created, _time_queued, _time_started, _time_finished); +} + // ------------------------------------------------------------------ // CompileTask::print_impl void CompileTask::print_impl(outputStream* st, Method* method, int compile_id, int comp_level, bool is_osr_method, int osr_bci, bool is_blocking, - const char* msg, bool short_form, bool cr, - jlong time_queued, jlong time_started) { - if (!short_form) { + const char* compiler_name, + const char* msg, bool short_form, bool cr, bool after_compile_details, + int inlined_bytecodes, int nm_total_size, int nm_insts_size, + jlong time_created, jlong time_queued, jlong time_started, jlong time_finished) { + // Use stringStream to avoid breaking the line + stringStream sst; + if (after_compile_details) { + { // Print current time + stringStream ss; + ss.print(UINT64_FORMAT, (uint64_t) tty->time_stamp().milliseconds()); + sst.print("%7s ", ss.freeze()); + } + { // Time waiting to be put on queue + stringStream ss; + if (time_created != 0 && time_queued != 0) { + ss.print("W%.1f", TimeHelper::counter_to_millis(time_queued - time_created)); + } + sst.print("%7s ", ss.freeze()); + } + { // Time in queue + stringStream ss; + if (time_queued != 0 && time_started != 0) { + ss.print("Q%.1f", TimeHelper::counter_to_millis(time_started - time_queued)); + } + sst.print("%7s ", ss.freeze()); + } + { // Time in compilation + stringStream ss; + if (time_started != 0 && time_finished != 0) { + ss.print("C%.1f", TimeHelper::counter_to_millis(time_finished - time_started)); + } + sst.print("%7s ", ss.freeze()); + } + } else if (!short_form) { // Print current time - st->print(UINT64_FORMAT " ", (uint64_t) tty->time_stamp().milliseconds()); + sst.print(UINT64_FORMAT " ", (uint64_t) tty->time_stamp().milliseconds()); if (Verbose && time_queued != 0) { // Print time in queue and time being processed by compiler thread jlong now = os::elapsed_counter(); - st->print("%.0f ", TimeHelper::counter_to_millis(now-time_queued)); + sst.print("%.0f ", TimeHelper::counter_to_millis(now-time_queued)); if (time_started != 0) { - st->print("%.0f ", TimeHelper::counter_to_millis(now-time_started)); + sst.print("%.0f ", TimeHelper::counter_to_millis(now-time_started)); } } } + // print compiler name if requested if (CIPrintCompilerName) { - st->print("%s:", CompileBroker::compiler_name(comp_level)); + sst.print("%s:", compiler_name); } - st->print("%4d ", compile_id); // print compilation number + sst.print("%4d ", compile_id); // print compilation number bool is_synchronized = false; bool has_exception_handler = false; @@ -208,40 +256,52 @@ void CompileTask::print_impl(outputStream* st, Method* method, int compile_id, i const char native_char = is_native ? 'n' : ' '; // print method attributes - st->print("%c%c%c%c%c ", compile_type, sync_char, exception_char, blocking_char, native_char); + sst.print("%c%c%c%c%c ", compile_type, sync_char, exception_char, blocking_char, native_char); if (TieredCompilation) { - if (comp_level != -1) st->print("%d ", comp_level); - else st->print("- "); + if (comp_level != -1) sst.print("%d ", comp_level); + else sst.print("- "); } - st->print(" "); // more indent + sst.print(" "); // more indent if (method == nullptr) { - st->print("(method)"); + sst.print("(method)"); } else { - method->print_short_name(st); - if (is_osr_method) { - st->print(" @ %d", osr_bci); + if (after_compile_details) { + sst.print("%s", method->name_and_sig_as_C_string(true /* use_double_colon */)); + } else { + method->print_short_name(&sst); } - if (method->is_native()) - st->print(" (native)"); - else - st->print(" (%d bytes)", method->code_size()); + if (is_osr_method) { + sst.print(" @ %d", osr_bci); + } + if (method->is_native()) { + sst.print(" (native)"); + } else { + sst.print(" (%d bytes)", method->code_size()); + } + } + if (after_compile_details) { + sst.print(" (inlined %d)", inlined_bytecodes); + sst.print(" (size %d/%d)", nm_total_size, nm_insts_size); } if (msg != nullptr) { - st->print(" %s", msg); + sst.print(" %s", msg); } if (cr) { - st->cr(); + sst.cr(); } + st->print("%s",sst.freeze()); } // ------------------------------------------------------------------ // CompileTask::print_compilation void CompileTask::print(outputStream* st, const char* msg, bool short_form, bool cr) { bool is_osr_method = osr_bci() != InvocationEntryBci; - print_impl(st, is_unloaded() ? nullptr : method(), compile_id(), comp_level(), is_osr_method, osr_bci(), is_blocking(), msg, short_form, cr, _time_queued, _time_started); + print_impl(st, is_unloaded() ? nullptr : method(), compile_id(), comp_level(), + is_osr_method, osr_bci(), is_blocking(), + compiler()->name(), msg, short_form, cr); } // ------------------------------------------------------------------ @@ -435,6 +495,7 @@ void CompileTask::print_ul(const nmethod* nm, const char* msg) { nm->comp_level(), nm->is_osr_method(), nm->is_osr_method() ? nm->osr_entry_bci() : -1, /*is_blocking*/ false, + nm->compiler_name(), msg, /* short form */ true, /* cr */ true); } } diff --git a/src/hotspot/share/compiler/compileTask.hpp b/src/hotspot/share/compiler/compileTask.hpp index 2cc5e9afe3c..3e25c34c829 100644 --- a/src/hotspot/share/compiler/compileTask.hpp +++ b/src/hotspot/share/compiler/compileTask.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -93,7 +93,8 @@ class CompileTask : public CHeapObj { CodeSection::csize_t _nm_content_size; CodeSection::csize_t _nm_total_size; CodeSection::csize_t _nm_insts_size; - DirectiveSet* _directive; + DirectiveSet* _directive; + AbstractCompiler* _compiler; #if INCLUDE_JVMCI bool _has_waiter; // Compilation state for a blocking JVMCI compilation @@ -104,8 +105,10 @@ class CompileTask : public CHeapObj { CompileTask* _next; CompileTask* _prev; // Fields used for logging why the compilation was initiated: + jlong _time_created; // time when task was created jlong _time_queued; // time when task was enqueued jlong _time_started; // time when compilation started + jlong _time_finished; // time when compilation finished int _hot_count; // information about its invocation counter CompileReason _compile_reason; // more info about the task const char* _failure_reason; @@ -118,6 +121,7 @@ class CompileTask : public CHeapObj { CompileTask(int compile_id, const methodHandle& method, int osr_bci, int comp_level, int hot_count, CompileReason compile_reason, bool is_blocking); ~CompileTask(); + static void wait_for_no_active_tasks(); int compile_id() const { return _compile_id; } @@ -127,6 +131,7 @@ class CompileTask : public CHeapObj { bool is_blocking() const { return _is_blocking; } bool is_success() const { return _is_success; } DirectiveSet* directive() const { return _directive; } + CompileReason compile_reason() const { return _compile_reason; } CodeSection::csize_t nm_content_size() { return _nm_content_size; } void set_nm_content_size(CodeSection::csize_t size) { _nm_content_size = size; } CodeSection::csize_t nm_insts_size() { return _nm_insts_size; } @@ -166,8 +171,9 @@ class CompileTask : public CHeapObj { void mark_complete() { _is_complete = true; } void mark_success() { _is_success = true; } + void mark_queued(jlong time) { _time_queued = time; } void mark_started(jlong time) { _time_started = time; } - + void mark_finished(jlong time) { _time_finished = time; } int comp_level() { return _comp_level;} void set_comp_level(int comp_level) { _comp_level = comp_level;} @@ -198,16 +204,20 @@ class CompileTask : public CHeapObj { private: static void print_impl(outputStream* st, Method* method, int compile_id, int comp_level, bool is_osr_method = false, int osr_bci = -1, bool is_blocking = false, + const char* compiler_name = nullptr, const char* msg = nullptr, bool short_form = false, bool cr = true, - jlong time_queued = 0, jlong time_started = 0); + bool after_compile_details = false, + int inlined_bytecodes = 0, int nm_total_size = 0, int nm_insts_size = 0, + jlong time_created = 0, jlong time_queued = 0, + jlong time_started = 0, jlong time_finished = 0); public: void print(outputStream* st = tty, const char* msg = nullptr, bool short_form = false, bool cr = true); void print_ul(const char* msg = nullptr); static void print(outputStream* st, const nmethod* nm, const char* msg = nullptr, bool short_form = false, bool cr = true) { print_impl(st, nm->method(), nm->compile_id(), nm->comp_level(), - nm->is_osr_method(), nm->is_osr_method() ? nm->osr_entry_bci() : -1, /*is_blocking*/ false, - msg, short_form, cr); + nm->is_osr_method(), nm->is_osr_method() ? nm->osr_entry_bci() : -1, /*is_blocking*/ false, + nm->compiler_name(), msg, short_form, cr); } static void print_ul(const nmethod* nm, const char* msg = nullptr); @@ -217,6 +227,7 @@ public: static void print_inline_indent(int inline_level, outputStream* st = tty); void print_tty(); + void print_post(outputStream* st); void print_line_on_error(outputStream* st, char* buf, int buflen); void log_task(xmlStream* log); @@ -224,6 +235,7 @@ public: void log_task_start(CompileLog* log); void log_task_done(CompileLog* log); + const char* failure_reason() const { return _failure_reason; } void set_failure_reason(const char* reason, bool on_C_heap = false) { _failure_reason = reason; _failure_reason_on_C_heap = on_C_heap; diff --git a/src/hotspot/share/compiler/compilerDirectives.cpp b/src/hotspot/share/compiler/compilerDirectives.cpp index 1cd8bd1b510..d0042d0e16c 100644 --- a/src/hotspot/share/compiler/compilerDirectives.cpp +++ b/src/hotspot/share/compiler/compilerDirectives.cpp @@ -256,7 +256,7 @@ ControlIntrinsicIter::ControlIntrinsicIter(ccstrlist option_value, bool disable_ } ControlIntrinsicIter::~ControlIntrinsicIter() { - FREE_C_HEAP_ARRAY(char, _list); + FREE_C_HEAP_ARRAY(_list); } // pre-increment diff --git a/src/hotspot/share/compiler/compilerDirectives.hpp b/src/hotspot/share/compiler/compilerDirectives.hpp index e4826b3056c..d9b229353ec 100644 --- a/src/hotspot/share/compiler/compilerDirectives.hpp +++ b/src/hotspot/share/compiler/compilerDirectives.hpp @@ -44,6 +44,7 @@ cflags(MemStat, uintx, 0, MemStat) \ cflags(PrintAssembly, bool, PrintAssembly, PrintAssembly) \ cflags(PrintCompilation, bool, PrintCompilation, PrintCompilation) \ + cflags(PrintCompilation2, bool, PrintCompilation2, PrintCompilation2) \ cflags(PrintInlining, bool, PrintInlining, PrintInlining) \ cflags(PrintNMethods, bool, PrintNMethods, PrintNMethods) \ cflags(BackgroundCompilation, bool, BackgroundCompilation, BackgroundCompilation) \ @@ -283,7 +284,7 @@ class ControlIntrinsicValidator { ~ControlIntrinsicValidator() { if (_bad != nullptr) { - FREE_C_HEAP_ARRAY(char, _bad); + FREE_C_HEAP_ARRAY(_bad); } } diff --git a/src/hotspot/share/compiler/compilerOracle.hpp b/src/hotspot/share/compiler/compilerOracle.hpp index 665f3b2fbfd..5615a2cf1fc 100644 --- a/src/hotspot/share/compiler/compilerOracle.hpp +++ b/src/hotspot/share/compiler/compilerOracle.hpp @@ -63,6 +63,7 @@ class methodHandle; option(MemStat, "MemStat", Uintx) \ option(PrintAssembly, "PrintAssembly", Bool) \ option(PrintCompilation, "PrintCompilation", Bool) \ + option(PrintCompilation2, "PrintCompilation2", Bool) \ option(PrintInlining, "PrintInlining", Bool) \ option(PrintIntrinsics, "PrintIntrinsics", Bool) \ option(PrintNMethods, "PrintNMethods", Bool) \ diff --git a/src/hotspot/share/compiler/directivesParser.cpp b/src/hotspot/share/compiler/directivesParser.cpp index a2da7c7e0e4..53a8325702e 100644 --- a/src/hotspot/share/compiler/directivesParser.cpp +++ b/src/hotspot/share/compiler/directivesParser.cpp @@ -198,7 +198,7 @@ bool DirectivesParser::push_key(const char* str, size_t len) { strncpy(s, str, len); s[len] = '\0'; error(KEY_ERROR, "No such key: '%s'.", s); - FREE_C_HEAP_ARRAY(char, s); + FREE_C_HEAP_ARRAY(s); return false; } @@ -370,7 +370,7 @@ bool DirectivesParser::set_option_flag(JSON_TYPE t, JSON_VAL* v, const key* opti #endif if (!valid) { - FREE_C_HEAP_ARRAY(char, s); + FREE_C_HEAP_ARRAY(s); return false; } (set->*test)((void *)&s); // Takes ownership. @@ -440,7 +440,7 @@ bool DirectivesParser::set_option(JSON_TYPE t, JSON_VAL* v) { assert (error_msg != nullptr, "Must have valid error message"); error(VALUE_ERROR, "Method pattern error: %s", error_msg); } - FREE_C_HEAP_ARRAY(char, s); + FREE_C_HEAP_ARRAY(s); } break; @@ -472,7 +472,7 @@ bool DirectivesParser::set_option(JSON_TYPE t, JSON_VAL* v) { error(VALUE_ERROR, "Method pattern error: %s", error_msg); } } - FREE_C_HEAP_ARRAY(char, s); + FREE_C_HEAP_ARRAY(s); } break; @@ -622,4 +622,3 @@ bool DirectivesParser::callback(JSON_TYPE t, JSON_VAL* v, uint rlimit) { } } } - diff --git a/src/hotspot/share/compiler/oopMap.cpp b/src/hotspot/share/compiler/oopMap.cpp index 87467d06400..c8d0c5d22ba 100644 --- a/src/hotspot/share/compiler/oopMap.cpp +++ b/src/hotspot/share/compiler/oopMap.cpp @@ -869,7 +869,7 @@ ImmutableOopMapSet* ImmutableOopMapSet::clone() const { } void ImmutableOopMapSet::operator delete(void* p) { - FREE_C_HEAP_ARRAY(unsigned char, p); + FREE_C_HEAP_ARRAY(p); } //------------------------------DerivedPointerTable--------------------------- diff --git a/src/hotspot/share/gc/epsilon/epsilonMonitoringSupport.cpp b/src/hotspot/share/gc/epsilon/epsilonMonitoringSupport.cpp index 213fc18b8ff..7ec4a0016db 100644 --- a/src/hotspot/share/gc/epsilon/epsilonMonitoringSupport.cpp +++ b/src/hotspot/share/gc/epsilon/epsilonMonitoringSupport.cpp @@ -70,7 +70,7 @@ public: } ~EpsilonSpaceCounters() { - FREE_C_HEAP_ARRAY(char, _name_space); + FREE_C_HEAP_ARRAY(_name_space); } inline void update_all(size_t capacity, size_t used) { diff --git a/src/hotspot/share/gc/g1/c2/g1BarrierSetC2.cpp b/src/hotspot/share/gc/g1/c2/g1BarrierSetC2.cpp index 34d31702e80..3bf26bf46c9 100644 --- a/src/hotspot/share/gc/g1/c2/g1BarrierSetC2.cpp +++ b/src/hotspot/share/gc/g1/c2/g1BarrierSetC2.cpp @@ -68,7 +68,7 @@ * has happened since the allocation. */ bool G1BarrierSetC2::g1_can_remove_pre_barrier(GraphKit* kit, - PhaseValues* phase, + PhaseGVN* phase, Node* adr, BasicType bt, uint adr_idx) const { diff --git a/src/hotspot/share/gc/g1/c2/g1BarrierSetC2.hpp b/src/hotspot/share/gc/g1/c2/g1BarrierSetC2.hpp index 601d0f1138e..e8a0e797dfa 100644 --- a/src/hotspot/share/gc/g1/c2/g1BarrierSetC2.hpp +++ b/src/hotspot/share/gc/g1/c2/g1BarrierSetC2.hpp @@ -74,7 +74,7 @@ private: protected: bool g1_can_remove_pre_barrier(GraphKit* kit, - PhaseValues* phase, + PhaseGVN* phase, Node* adr, BasicType bt, uint adr_idx) const; diff --git a/src/hotspot/share/gc/g1/g1Allocator.cpp b/src/hotspot/share/gc/g1/g1Allocator.cpp index 78710084ee3..e9d1c13af7a 100644 --- a/src/hotspot/share/gc/g1/g1Allocator.cpp +++ b/src/hotspot/share/gc/g1/g1Allocator.cpp @@ -63,8 +63,8 @@ G1Allocator::~G1Allocator() { _mutator_alloc_regions[i].~MutatorAllocRegion(); _survivor_gc_alloc_regions[i].~SurvivorGCAllocRegion(); } - FREE_C_HEAP_ARRAY(MutatorAllocRegion, _mutator_alloc_regions); - FREE_C_HEAP_ARRAY(SurvivorGCAllocRegion, _survivor_gc_alloc_regions); + FREE_C_HEAP_ARRAY(_mutator_alloc_regions); + FREE_C_HEAP_ARRAY(_survivor_gc_alloc_regions); } #ifdef ASSERT @@ -315,7 +315,7 @@ G1PLABAllocator::PLABData::~PLABData() { for (uint node_index = 0; node_index < _num_alloc_buffers; node_index++) { delete _alloc_buffer[node_index]; } - FREE_C_HEAP_ARRAY(PLAB*, _alloc_buffer); + FREE_C_HEAP_ARRAY(_alloc_buffer); } void G1PLABAllocator::PLABData::initialize(uint num_alloc_buffers, size_t desired_plab_size, size_t tolerated_refills) { diff --git a/src/hotspot/share/gc/g1/g1Arguments.cpp b/src/hotspot/share/gc/g1/g1Arguments.cpp index c3bbd5a3b52..a0acd903b0f 100644 --- a/src/hotspot/share/gc/g1/g1Arguments.cpp +++ b/src/hotspot/share/gc/g1/g1Arguments.cpp @@ -98,7 +98,7 @@ void G1Arguments::initialize_verification_types() { parse_verification_type(token); token = strtok_r(nullptr, delimiter, &save_ptr); } - FREE_C_HEAP_ARRAY(char, type_list); + FREE_C_HEAP_ARRAY(type_list); } } diff --git a/src/hotspot/share/gc/g1/g1CardSet.cpp b/src/hotspot/share/gc/g1/g1CardSet.cpp index 60ad63e812c..f0db638a2fe 100644 --- a/src/hotspot/share/gc/g1/g1CardSet.cpp +++ b/src/hotspot/share/gc/g1/g1CardSet.cpp @@ -145,7 +145,7 @@ G1CardSetConfiguration::G1CardSetConfiguration(uint inline_ptr_bits_per_card, } G1CardSetConfiguration::~G1CardSetConfiguration() { - FREE_C_HEAP_ARRAY(size_t, _card_set_alloc_options); + FREE_C_HEAP_ARRAY(_card_set_alloc_options); } void G1CardSetConfiguration::init_card_set_alloc_options() { diff --git a/src/hotspot/share/gc/g1/g1CardSetMemory.cpp b/src/hotspot/share/gc/g1/g1CardSetMemory.cpp index 0da2f90da3f..95a32bae766 100644 --- a/src/hotspot/share/gc/g1/g1CardSetMemory.cpp +++ b/src/hotspot/share/gc/g1/g1CardSetMemory.cpp @@ -90,7 +90,7 @@ G1CardSetMemoryManager::~G1CardSetMemoryManager() { for (uint i = 0; i < num_mem_object_types(); i++) { _allocators[i].~G1CardSetAllocator(); } - FREE_C_HEAP_ARRAY(G1CardSetAllocator, _allocators); + FREE_C_HEAP_ARRAY(_allocators); } void G1CardSetMemoryManager::free(uint type, void* value) { diff --git a/src/hotspot/share/gc/g1/g1CardTableClaimTable.cpp b/src/hotspot/share/gc/g1/g1CardTableClaimTable.cpp index d8cabaa00a4..27b41ef165f 100644 --- a/src/hotspot/share/gc/g1/g1CardTableClaimTable.cpp +++ b/src/hotspot/share/gc/g1/g1CardTableClaimTable.cpp @@ -39,7 +39,7 @@ G1CardTableClaimTable::G1CardTableClaimTable(uint chunks_per_region) : } G1CardTableClaimTable::~G1CardTableClaimTable() { - FREE_C_HEAP_ARRAY(uint, _card_claims); + FREE_C_HEAP_ARRAY(_card_claims); } void G1CardTableClaimTable::initialize(uint max_reserved_regions) { diff --git a/src/hotspot/share/gc/g1/g1CollectedHeap.cpp b/src/hotspot/share/gc/g1/g1CollectedHeap.cpp index 2709e6b3008..de0a0927115 100644 --- a/src/hotspot/share/gc/g1/g1CollectedHeap.cpp +++ b/src/hotspot/share/gc/g1/g1CollectedHeap.cpp @@ -944,10 +944,6 @@ void G1CollectedHeap::do_full_collection(size_t allocation_word_size, } void G1CollectedHeap::do_full_collection(bool clear_all_soft_refs) { - // Currently, there is no facility in the do_full_collection(bool) API to notify - // the caller that the collection did not succeed (e.g., because it was locked - // out by the GC locker). So, right now, we'll ignore the return value. - do_full_collection(size_t(0) /* allocation_word_size */, clear_all_soft_refs, false /* do_maximal_compaction */); @@ -2960,7 +2956,7 @@ void G1CollectedHeap::abandon_collection_set() { collection_set()->abandon(); } -size_t G1CollectedHeap::non_young_occupancy_after_allocation(size_t allocation_word_size) { +size_t G1CollectedHeap::non_young_occupancy_after_allocation(size_t allocation_word_size) const { const size_t cur_occupancy = (old_regions_count() + humongous_regions_count()) * G1HeapRegion::GrainBytes - _allocator->free_bytes_in_retained_old_region(); // Humongous allocations will always be assigned to non-young heap, so consider diff --git a/src/hotspot/share/gc/g1/g1CollectedHeap.hpp b/src/hotspot/share/gc/g1/g1CollectedHeap.hpp index 3a47453819e..a68d1030636 100644 --- a/src/hotspot/share/gc/g1/g1CollectedHeap.hpp +++ b/src/hotspot/share/gc/g1/g1CollectedHeap.hpp @@ -1032,7 +1032,7 @@ public: // Returns how much memory there is assigned to non-young heap that can not be // allocated into any more without garbage collection after a hypothetical // allocation of allocation_word_size. - size_t non_young_occupancy_after_allocation(size_t allocation_word_size); + size_t non_young_occupancy_after_allocation(size_t allocation_word_size) const; // Determine whether the given region is one that we are using as an // old GC alloc region. diff --git a/src/hotspot/share/gc/g1/g1CollectionSet.cpp b/src/hotspot/share/gc/g1/g1CollectionSet.cpp index b3bcf6094ab..7329e679519 100644 --- a/src/hotspot/share/gc/g1/g1CollectionSet.cpp +++ b/src/hotspot/share/gc/g1/g1CollectionSet.cpp @@ -72,7 +72,7 @@ G1CollectionSet::G1CollectionSet(G1CollectedHeap* g1h, G1Policy* policy) : } G1CollectionSet::~G1CollectionSet() { - FREE_C_HEAP_ARRAY(uint, _regions); + FREE_C_HEAP_ARRAY(_regions); abandon_all_candidates(); } @@ -373,7 +373,7 @@ double G1CollectionSet::finalize_young_part(double target_pause_time_ms, G1Survi // made to regular old regions without remembered sets after a few attempts to save computation costs // of keeping them candidates for very long living pinned regions. void G1CollectionSet::finalize_old_part(double time_remaining_ms) { - double non_young_start_time_sec = os::elapsedTime(); + Ticks start_time = Ticks::now(); if (!candidates()->is_empty()) { candidates()->verify(); @@ -392,8 +392,7 @@ void G1CollectionSet::finalize_old_part(double time_remaining_ms) { log_debug(gc, ergo, cset)("No candidates to reclaim."); } - double non_young_end_time_sec = os::elapsedTime(); - phase_times()->record_non_young_cset_choice_time_ms((non_young_end_time_sec - non_young_start_time_sec) * 1000.0); + phase_times()->record_non_young_cset_choice_time_ms((Ticks::now() - start_time).seconds() * MILLIUNITS); } static void print_finish_message(const char* reason, bool from_marking) { @@ -766,7 +765,7 @@ public: } } ~G1VerifyYoungCSetIndicesClosure() { - FREE_C_HEAP_ARRAY(int, _heap_region_indices); + FREE_C_HEAP_ARRAY(_heap_region_indices); } virtual bool do_heap_region(G1HeapRegion* r) { diff --git a/src/hotspot/share/gc/g1/g1CollectionSetCandidates.cpp b/src/hotspot/share/gc/g1/g1CollectionSetCandidates.cpp index 2113db1163b..3637d477229 100644 --- a/src/hotspot/share/gc/g1/g1CollectionSetCandidates.cpp +++ b/src/hotspot/share/gc/g1/g1CollectionSetCandidates.cpp @@ -214,7 +214,7 @@ G1CollectionSetCandidates::G1CollectionSetCandidates() : { } G1CollectionSetCandidates::~G1CollectionSetCandidates() { - FREE_C_HEAP_ARRAY(CandidateOrigin, _contains_map); + FREE_C_HEAP_ARRAY(_contains_map); _from_marking_groups.clear(); _retained_groups.clear(); } @@ -413,7 +413,7 @@ void G1CollectionSetCandidates::verify() { static_cast::type>(verify_map[i])); } - FREE_C_HEAP_ARRAY(CandidateOrigin, verify_map); + FREE_C_HEAP_ARRAY(verify_map); } #endif diff --git a/src/hotspot/share/gc/g1/g1ConcurrentMark.cpp b/src/hotspot/share/gc/g1/g1ConcurrentMark.cpp index dbb5ba509a2..9952fab5e2c 100644 --- a/src/hotspot/share/gc/g1/g1ConcurrentMark.cpp +++ b/src/hotspot/share/gc/g1/g1ConcurrentMark.cpp @@ -249,7 +249,7 @@ G1CMMarkStack::ChunkAllocator::~ChunkAllocator() { } } - FREE_C_HEAP_ARRAY(TaskQueueEntryChunk*, _buckets); + FREE_C_HEAP_ARRAY(_buckets); } bool G1CMMarkStack::ChunkAllocator::reserve(size_t new_capacity) { @@ -524,7 +524,10 @@ void G1ConcurrentMark::fully_initialize() { uint max_num_regions = _g1h->max_num_regions(); ::new (_region_mark_stats) G1RegionMarkStats[max_num_regions]{}; - ::new (_top_at_mark_starts) Atomic[max_num_regions]{}; + for (uint i = 0; i < max_num_regions; i++) { + ::new (&_top_at_mark_starts[i]) Atomic(_g1h->bottom_addr_for_region(i)); + } + // Contrary to TAMS, the default value of _top_at_rebuild_starts needs to be null. ::new (_top_at_rebuild_starts) Atomic[max_num_regions]{}; reset_at_marking_complete(); @@ -676,9 +679,9 @@ void G1ConcurrentMark::reset_at_marking_complete() { } G1ConcurrentMark::~G1ConcurrentMark() { - FREE_C_HEAP_ARRAY(Atomic, _top_at_mark_starts); - FREE_C_HEAP_ARRAY(Atomic, _top_at_rebuild_starts); - FREE_C_HEAP_ARRAY(G1RegionMarkStats, _region_mark_stats); + FREE_C_HEAP_ARRAY(_top_at_mark_starts); + FREE_C_HEAP_ARRAY(_top_at_rebuild_starts); + FREE_C_HEAP_ARRAY(_region_mark_stats); // The G1ConcurrentMark instance is never freed. ShouldNotReachHere(); } diff --git a/src/hotspot/share/gc/g1/g1ConcurrentRefineSweepTask.cpp b/src/hotspot/share/gc/g1/g1ConcurrentRefineSweepTask.cpp index ce944f2254d..e522163f980 100644 --- a/src/hotspot/share/gc/g1/g1ConcurrentRefineSweepTask.cpp +++ b/src/hotspot/share/gc/g1/g1ConcurrentRefineSweepTask.cpp @@ -35,8 +35,6 @@ class G1RefineRegionClosure : public G1HeapRegionClosure { uint _worker_id; - size_t _num_collections_at_start; - bool has_work(G1HeapRegion* r) { return _scan_state->has_unclaimed_cards(r->hrm_index()); } @@ -189,4 +187,4 @@ void G1ConcurrentRefineSweepTask::work(uint worker_id) { _stats->add_atomic(&sweep_cl._refine_stats); } -bool G1ConcurrentRefineSweepTask::sweep_completed() const { return _sweep_completed; } \ No newline at end of file +bool G1ConcurrentRefineSweepTask::sweep_completed() const { return _sweep_completed; } diff --git a/src/hotspot/share/gc/g1/g1EvacFailureRegions.cpp b/src/hotspot/share/gc/g1/g1EvacFailureRegions.cpp index 37553e2aa56..03c20346eb3 100644 --- a/src/hotspot/share/gc/g1/g1EvacFailureRegions.cpp +++ b/src/hotspot/share/gc/g1/g1EvacFailureRegions.cpp @@ -55,7 +55,7 @@ void G1EvacFailureRegions::post_collection() { _regions_pinned.resize(0); _regions_alloc_failed.resize(0); - FREE_C_HEAP_ARRAY(uint, _evac_failed_regions); + FREE_C_HEAP_ARRAY(_evac_failed_regions); _evac_failed_regions = nullptr; } diff --git a/src/hotspot/share/gc/g1/g1FullCollector.cpp b/src/hotspot/share/gc/g1/g1FullCollector.cpp index c835dd159a6..8b38509d1d8 100644 --- a/src/hotspot/share/gc/g1/g1FullCollector.cpp +++ b/src/hotspot/share/gc/g1/g1FullCollector.cpp @@ -167,10 +167,10 @@ G1FullCollector::~G1FullCollector() { delete _partial_array_state_manager; - FREE_C_HEAP_ARRAY(G1FullGCMarker*, _markers); - FREE_C_HEAP_ARRAY(G1FullGCCompactionPoint*, _compaction_points); - FREE_C_HEAP_ARRAY(Atomic, _compaction_tops); - FREE_C_HEAP_ARRAY(G1RegionMarkStats, _live_stats); + FREE_C_HEAP_ARRAY(_markers); + FREE_C_HEAP_ARRAY(_compaction_points); + FREE_C_HEAP_ARRAY(_compaction_tops); + FREE_C_HEAP_ARRAY(_live_stats); } class PrepareRegionsClosure : public G1HeapRegionClosure { diff --git a/src/hotspot/share/gc/g1/g1GCPhaseTimes.cpp b/src/hotspot/share/gc/g1/g1GCPhaseTimes.cpp index 023790a2422..e13b9d91bc5 100644 --- a/src/hotspot/share/gc/g1/g1GCPhaseTimes.cpp +++ b/src/hotspot/share/gc/g1/g1GCPhaseTimes.cpp @@ -181,7 +181,6 @@ void G1GCPhaseTimes::reset() { _cur_resize_heap_time_ms = 0.0; _cur_ref_proc_time_ms = 0.0; _root_region_scan_time_ms = 0.0; - _external_accounted_time_ms = 0.0; _recorded_prepare_heap_roots_time_ms = 0.0; _recorded_young_cset_choice_time_ms = 0.0; _recorded_non_young_cset_choice_time_ms = 0.0; @@ -416,8 +415,6 @@ double G1GCPhaseTimes::print_pre_evacuate_collection_set() const { info_time("Pre Evacuate Collection Set", sum_ms); - // Concurrent tasks of ResetMarkingState and NoteStartOfMark are triggered during - // young collection. However, their execution time are not included in _gc_pause_time_ms. if (_cur_prepare_concurrent_task_time_ms > 0.0) { debug_time("Prepare Concurrent Start", _cur_prepare_concurrent_task_time_ms); debug_phase(_gc_par_phases[ResetMarkingState], 1); @@ -543,10 +540,9 @@ void G1GCPhaseTimes::print_other(double accounted_ms) const { info_time("Other", _gc_pause_time_ms - accounted_ms); } -// Root-region-scan-wait, verify-before and verify-after are part of young GC, +// Root region scan, verify before and verify after are part of young GC, // but these are not measured by G1Policy. i.e. these are not included in // G1Policy::record_young_collection_start() and record_young_collection_end(). -// In addition, these are not included in G1GCPhaseTimes::_gc_pause_time_ms. // See G1YoungCollector::collect(). void G1GCPhaseTimes::print(bool evacuation_failed) { if (_root_region_scan_time_ms > 0.0) { diff --git a/src/hotspot/share/gc/g1/g1GCPhaseTimes.hpp b/src/hotspot/share/gc/g1/g1GCPhaseTimes.hpp index b57bf0d617e..eb51b340da3 100644 --- a/src/hotspot/share/gc/g1/g1GCPhaseTimes.hpp +++ b/src/hotspot/share/gc/g1/g1GCPhaseTimes.hpp @@ -175,7 +175,6 @@ class G1GCPhaseTimes : public CHeapObj { double _cur_collection_nmethod_list_cleanup_time_ms; double _cur_merge_heap_roots_time_ms; - // Merge refinement table time. Note that this time is included in _cur_merge_heap_roots_time_ms. double _cur_merge_refinement_table_time_ms; double _cur_optional_merge_heap_roots_time_ms; @@ -190,11 +189,8 @@ class G1GCPhaseTimes : public CHeapObj { double _cur_resize_heap_time_ms; double _cur_ref_proc_time_ms; - // Not included in _gc_pause_time_ms double _root_region_scan_time_ms; - double _external_accounted_time_ms; - double _recorded_prepare_heap_roots_time_ms; double _recorded_young_cset_choice_time_ms; @@ -210,7 +206,6 @@ class G1GCPhaseTimes : public CHeapObj { double _cur_region_register_time; - // Not included in _gc_pause_time_ms double _cur_verify_before_time_ms; double _cur_verify_after_time_ms; @@ -298,7 +293,7 @@ class G1GCPhaseTimes : public CHeapObj { } void record_merge_heap_roots_time(double ms) { - _cur_merge_heap_roots_time_ms += ms; + _cur_merge_heap_roots_time_ms = ms; } void record_merge_refinement_table_time(double ms) { @@ -373,10 +368,6 @@ class G1GCPhaseTimes : public CHeapObj { _cur_verify_after_time_ms = time_ms; } - void inc_external_accounted_time_ms(double time_ms) { - _external_accounted_time_ms += time_ms; - } - void record_prepare_heap_roots_time_ms(double recorded_prepare_heap_roots_time_ms) { _recorded_prepare_heap_roots_time_ms = recorded_prepare_heap_roots_time_ms; } diff --git a/src/hotspot/share/gc/g1/g1HeapRegion.inline.hpp b/src/hotspot/share/gc/g1/g1HeapRegion.inline.hpp index f92e37fee3c..619aef35a9a 100644 --- a/src/hotspot/share/gc/g1/g1HeapRegion.inline.hpp +++ b/src/hotspot/share/gc/g1/g1HeapRegion.inline.hpp @@ -187,7 +187,16 @@ inline void G1HeapRegion::apply_to_marked_objects(G1CMBitMap* bitmap, ApplyToMar } } - assert(next_addr == limit, "Should stop the scan at the limit."); +#ifdef ASSERT + if (is_starts_humongous() && bitmap->is_marked(bottom())) { + HeapWord* humongous_end = bottom() + cast_to_oop(bottom())->size(); + assert(next_addr == MAX2(limit, humongous_end), + "Should stop the scan at limit or end of humongous object. r %u (%s)", + hrm_index(), get_short_type_str()); + } else { + assert(next_addr == limit, "Should stop the scan at the limit. r %u (%s)", hrm_index(), get_short_type_str()); + } +#endif } inline HeapWord* G1HeapRegion::par_allocate(size_t min_word_size, diff --git a/src/hotspot/share/gc/g1/g1HeapRegionManager.cpp b/src/hotspot/share/gc/g1/g1HeapRegionManager.cpp index 3c0318827ef..214f1a2d2b6 100644 --- a/src/hotspot/share/gc/g1/g1HeapRegionManager.cpp +++ b/src/hotspot/share/gc/g1/g1HeapRegionManager.cpp @@ -718,7 +718,7 @@ G1HeapRegionClaimer::G1HeapRegionClaimer(uint n_workers) : } G1HeapRegionClaimer::~G1HeapRegionClaimer() { - FREE_C_HEAP_ARRAY(uint, _claims); + FREE_C_HEAP_ARRAY(_claims); } uint G1HeapRegionClaimer::offset_for_worker(uint worker_id) const { @@ -759,7 +759,7 @@ public: for (uint worker = 0; worker < _num_workers; worker++) { _worker_freelists[worker].~G1FreeRegionList(); } - FREE_C_HEAP_ARRAY(G1FreeRegionList, _worker_freelists); + FREE_C_HEAP_ARRAY(_worker_freelists); } G1FreeRegionList* worker_freelist(uint worker) { diff --git a/src/hotspot/share/gc/g1/g1HeapRegionSet.cpp b/src/hotspot/share/gc/g1/g1HeapRegionSet.cpp index 70186adcdfc..930a4bd953f 100644 --- a/src/hotspot/share/gc/g1/g1HeapRegionSet.cpp +++ b/src/hotspot/share/gc/g1/g1HeapRegionSet.cpp @@ -384,7 +384,7 @@ G1FreeRegionList::NodeInfo::NodeInfo() : _numa(G1NUMA::numa()), _length_of_node( } G1FreeRegionList::NodeInfo::~NodeInfo() { - FREE_C_HEAP_ARRAY(uint, _length_of_node); + FREE_C_HEAP_ARRAY(_length_of_node); } void G1FreeRegionList::NodeInfo::clear() { diff --git a/src/hotspot/share/gc/g1/g1HeapTransition.cpp b/src/hotspot/share/gc/g1/g1HeapTransition.cpp index 30ad4c72bf6..690bda4e7e6 100644 --- a/src/hotspot/share/gc/g1/g1HeapTransition.cpp +++ b/src/hotspot/share/gc/g1/g1HeapTransition.cpp @@ -55,8 +55,8 @@ G1HeapTransition::Data::Data(G1CollectedHeap* g1_heap) : } G1HeapTransition::Data::~Data() { - FREE_C_HEAP_ARRAY(uint, _eden_length_per_node); - FREE_C_HEAP_ARRAY(uint, _survivor_length_per_node); + FREE_C_HEAP_ARRAY(_eden_length_per_node); + FREE_C_HEAP_ARRAY(_survivor_length_per_node); } G1HeapTransition::G1HeapTransition(G1CollectedHeap* g1_heap) : _g1_heap(g1_heap), _before(g1_heap) { } diff --git a/src/hotspot/share/gc/g1/g1HeapVerifier.cpp b/src/hotspot/share/gc/g1/g1HeapVerifier.cpp index 714a2473a08..304722c13a1 100644 --- a/src/hotspot/share/gc/g1/g1HeapVerifier.cpp +++ b/src/hotspot/share/gc/g1/g1HeapVerifier.cpp @@ -461,35 +461,34 @@ public: G1ConcurrentMark* cm = G1CollectedHeap::heap()->concurrent_mark(); - bool part_of_marking = r->is_old_or_humongous() && !r->is_collection_set_candidate(); HeapWord* top_at_mark_start = cm->top_at_mark_start(r); - if (part_of_marking) { - guarantee(r->bottom() != top_at_mark_start, - "region %u (%s) does not have TAMS set", - r->hrm_index(), r->get_short_type_str()); - size_t marked_bytes = cm->live_bytes(r->hrm_index()); - + if (r->is_old_or_humongous()) { + if (!cm->is_root_region(r)) { + guarantee(r->bottom() != top_at_mark_start, + "region %u (%s) does not have TAMS set although it's going to be marked through", + r->hrm_index(), r->get_short_type_str()); + } MarkedBytesClosure cl; r->apply_to_marked_objects(cm->mark_bitmap(), &cl); + size_t marked_bytes = cm->live_bytes(r->hrm_index()); guarantee(cl.marked_bytes() == marked_bytes, "region %u (%s) live bytes actual %zu and cache %zu differ", r->hrm_index(), r->get_short_type_str(), cl.marked_bytes(), marked_bytes); - } else { + } else if (r->is_young()) { guarantee(r->bottom() == top_at_mark_start, "region %u (%s) has TAMS set " PTR_FORMAT " " PTR_FORMAT, r->hrm_index(), r->get_short_type_str(), p2i(r->bottom()), p2i(top_at_mark_start)); guarantee(cm->live_bytes(r->hrm_index()) == 0, "region %u (%s) has %zu live bytes recorded", r->hrm_index(), r->get_short_type_str(), cm->live_bytes(r->hrm_index())); - guarantee(cm->mark_bitmap()->get_next_marked_addr(r->bottom(), r->end()) == r->end(), - "region %u (%s) has mark", - r->hrm_index(), r->get_short_type_str()); - guarantee(cm->is_root_region(r), - "region %u (%s) should be root region", - r->hrm_index(), r->get_short_type_str()); + guarantee(cm->is_root_region(r), "must be for %u (%s)", r->hrm_index(), r->get_short_type_str()); } + + guarantee(cm->mark_bitmap()->get_next_marked_addr(top_at_mark_start, r->end()) == r->end(), + "region %u (%s) has mark from TAMS to top", + r->hrm_index(), r->get_short_type_str()); return false; } }; diff --git a/src/hotspot/share/gc/g1/g1IHOPControl.cpp b/src/hotspot/share/gc/g1/g1IHOPControl.cpp index 1e1c52477f9..164486123f7 100644 --- a/src/hotspot/share/gc/g1/g1IHOPControl.cpp +++ b/src/hotspot/share/gc/g1/g1IHOPControl.cpp @@ -114,7 +114,7 @@ void G1IHOPControl::add_marking_start_to_mixed_length(double length_s) { // Determine the old generation occupancy threshold at which to start // concurrent marking such that reclamation (first Mixed GC) begins // before the heap reaches a critical occupancy level. -size_t G1IHOPControl::old_gen_threshold_for_conc_mark_start() { +size_t G1IHOPControl::old_gen_threshold_for_conc_mark_start() const { guarantee(_target_occupancy > 0, "Target occupancy must be initialized"); if (!_is_adaptive || !have_enough_data_for_prediction()) { diff --git a/src/hotspot/share/gc/g1/g1IHOPControl.hpp b/src/hotspot/share/gc/g1/g1IHOPControl.hpp index ff209012f02..2836408978b 100644 --- a/src/hotspot/share/gc/g1/g1IHOPControl.hpp +++ b/src/hotspot/share/gc/g1/g1IHOPControl.hpp @@ -115,7 +115,7 @@ class G1IHOPControl : public CHeapObj { void add_marking_start_to_mixed_length(double length_s); // Get the current non-young occupancy at which concurrent marking should start. - size_t old_gen_threshold_for_conc_mark_start(); + size_t old_gen_threshold_for_conc_mark_start() const; void report_statistics(G1NewTracer* tracer, size_t non_young_occupancy); }; diff --git a/src/hotspot/share/gc/g1/g1MonotonicArena.cpp b/src/hotspot/share/gc/g1/g1MonotonicArena.cpp index 3f97870a67f..aea6f4335e8 100644 --- a/src/hotspot/share/gc/g1/g1MonotonicArena.cpp +++ b/src/hotspot/share/gc/g1/g1MonotonicArena.cpp @@ -52,7 +52,7 @@ void G1MonotonicArena::Segment::delete_segment(Segment* segment) { GlobalCounter::write_synchronize(); } segment->~Segment(); - FREE_C_HEAP_ARRAY(_mem_tag, segment); + FREE_C_HEAP_ARRAY(segment); } void G1MonotonicArena::SegmentFreeList::bulk_add(Segment& first, diff --git a/src/hotspot/share/gc/g1/g1MonotonicArenaFreePool.cpp b/src/hotspot/share/gc/g1/g1MonotonicArenaFreePool.cpp index 922c68bfba4..c12321b851a 100644 --- a/src/hotspot/share/gc/g1/g1MonotonicArenaFreePool.cpp +++ b/src/hotspot/share/gc/g1/g1MonotonicArenaFreePool.cpp @@ -159,7 +159,7 @@ G1MonotonicArenaFreePool::~G1MonotonicArenaFreePool() { for (uint i = 0; i < _num_free_lists; i++) { _free_lists[i].~SegmentFreeList(); } - FREE_C_HEAP_ARRAY(mtGC, _free_lists); + FREE_C_HEAP_ARRAY(_free_lists); } G1MonotonicArenaMemoryStats G1MonotonicArenaFreePool::memory_sizes() const { diff --git a/src/hotspot/share/gc/g1/g1NUMA.cpp b/src/hotspot/share/gc/g1/g1NUMA.cpp index 778ed31d7b5..db42b8c10fc 100644 --- a/src/hotspot/share/gc/g1/g1NUMA.cpp +++ b/src/hotspot/share/gc/g1/g1NUMA.cpp @@ -123,8 +123,8 @@ void G1NUMA::initialize(bool use_numa) { G1NUMA::~G1NUMA() { delete _stats; - FREE_C_HEAP_ARRAY(uint, _node_id_to_index_map); - FREE_C_HEAP_ARRAY(uint, _node_ids); + FREE_C_HEAP_ARRAY(_node_id_to_index_map); + FREE_C_HEAP_ARRAY(_node_ids); } void G1NUMA::set_region_info(size_t region_size, size_t page_size) { @@ -280,9 +280,9 @@ G1NodeIndexCheckClosure::~G1NodeIndexCheckClosure() { _ls->print("%u: %u/%u/%u ", numa_ids[i], _matched[i], _mismatched[i], _total[i]); } - FREE_C_HEAP_ARRAY(uint, _matched); - FREE_C_HEAP_ARRAY(uint, _mismatched); - FREE_C_HEAP_ARRAY(uint, _total); + FREE_C_HEAP_ARRAY(_matched); + FREE_C_HEAP_ARRAY(_mismatched); + FREE_C_HEAP_ARRAY(_total); } bool G1NodeIndexCheckClosure::do_heap_region(G1HeapRegion* hr) { diff --git a/src/hotspot/share/gc/g1/g1NUMAStats.cpp b/src/hotspot/share/gc/g1/g1NUMAStats.cpp index aaebfa1be8f..ce62d34f847 100644 --- a/src/hotspot/share/gc/g1/g1NUMAStats.cpp +++ b/src/hotspot/share/gc/g1/g1NUMAStats.cpp @@ -45,9 +45,9 @@ G1NUMAStats::NodeDataArray::NodeDataArray(uint num_nodes) { G1NUMAStats::NodeDataArray::~NodeDataArray() { for (uint row = 0; row < _num_row; row++) { - FREE_C_HEAP_ARRAY(size_t, _data[row]); + FREE_C_HEAP_ARRAY(_data[row]); } - FREE_C_HEAP_ARRAY(size_t*, _data); + FREE_C_HEAP_ARRAY(_data); } void G1NUMAStats::NodeDataArray::create_hit_rate(Stat* result) const { diff --git a/src/hotspot/share/gc/g1/g1ParScanThreadState.cpp b/src/hotspot/share/gc/g1/g1ParScanThreadState.cpp index 52c8d4d4389..50438c641c2 100644 --- a/src/hotspot/share/gc/g1/g1ParScanThreadState.cpp +++ b/src/hotspot/share/gc/g1/g1ParScanThreadState.cpp @@ -131,9 +131,9 @@ size_t G1ParScanThreadState::flush_stats(size_t* surviving_young_words, uint num G1ParScanThreadState::~G1ParScanThreadState() { delete _plab_allocator; delete _closures; - FREE_C_HEAP_ARRAY(size_t, _surviving_young_words_base); + FREE_C_HEAP_ARRAY(_surviving_young_words_base); delete[] _oops_into_optional_regions; - FREE_C_HEAP_ARRAY(size_t, _obj_alloc_stat); + FREE_C_HEAP_ARRAY(_obj_alloc_stat); } size_t G1ParScanThreadState::lab_waste_words() const { @@ -730,8 +730,8 @@ G1ParScanThreadStateSet::G1ParScanThreadStateSet(G1CollectedHeap* g1h, G1ParScanThreadStateSet::~G1ParScanThreadStateSet() { assert(_flushed, "thread local state from the per thread states should have been flushed"); - FREE_C_HEAP_ARRAY(G1ParScanThreadState*, _states); - FREE_C_HEAP_ARRAY(size_t, _surviving_young_words_total); + FREE_C_HEAP_ARRAY(_states); + FREE_C_HEAP_ARRAY(_surviving_young_words_total); } #if TASKQUEUE_STATS diff --git a/src/hotspot/share/gc/g1/g1Policy.cpp b/src/hotspot/share/gc/g1/g1Policy.cpp index 78a533d62c0..769977c7dac 100644 --- a/src/hotspot/share/gc/g1/g1Policy.cpp +++ b/src/hotspot/share/gc/g1/g1Policy.cpp @@ -728,7 +728,7 @@ bool G1Policy::about_to_start_mixed_phase() const { return collector_state()->is_in_concurrent_cycle() || collector_state()->is_in_prepare_mixed_gc(); } -bool G1Policy::need_to_start_conc_mark(const char* source, size_t allocation_word_size) { +bool G1Policy::need_to_start_conc_mark(const char* source, size_t allocation_word_size) const { if (about_to_start_mixed_phase()) { return false; } diff --git a/src/hotspot/share/gc/g1/g1Policy.hpp b/src/hotspot/share/gc/g1/g1Policy.hpp index 5c5c2bc3572..0aa15be9cae 100644 --- a/src/hotspot/share/gc/g1/g1Policy.hpp +++ b/src/hotspot/share/gc/g1/g1Policy.hpp @@ -296,7 +296,7 @@ public: void record_young_gc_pause_start(); void record_young_gc_pause_end(bool evacuation_failed); - bool need_to_start_conc_mark(const char* source, size_t allocation_word_size); + bool need_to_start_conc_mark(const char* source, size_t allocation_word_size) const; bool concurrent_operation_is_full_mark(const char* msg, size_t allocation_word_size); diff --git a/src/hotspot/share/gc/g1/g1RegionMarkStatsCache.cpp b/src/hotspot/share/gc/g1/g1RegionMarkStatsCache.cpp index c5f55e1d20c..a9f4115df94 100644 --- a/src/hotspot/share/gc/g1/g1RegionMarkStatsCache.cpp +++ b/src/hotspot/share/gc/g1/g1RegionMarkStatsCache.cpp @@ -38,7 +38,7 @@ G1RegionMarkStatsCache::G1RegionMarkStatsCache(G1RegionMarkStats* target, uint n } G1RegionMarkStatsCache::~G1RegionMarkStatsCache() { - FREE_C_HEAP_ARRAY(G1RegionMarkStatsCacheEntry, _cache); + FREE_C_HEAP_ARRAY(_cache); } void G1RegionMarkStatsCache::add_live_words(oop obj) { diff --git a/src/hotspot/share/gc/g1/g1RegionsOnNodes.cpp b/src/hotspot/share/gc/g1/g1RegionsOnNodes.cpp index c1c0d471796..9550e57698e 100644 --- a/src/hotspot/share/gc/g1/g1RegionsOnNodes.cpp +++ b/src/hotspot/share/gc/g1/g1RegionsOnNodes.cpp @@ -32,7 +32,7 @@ G1RegionsOnNodes::G1RegionsOnNodes() : _count_per_node(nullptr), _numa(G1NUMA::n } G1RegionsOnNodes::~G1RegionsOnNodes() { - FREE_C_HEAP_ARRAY(uint, _count_per_node); + FREE_C_HEAP_ARRAY(_count_per_node); } void G1RegionsOnNodes::add(G1HeapRegion* hr) { diff --git a/src/hotspot/share/gc/g1/g1RemSet.cpp b/src/hotspot/share/gc/g1/g1RemSet.cpp index 9f9f0ecdf3a..be18a3065e9 100644 --- a/src/hotspot/share/gc/g1/g1RemSet.cpp +++ b/src/hotspot/share/gc/g1/g1RemSet.cpp @@ -124,8 +124,8 @@ class G1RemSetScanState : public CHeapObj { } ~G1DirtyRegions() { - FREE_C_HEAP_ARRAY(uint, _buffer); - FREE_C_HEAP_ARRAY(Atomic, _contains); + FREE_C_HEAP_ARRAY(_buffer); + FREE_C_HEAP_ARRAY(_contains); } void reset() { @@ -245,7 +245,7 @@ public: _scan_top(nullptr) { } ~G1RemSetScanState() { - FREE_C_HEAP_ARRAY(HeapWord*, _scan_top); + FREE_C_HEAP_ARRAY(_scan_top); } void initialize(uint max_reserved_regions) { diff --git a/src/hotspot/share/gc/g1/g1RemSetSummary.cpp b/src/hotspot/share/gc/g1/g1RemSetSummary.cpp index 3e9cf938097..1c0e15757cc 100644 --- a/src/hotspot/share/gc/g1/g1RemSetSummary.cpp +++ b/src/hotspot/share/gc/g1/g1RemSetSummary.cpp @@ -98,7 +98,7 @@ G1RemSetSummary::G1RemSetSummary(bool should_update) : } G1RemSetSummary::~G1RemSetSummary() { - FREE_C_HEAP_ARRAY(jlong, _worker_threads_cpu_times); + FREE_C_HEAP_ARRAY(_worker_threads_cpu_times); } void G1RemSetSummary::set(G1RemSetSummary* other) { diff --git a/src/hotspot/share/gc/g1/g1SurvRateGroup.cpp b/src/hotspot/share/gc/g1/g1SurvRateGroup.cpp index f858b93b13d..15c6d3d1f15 100644 --- a/src/hotspot/share/gc/g1/g1SurvRateGroup.cpp +++ b/src/hotspot/share/gc/g1/g1SurvRateGroup.cpp @@ -65,8 +65,8 @@ void G1SurvRateGroup::start_adding_regions() { void G1SurvRateGroup::stop_adding_regions() { if (_num_added_regions > _stats_arrays_length) { - _accum_surv_rate_pred = REALLOC_C_HEAP_ARRAY(double, _accum_surv_rate_pred, _num_added_regions, mtGC); - _surv_rate_predictors = REALLOC_C_HEAP_ARRAY(TruncatedSeq*, _surv_rate_predictors, _num_added_regions, mtGC); + _accum_surv_rate_pred = REALLOC_C_HEAP_ARRAY(_accum_surv_rate_pred, _num_added_regions, mtGC); + _surv_rate_predictors = REALLOC_C_HEAP_ARRAY(_surv_rate_predictors, _num_added_regions, mtGC); for (uint i = _stats_arrays_length; i < _num_added_regions; ++i) { // Initialize predictors and accumulated survivor rate predictions. diff --git a/src/hotspot/share/gc/g1/g1YoungGCPostEvacuateTasks.cpp b/src/hotspot/share/gc/g1/g1YoungGCPostEvacuateTasks.cpp index 14282383e29..11da3cb8263 100644 --- a/src/hotspot/share/gc/g1/g1YoungGCPostEvacuateTasks.cpp +++ b/src/hotspot/share/gc/g1/g1YoungGCPostEvacuateTasks.cpp @@ -802,7 +802,7 @@ public: for (uint worker = 0; worker < _active_workers; worker++) { _worker_stats[worker].~FreeCSetStats(); } - FREE_C_HEAP_ARRAY(FreeCSetStats, _worker_stats); + FREE_C_HEAP_ARRAY(_worker_stats); _g1h->clear_collection_set(); diff --git a/src/hotspot/share/gc/g1/g1YoungGCPreEvacuateTasks.cpp b/src/hotspot/share/gc/g1/g1YoungGCPreEvacuateTasks.cpp index 936457659b6..7889fd4fb31 100644 --- a/src/hotspot/share/gc/g1/g1YoungGCPreEvacuateTasks.cpp +++ b/src/hotspot/share/gc/g1/g1YoungGCPreEvacuateTasks.cpp @@ -73,7 +73,7 @@ public: ~JavaThreadRetireTLABs() { static_assert(std::is_trivially_destructible::value, "must be"); - FREE_C_HEAP_ARRAY(ThreadLocalAllocStats, _local_tlab_stats); + FREE_C_HEAP_ARRAY(_local_tlab_stats); } void do_work(uint worker_id) override { diff --git a/src/hotspot/share/gc/g1/g1_globals.hpp b/src/hotspot/share/gc/g1/g1_globals.hpp index b338c11d5be..baed70b7088 100644 --- a/src/hotspot/share/gc/g1/g1_globals.hpp +++ b/src/hotspot/share/gc/g1/g1_globals.hpp @@ -316,7 +316,7 @@ product(bool, G1VerifyHeapRegionCodeRoots, false, DIAGNOSTIC, \ "Verify the code root lists attached to each heap region.") \ \ - develop(bool, G1VerifyBitmaps, false, \ + product(bool, G1VerifyBitmaps, false, DIAGNOSTIC, \ "Verifies the consistency of the marking bitmaps") \ \ product(uintx, G1PeriodicGCInterval, 0, MANAGEABLE, \ diff --git a/src/hotspot/share/gc/parallel/mutableNUMASpace.cpp b/src/hotspot/share/gc/parallel/mutableNUMASpace.cpp index c5d112ffbc1..8b514fe7199 100644 --- a/src/hotspot/share/gc/parallel/mutableNUMASpace.cpp +++ b/src/hotspot/share/gc/parallel/mutableNUMASpace.cpp @@ -55,7 +55,7 @@ MutableNUMASpace::MutableNUMASpace(size_t page_size) : MutableSpace(page_size) { lgrp_spaces()->append(new LGRPSpace(lgrp_ids[i], page_size)); } - FREE_C_HEAP_ARRAY(uint, lgrp_ids); + FREE_C_HEAP_ARRAY(lgrp_ids); } MutableNUMASpace::~MutableNUMASpace() { diff --git a/src/hotspot/share/gc/shared/bufferNode.cpp b/src/hotspot/share/gc/shared/bufferNode.cpp index 90e50f52e84..855f872afab 100644 --- a/src/hotspot/share/gc/shared/bufferNode.cpp +++ b/src/hotspot/share/gc/shared/bufferNode.cpp @@ -41,7 +41,7 @@ void* BufferNode::AllocatorConfig::allocate() { void BufferNode::AllocatorConfig::deallocate(void* node) { assert(node != nullptr, "precondition"); - FREE_C_HEAP_ARRAY(char, node); + FREE_C_HEAP_ARRAY(node); } BufferNode::Allocator::Allocator(const char* name, size_t buffer_capacity) : diff --git a/src/hotspot/share/gc/shared/c1/barrierSetC1.cpp b/src/hotspot/share/gc/shared/c1/barrierSetC1.cpp index a31078f7e67..692893544d5 100644 --- a/src/hotspot/share/gc/shared/c1/barrierSetC1.cpp +++ b/src/hotspot/share/gc/shared/c1/barrierSetC1.cpp @@ -183,6 +183,7 @@ void BarrierSetC1::load_at_resolved(LIRAccess& access, LIR_Opr result) { bool needs_patching = (decorators & C1_NEEDS_PATCHING) != 0; bool mask_boolean = (decorators & C1_MASK_BOOLEAN) != 0; bool in_native = (decorators & IN_NATIVE) != 0; + bool needs_trailing_membar = is_volatile; if (support_IRIW_for_not_multiple_copy_atomic_cpu && is_volatile) { __ membar(); @@ -192,12 +193,15 @@ void BarrierSetC1::load_at_resolved(LIRAccess& access, LIR_Opr result) { if (in_native) { __ move_wide(access.resolved_addr()->as_address_ptr(), result); } else if ((is_volatile || needs_atomic) && !needs_patching) { + // volatile_field_load provides trailing membar semantics. + // Hence separate trailing membar is not needed. + needs_trailing_membar = false; gen->volatile_field_load(access.resolved_addr()->as_address_ptr(), result, access.access_emit_info()); } else { __ load(access.resolved_addr()->as_address_ptr(), result, access.access_emit_info(), patch_code); } - if (is_volatile) { + if (needs_trailing_membar) { __ membar_acquire(); } diff --git a/src/hotspot/share/gc/shared/classUnloadingContext.cpp b/src/hotspot/share/gc/shared/classUnloadingContext.cpp index 4eac2561e67..d2b4a2fc636 100644 --- a/src/hotspot/share/gc/shared/classUnloadingContext.cpp +++ b/src/hotspot/share/gc/shared/classUnloadingContext.cpp @@ -54,7 +54,7 @@ ClassUnloadingContext::~ClassUnloadingContext() { for (uint i = 0; i < _num_nmethod_unlink_workers; ++i) { delete _unlinked_nmethods[i]; } - FREE_C_HEAP_ARRAY(NMethodSet*, _unlinked_nmethods); + FREE_C_HEAP_ARRAY(_unlinked_nmethods); assert(_context == this, "context not set correctly"); _context = nullptr; diff --git a/src/hotspot/share/gc/shared/collectorCounters.cpp b/src/hotspot/share/gc/shared/collectorCounters.cpp index f01997f9854..1624c693470 100644 --- a/src/hotspot/share/gc/shared/collectorCounters.cpp +++ b/src/hotspot/share/gc/shared/collectorCounters.cpp @@ -62,7 +62,7 @@ CollectorCounters::CollectorCounters(const char* name, int ordinal) { } CollectorCounters::~CollectorCounters() { - FREE_C_HEAP_ARRAY(char, _name_space); + FREE_C_HEAP_ARRAY(_name_space); } TraceCollectorStats::TraceCollectorStats(CollectorCounters* c) : diff --git a/src/hotspot/share/gc/shared/gc_globals.hpp b/src/hotspot/share/gc/shared/gc_globals.hpp index c9102944197..1ff6fd493a7 100644 --- a/src/hotspot/share/gc/shared/gc_globals.hpp +++ b/src/hotspot/share/gc/shared/gc_globals.hpp @@ -262,10 +262,6 @@ "and ObjArrayMarkingStride.") \ constraint(ArrayMarkingMinStrideConstraintFunc,AfterErgo) \ \ - product(bool, AggressiveHeap, false, \ - "(Deprecated) Optimize heap options for long-running memory " \ - "intensive apps") \ - \ product(size_t, ErgoHeapSizeLimit, 0, \ "Maximum ergonomically set heap size (in bytes); zero means use " \ "(System RAM) * MaxRAMPercentage / 100") \ diff --git a/src/hotspot/share/gc/shared/generationCounters.cpp b/src/hotspot/share/gc/shared/generationCounters.cpp index f6bbc1c2618..85da4c99cbb 100644 --- a/src/hotspot/share/gc/shared/generationCounters.cpp +++ b/src/hotspot/share/gc/shared/generationCounters.cpp @@ -64,7 +64,7 @@ GenerationCounters::GenerationCounters(const char* name, } GenerationCounters::~GenerationCounters() { - FREE_C_HEAP_ARRAY(char, _name_space); + FREE_C_HEAP_ARRAY(_name_space); } void GenerationCounters::update_capacity(size_t curr_capacity) { diff --git a/src/hotspot/share/gc/shared/hSpaceCounters.cpp b/src/hotspot/share/gc/shared/hSpaceCounters.cpp index a873bc2f45c..5dd9d5bfaa8 100644 --- a/src/hotspot/share/gc/shared/hSpaceCounters.cpp +++ b/src/hotspot/share/gc/shared/hSpaceCounters.cpp @@ -66,7 +66,7 @@ HSpaceCounters::HSpaceCounters(const char* name_space, } HSpaceCounters::~HSpaceCounters() { - FREE_C_HEAP_ARRAY(char, _name_space); + FREE_C_HEAP_ARRAY(_name_space); } void HSpaceCounters::update_capacity(size_t v) { diff --git a/src/hotspot/share/gc/shared/oopStorage.cpp b/src/hotspot/share/gc/shared/oopStorage.cpp index 21e63f6fc32..8aea565cdf7 100644 --- a/src/hotspot/share/gc/shared/oopStorage.cpp +++ b/src/hotspot/share/gc/shared/oopStorage.cpp @@ -136,7 +136,7 @@ OopStorage::ActiveArray* OopStorage::ActiveArray::create(size_t size, void OopStorage::ActiveArray::destroy(ActiveArray* ba) { ba->~ActiveArray(); - FREE_C_HEAP_ARRAY(char, ba); + FREE_C_HEAP_ARRAY(ba); } size_t OopStorage::ActiveArray::size() const { @@ -362,7 +362,7 @@ OopStorage::Block* OopStorage::Block::new_block(const OopStorage* owner) { void OopStorage::Block::delete_block(const Block& block) { void* memory = block._memory; block.Block::~Block(); - FREE_C_HEAP_ARRAY(char, memory); + FREE_C_HEAP_ARRAY(memory); } // This can return a false positive if ptr is not contained by some diff --git a/src/hotspot/share/gc/shared/partialArrayState.cpp b/src/hotspot/share/gc/shared/partialArrayState.cpp index d3b21c2fdaa..4679ac2f51c 100644 --- a/src/hotspot/share/gc/shared/partialArrayState.cpp +++ b/src/hotspot/share/gc/shared/partialArrayState.cpp @@ -114,7 +114,7 @@ PartialArrayStateManager::PartialArrayStateManager(uint max_allocators) PartialArrayStateManager::~PartialArrayStateManager() { reset(); - FREE_C_HEAP_ARRAY(Arena, _arenas); + FREE_C_HEAP_ARRAY(_arenas); } Arena* PartialArrayStateManager::register_allocator() { diff --git a/src/hotspot/share/gc/shared/preservedMarks.cpp b/src/hotspot/share/gc/shared/preservedMarks.cpp index 605b7afe072..6a69fe10f95 100644 --- a/src/hotspot/share/gc/shared/preservedMarks.cpp +++ b/src/hotspot/share/gc/shared/preservedMarks.cpp @@ -148,7 +148,7 @@ void PreservedMarksSet::reclaim() { } if (_in_c_heap) { - FREE_C_HEAP_ARRAY(Padded, _stacks); + FREE_C_HEAP_ARRAY(_stacks); } else { // the array was resource-allocated, so nothing to do } diff --git a/src/hotspot/share/gc/shared/stringdedup/stringDedup.cpp b/src/hotspot/share/gc/shared/stringdedup/stringDedup.cpp index b3f96da1cce..ab1b15b0447 100644 --- a/src/hotspot/share/gc/shared/stringdedup/stringDedup.cpp +++ b/src/hotspot/share/gc/shared/stringdedup/stringDedup.cpp @@ -182,7 +182,7 @@ void StringDedup::Requests::flush() { assert(_storage_for_requests != nullptr, "invariant"); _storage_for_requests->storage()->release(_buffer, _index); } - FREE_C_HEAP_ARRAY(oop*, _buffer); + FREE_C_HEAP_ARRAY(_buffer); _buffer = nullptr; } if (_storage_for_requests != nullptr) { diff --git a/src/hotspot/share/gc/shared/stringdedup/stringDedupTable.cpp b/src/hotspot/share/gc/shared/stringdedup/stringDedupTable.cpp index a376f3b96de..546efa4774b 100644 --- a/src/hotspot/share/gc/shared/stringdedup/stringDedupTable.cpp +++ b/src/hotspot/share/gc/shared/stringdedup/stringDedupTable.cpp @@ -455,7 +455,7 @@ void StringDedup::Table::free_buckets(Bucket* buckets, size_t number_of_buckets) while (number_of_buckets > 0) { buckets[--number_of_buckets].~Bucket(); } - FREE_C_HEAP_ARRAY(Bucket, buckets); + FREE_C_HEAP_ARRAY(buckets); } // Compute the hash code for obj using halfsiphash_32. As this is a high diff --git a/src/hotspot/share/gc/shared/taskqueue.inline.hpp b/src/hotspot/share/gc/shared/taskqueue.inline.hpp index b142aadc580..c942b6cc3e9 100644 --- a/src/hotspot/share/gc/shared/taskqueue.inline.hpp +++ b/src/hotspot/share/gc/shared/taskqueue.inline.hpp @@ -48,7 +48,7 @@ inline GenericTaskQueueSet::GenericTaskQueueSet(uint n) : _n(n) { template inline GenericTaskQueueSet::~GenericTaskQueueSet() { - FREE_C_HEAP_ARRAY(T*, _queues); + FREE_C_HEAP_ARRAY(_queues); } #if TASKQUEUE_STATS diff --git a/src/hotspot/share/gc/shared/threadLocalAllocBuffer.cpp b/src/hotspot/share/gc/shared/threadLocalAllocBuffer.cpp index f9b8694eb04..59d7befb32d 100644 --- a/src/hotspot/share/gc/shared/threadLocalAllocBuffer.cpp +++ b/src/hotspot/share/gc/shared/threadLocalAllocBuffer.cpp @@ -58,7 +58,11 @@ ThreadLocalAllocBuffer::ThreadLocalAllocBuffer() : // do nothing. TLABs must be inited by initialize() calls } -size_t ThreadLocalAllocBuffer::initial_refill_waste_limit() { return desired_size() / TLABRefillWasteFraction; } +size_t ThreadLocalAllocBuffer::initial_refill_waste_limit() { + assert(TLABRefillWasteFraction != 0, "inv"); + return desired_size() / TLABRefillWasteFraction; +} + size_t ThreadLocalAllocBuffer::min_size() { return align_object_size(MinTLABSize / HeapWordSize) + alignment_reserve(); } size_t ThreadLocalAllocBuffer::refill_waste_limit_increment() { return TLABWasteIncrement; } diff --git a/src/hotspot/share/gc/shared/workerDataArray.inline.hpp b/src/hotspot/share/gc/shared/workerDataArray.inline.hpp index 34549bc079e..3b7658ec4c8 100644 --- a/src/hotspot/share/gc/shared/workerDataArray.inline.hpp +++ b/src/hotspot/share/gc/shared/workerDataArray.inline.hpp @@ -72,7 +72,7 @@ WorkerDataArray::~WorkerDataArray() { for (uint i = 0; i < MaxThreadWorkItems; i++) { delete _thread_work_items[i]; } - FREE_C_HEAP_ARRAY(T, _data); + FREE_C_HEAP_ARRAY(_data); } template diff --git a/src/hotspot/share/gc/shared/workerUtils.cpp b/src/hotspot/share/gc/shared/workerUtils.cpp index 1826b9d7df8..736a9b007dd 100644 --- a/src/hotspot/share/gc/shared/workerUtils.cpp +++ b/src/hotspot/share/gc/shared/workerUtils.cpp @@ -122,7 +122,7 @@ bool SubTasksDone::try_claim_task(uint t) { SubTasksDone::~SubTasksDone() { assert(_verification_done.load_relaxed(), "all_tasks_claimed must have been called."); - FREE_C_HEAP_ARRAY(Atomic, _tasks); + FREE_C_HEAP_ARRAY(_tasks); } // *** SequentialSubTasksDone diff --git a/src/hotspot/share/gc/shenandoah/c2/shenandoahBarrierSetC2.cpp b/src/hotspot/share/gc/shenandoah/c2/shenandoahBarrierSetC2.cpp index f721c3cd001..4fcc90d7bde 100644 --- a/src/hotspot/share/gc/shenandoah/c2/shenandoahBarrierSetC2.cpp +++ b/src/hotspot/share/gc/shenandoah/c2/shenandoahBarrierSetC2.cpp @@ -73,7 +73,7 @@ void ShenandoahBarrierSetC2State::remove_load_reference_barrier(ShenandoahLoadRe #define __ kit-> -bool ShenandoahBarrierSetC2::satb_can_remove_pre_barrier(GraphKit* kit, PhaseValues* phase, Node* adr, +bool ShenandoahBarrierSetC2::satb_can_remove_pre_barrier(GraphKit* kit, PhaseGVN* phase, Node* adr, BasicType bt, uint adr_idx) const { intptr_t offset = 0; Node* base = AddPNode::Ideal_base_and_offset(adr, phase, offset); diff --git a/src/hotspot/share/gc/shenandoah/c2/shenandoahBarrierSetC2.hpp b/src/hotspot/share/gc/shenandoah/c2/shenandoahBarrierSetC2.hpp index 108eaa0998b..c77a9da63fc 100644 --- a/src/hotspot/share/gc/shenandoah/c2/shenandoahBarrierSetC2.hpp +++ b/src/hotspot/share/gc/shenandoah/c2/shenandoahBarrierSetC2.hpp @@ -46,7 +46,7 @@ class ShenandoahBarrierSetC2 : public BarrierSetC2 { private: void shenandoah_eliminate_wb_pre(Node* call, PhaseIterGVN* igvn) const; - bool satb_can_remove_pre_barrier(GraphKit* kit, PhaseValues* phase, Node* adr, + bool satb_can_remove_pre_barrier(GraphKit* kit, PhaseGVN* phase, Node* adr, BasicType bt, uint adr_idx) const; void satb_write_barrier_pre(GraphKit* kit, bool do_load, Node* obj, diff --git a/src/hotspot/share/gc/shenandoah/heuristics/shenandoahAdaptiveHeuristics.cpp b/src/hotspot/share/gc/shenandoah/heuristics/shenandoahAdaptiveHeuristics.cpp index c595d1fd9cd..ce74e8cf199 100644 --- a/src/hotspot/share/gc/shenandoah/heuristics/shenandoahAdaptiveHeuristics.cpp +++ b/src/hotspot/share/gc/shenandoah/heuristics/shenandoahAdaptiveHeuristics.cpp @@ -111,12 +111,12 @@ ShenandoahAdaptiveHeuristics::ShenandoahAdaptiveHeuristics(ShenandoahSpaceInfo* } ShenandoahAdaptiveHeuristics::~ShenandoahAdaptiveHeuristics() { - FREE_C_HEAP_ARRAY(double, _spike_acceleration_rate_samples); - FREE_C_HEAP_ARRAY(double, _spike_acceleration_rate_timestamps); - FREE_C_HEAP_ARRAY(double, _gc_time_timestamps); - FREE_C_HEAP_ARRAY(double, _gc_time_samples); - FREE_C_HEAP_ARRAY(double, _gc_time_xy); - FREE_C_HEAP_ARRAY(double, _gc_time_xx); + FREE_C_HEAP_ARRAY(_spike_acceleration_rate_samples); + FREE_C_HEAP_ARRAY(_spike_acceleration_rate_timestamps); + FREE_C_HEAP_ARRAY(_gc_time_timestamps); + FREE_C_HEAP_ARRAY(_gc_time_samples); + FREE_C_HEAP_ARRAY(_gc_time_xy); + FREE_C_HEAP_ARRAY(_gc_time_xx); } void ShenandoahAdaptiveHeuristics::initialize() { @@ -428,9 +428,7 @@ bool ShenandoahAdaptiveHeuristics::should_start_gc() { double predicted_future_gc_time = 0; double future_planned_gc_time = 0; bool future_planned_gc_time_is_average = false; - double avg_time_to_deplete_available = 0.0; bool is_spiking = false; - double spike_time_to_deplete_available = 0.0; log_debug(gc, ergo)("should_start_gc calculation: available: " PROPERFMT ", soft_max_capacity: " PROPERFMT ", " "allocated_since_gc_start: " PROPERFMT, @@ -650,9 +648,8 @@ bool ShenandoahAdaptiveHeuristics::should_start_gc() { _space_info->name(), avg_cycle_time * 1000, predicted_future_gc_time * 1000, byte_size_in_proper_unit(avg_alloc_rate), proper_unit_for_byte_size(avg_alloc_rate)); size_t allocatable_bytes = allocatable_words * HeapWordSize; - avg_time_to_deplete_available = allocatable_bytes / avg_alloc_rate; - if (future_planned_gc_time > avg_time_to_deplete_available) { + if (future_planned_gc_time * avg_alloc_rate > allocatable_bytes) { log_trigger("%s GC time (%.2f ms) is above the time for average allocation rate (%.0f %sB/s)" " to deplete free headroom (%zu%s) (margin of error = %.2f)", future_planned_gc_time_is_average? "Average": "Linear prediction of", future_planned_gc_time * 1000, @@ -675,8 +672,7 @@ bool ShenandoahAdaptiveHeuristics::should_start_gc() { } is_spiking = _allocation_rate.is_spiking(rate, _spike_threshold_sd); - spike_time_to_deplete_available = (rate == 0)? 0: allocatable_bytes / rate; - if (is_spiking && (rate != 0) && (future_planned_gc_time > spike_time_to_deplete_available)) { + if (is_spiking && (future_planned_gc_time * rate > allocatable_bytes)) { log_trigger("%s GC time (%.2f ms) is above the time for instantaneous allocation rate (%.0f %sB/s)" " to deplete free headroom (%zu%s) (spike threshold = %.2f)", future_planned_gc_time_is_average? "Average": "Linear prediction of", future_planned_gc_time * 1000, @@ -837,19 +833,29 @@ double ShenandoahAllocationRate::force_sample(size_t allocated, size_t &unaccoun const double MinSampleTime = 0.002; // Do not sample if time since last update is less than 2 ms double now = os::elapsedTime(); double time_since_last_update = now - _last_sample_time; + double rate = 0.0; if (time_since_last_update < MinSampleTime) { + // If we choose not to sample right now, the unaccounted_bytes_allocated will be added + // into the next sample taken. These unaccounted_bytes_allocated will be added to + // any additional bytes that are allocated during this GC cycle at the time the rate is + // next sampled. We do not overwrite _last_sample_time on this path, because the + // unaccounted_bytes_allocated were allocated following _last_sample_time. unaccounted_bytes_allocated = allocated - _last_sample_value; - _last_sample_value = 0; - return 0.0; } else { - double rate = instantaneous_rate(now, allocated); + rate = instantaneous_rate(now, allocated); _rate.add(rate); _rate_avg.add(_rate.avg()); _last_sample_time = now; - _last_sample_value = allocated; unaccounted_bytes_allocated = 0; - return rate; } + // force_sample() is called when resetting bytes allocated since gc start. All subsequent + // requests to sample allocated bytes during this GC cycle are measured as a delta from + // _last_sample_value. In the case that we choose not to sample now, we will count the + // unaccounted_bytes_allocated as if they were allocated following the start of this GC + // cycle (but the time span over which these bytes were allocated begins at + // _last_sample_time, which we do not overwrite). + _last_sample_value = 0; + return rate; } double ShenandoahAllocationRate::sample(size_t allocated) { @@ -898,9 +904,7 @@ bool ShenandoahAllocationRate::is_spiking(double rate, double threshold) const { } double ShenandoahAllocationRate::instantaneous_rate(double time, size_t allocated) const { - size_t last_value = _last_sample_value; - double last_time = _last_sample_time; - size_t allocation_delta = (allocated > last_value) ? (allocated - last_value) : 0; - double time_delta_sec = time - last_time; - return (time_delta_sec > 0) ? (allocation_delta / time_delta_sec) : 0; + assert(allocated >= _last_sample_value, "Must be"); + assert(time > _last_sample_time, "Must be"); + return (allocated - _last_sample_value) / (time - _last_sample_time); } diff --git a/src/hotspot/share/gc/shenandoah/heuristics/shenandoahGenerationalHeuristics.cpp b/src/hotspot/share/gc/shenandoah/heuristics/shenandoahGenerationalHeuristics.cpp index 594367e2972..840459288c3 100644 --- a/src/hotspot/share/gc/shenandoah/heuristics/shenandoahGenerationalHeuristics.cpp +++ b/src/hotspot/share/gc/shenandoah/heuristics/shenandoahGenerationalHeuristics.cpp @@ -91,19 +91,6 @@ void ShenandoahGenerationalHeuristics::choose_collection_set_from_regiondata(She heap->shenandoah_policy()->record_mixed_cycle(); } - if (_generation->is_global()) { - // We have just chosen a collection set for a global cycle. The mark bitmap covering old regions is complete, so - // the remembered set scan can use that to avoid walking into garbage. When the next old mark begins, we will - // use the mark bitmap to make the old regions parsable by coalescing and filling any unmarked objects. Thus, - // we prepare for old collections by remembering which regions are old at this time. Note that any objects - // promoted into old regions will be above TAMS, and so will be considered marked. However, free regions that - // become old after this point will not be covered correctly by the mark bitmap, so we must be careful not to - // coalesce those regions. Only the old regions which are not part of the collection set at this point are - // eligible for coalescing. As implemented now, this has the side effect of possibly initiating mixed-evacuations - // after a global cycle for old regions that were not included in this collection set. - heap->old_generation()->transition_old_generation_after_global_gc(); - } - ShenandoahTracer::report_promotion_info(collection_set, in_place_promotions.humongous_region_stats().count, in_place_promotions.humongous_region_stats().garbage, diff --git a/src/hotspot/share/gc/shenandoah/heuristics/shenandoahHeuristics.cpp b/src/hotspot/share/gc/shenandoah/heuristics/shenandoahHeuristics.cpp index 3091b19b600..d2010d921b1 100644 --- a/src/hotspot/share/gc/shenandoah/heuristics/shenandoahHeuristics.cpp +++ b/src/hotspot/share/gc/shenandoah/heuristics/shenandoahHeuristics.cpp @@ -73,7 +73,7 @@ ShenandoahHeuristics::ShenandoahHeuristics(ShenandoahSpaceInfo* space_info) : } ShenandoahHeuristics::~ShenandoahHeuristics() { - FREE_C_HEAP_ARRAY(RegionGarbage, _region_data); + FREE_C_HEAP_ARRAY(_region_data); } void ShenandoahHeuristics::choose_collection_set(ShenandoahCollectionSet* collection_set) { diff --git a/src/hotspot/share/gc/shenandoah/shenandoahAgeCensus.cpp b/src/hotspot/share/gc/shenandoah/shenandoahAgeCensus.cpp index a81efa99d70..4989c929b32 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahAgeCensus.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahAgeCensus.cpp @@ -70,15 +70,15 @@ ShenandoahAgeCensus::~ShenandoahAgeCensus() { for (uint i = 0; i < MAX_SNAPSHOTS; i++) { delete _global_age_tables[i]; } - FREE_C_HEAP_ARRAY(AgeTable*, _global_age_tables); - FREE_C_HEAP_ARRAY(uint, _tenuring_threshold); - CENSUS_NOISE(FREE_C_HEAP_ARRAY(ShenandoahNoiseStats, _global_noise)); + FREE_C_HEAP_ARRAY(_global_age_tables); + FREE_C_HEAP_ARRAY(_tenuring_threshold); + CENSUS_NOISE(FREE_C_HEAP_ARRAY(_global_noise)); if (_local_age_tables) { for (uint i = 0; i < _max_workers; i++) { delete _local_age_tables[i]; } - FREE_C_HEAP_ARRAY(AgeTable*, _local_age_tables); - CENSUS_NOISE(FREE_C_HEAP_ARRAY(ShenandoahNoiseStats, _local_noise)); + FREE_C_HEAP_ARRAY(_local_age_tables); + CENSUS_NOISE(FREE_C_HEAP_ARRAY(_local_noise)); } } diff --git a/src/hotspot/share/gc/shenandoah/shenandoahArguments.cpp b/src/hotspot/share/gc/shenandoah/shenandoahArguments.cpp index e9d6a686694..095fb8f42f4 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahArguments.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahArguments.cpp @@ -207,7 +207,8 @@ void ShenandoahArguments::initialize() { } size_t ShenandoahArguments::conservative_max_heap_alignment() { - size_t align = next_power_of_2(ShenandoahMaxRegionSize); + static_assert(is_power_of_2(ShenandoahHeapRegion::MAX_REGION_SIZE), "Max region size must be a power of 2."); + size_t align = ShenandoahHeapRegion::MAX_REGION_SIZE; if (UseLargePages) { align = MAX2(align, os::large_page_size()); } diff --git a/src/hotspot/share/gc/shenandoah/shenandoahBarrierSet.hpp b/src/hotspot/share/gc/shenandoah/shenandoahBarrierSet.hpp index e7a0ed57740..06e16af24c6 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahBarrierSet.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahBarrierSet.hpp @@ -96,7 +96,6 @@ public: void on_thread_detach(Thread* thread) override; static inline oop resolve_forwarded_not_null(oop p); - static inline oop resolve_forwarded_not_null_mutator(oop p); static inline oop resolve_forwarded(oop p); template @@ -109,7 +108,7 @@ public: inline oop load_reference_barrier(oop obj); - template + template inline oop load_reference_barrier_mutator(oop obj, T* load_addr); template diff --git a/src/hotspot/share/gc/shenandoah/shenandoahBarrierSet.inline.hpp b/src/hotspot/share/gc/shenandoah/shenandoahBarrierSet.inline.hpp index f4b35e29b09..97e2af1714d 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahBarrierSet.inline.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahBarrierSet.inline.hpp @@ -56,16 +56,49 @@ inline oop ShenandoahBarrierSet::resolve_forwarded(oop p) { } } -inline oop ShenandoahBarrierSet::resolve_forwarded_not_null_mutator(oop p) { - return ShenandoahForwarding::get_forwardee_mutator(p); -} - -template +template inline oop ShenandoahBarrierSet::load_reference_barrier_mutator(oop obj, T* load_addr) { - assert(ShenandoahLoadRefBarrier, "should be enabled"); - shenandoah_assert_in_cset(load_addr, obj); + assert(ShenandoahLoadRefBarrier, "Should be enabled"); - oop fwd = resolve_forwarded_not_null_mutator(obj); + constexpr bool on_weak = HasDecorator::value; + constexpr bool on_phantom = HasDecorator::value; + + // Handle nulls. Strong loads filtered nulls with cset checks. + // Weak/phantom loads need to check for nulls here. + if (on_weak || on_phantom) { + if (obj == nullptr) { + return nullptr; + } + } else { + assert(obj != nullptr, "Should have been filtered before"); + } + + // Prevent resurrection of unreachable phantom (i.e. weak-native) references. + if (on_phantom && + _heap->is_concurrent_weak_root_in_progress() && + _heap->is_in_active_generation(obj) && + !_heap->marking_context()->is_marked(obj)) { + return nullptr; + } + + // Prevent resurrection of unreachable weak references. + if (on_weak && + _heap->is_concurrent_weak_root_in_progress() && + _heap->is_in_active_generation(obj) && + !_heap->marking_context()->is_marked_strong(obj)) { + return nullptr; + } + + // Weak/phantom loads need additional cset check. + if (on_phantom || on_weak) { + if (!_heap->has_forwarded_objects() || !_heap->in_collection_set(obj)) { + return obj; + } + } else { + shenandoah_assert_in_cset(load_addr, obj); + } + + oop fwd = ShenandoahForwarding::get_forwardee_mutator(obj); if (obj == fwd) { assert(_heap->is_evacuation_in_progress(), "evac should be in progress"); Thread* const t = Thread::current(); diff --git a/src/hotspot/share/gc/shenandoah/shenandoahConcurrentMark.cpp b/src/hotspot/share/gc/shenandoah/shenandoahConcurrentMark.cpp index 367a15abfa4..fb716aef21e 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahConcurrentMark.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahConcurrentMark.cpp @@ -300,7 +300,11 @@ void ShenandoahConcurrentMark::finish_mark_work() { default: ShouldNotReachHere(); } - + if (!generation()->is_old() && heap->is_concurrent_young_mark_in_progress()) { + // Lastly, ensure all the invisible roots are marked. + ShenandoahInvisibleRootsMarkClosure cl; + Threads::java_threads_do(&cl); + } assert(task_queues()->is_empty(), "Should be empty"); } diff --git a/src/hotspot/share/gc/shenandoah/shenandoahEvacOOMHandler.cpp b/src/hotspot/share/gc/shenandoah/shenandoahEvacOOMHandler.cpp index 5b24140ac1c..cf5386e027e 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahEvacOOMHandler.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahEvacOOMHandler.cpp @@ -184,3 +184,7 @@ void ShenandoahEvacOOMHandler::clear() { _threads_in_evac[i].clear(); } } + +bool ShenandoahEvacOOMHandler::is_active() { + return ShenandoahThreadLocalData::evac_oom_scope_level(Thread::current()) > 0; +} diff --git a/src/hotspot/share/gc/shenandoah/shenandoahEvacOOMHandler.hpp b/src/hotspot/share/gc/shenandoah/shenandoahEvacOOMHandler.hpp index 3e28d9ac88e..068a4081e83 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahEvacOOMHandler.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahEvacOOMHandler.hpp @@ -147,6 +147,11 @@ public: void clear(); + /** + * Returns true if current thread is in evacuation OOM protocol. + */ + static bool is_active(); + private: // Register/Unregister thread to evacuation OOM protocol void register_thread(Thread* t); diff --git a/src/hotspot/share/gc/shenandoah/shenandoahFreeSet.hpp b/src/hotspot/share/gc/shenandoah/shenandoahFreeSet.hpp index eeff0fde87c..f7ba1f05f47 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahFreeSet.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahFreeSet.hpp @@ -680,32 +680,18 @@ public: } inline size_t get_bytes_allocated_since_previous_sample() { - size_t total_bytes = get_total_bytes_allocated(); - size_t result; - if (total_bytes < _mutator_bytes_at_last_sample) { - // This rare condition may occur if bytes allocated overflows (wraps around) size_t tally of allocations. - // This may also occur in the very rare situation that get_total_bytes_allocated() is queried in the middle of - // reset_bytes_allocated_since_gc_start(). Note that there is no lock to assure that the two global variables - // it modifies are modified atomically (_total_bytes_previously_allocated and _mutator_byts_allocated_since_gc_start) - // This has been observed to occur when an out-of-cycle degenerated cycle is starting (and thus calls - // reset_bytes_allocated_since_gc_start()) at the same time that the control (non-generational mode) or - // regulator (generational-mode) thread calls should_start_gc() (which invokes get_bytes_allocated_since_previous_sample()). - // - // Handle this rare situation by responding with the "innocent" value 0 and resetting internal state so that the - // the next query can recalibrate. - result = 0; - } else { - // Note: there's always the possibility that the tally of total allocations exceeds the 64-bit capacity of our size_t - // counter. We assume that the difference between relevant samples does not exceed this count. Example: - // Suppose _mutator_words_at_last_sample is 0xffff_ffff_ffff_fff0 (18,446,744,073,709,551,600 Decimal) - // and _total_words is 0x0000_0000_0000_0800 ( 32,768 Decimal) - // Then, total_words - _mutator_words_at_last_sample can be done adding 1's complement of subtrahend: - // 1's complement of _mutator_words_at_last_sample is: 0x0000_0000_0000_0010 ( 16 Decimal)) - // plus total_words: 0x0000_0000_0000_0800 (32,768 Decimal) - // sum: 0x0000_0000_0000_0810 (32,784 Decimal) - result = total_bytes - _mutator_bytes_at_last_sample; - } - _mutator_bytes_at_last_sample = total_bytes; + const size_t total_bytes_allocated = get_total_bytes_allocated(); + // total_bytes_allocated could overflow (wraps around) size_t in rare condition, we are relying on + // wrap-around arithmetic of size_t type to produce meaningful result when total_bytes_allocated overflows + // its 64-bit counter. The expression below is equivalent to code: + // if (total_bytes < _mutator_bytes_at_last_sample) { + // // overflow + // return total_bytes + (SIZE_T_MAX - _mutator_bytes_at_last_sample) + 1; + // } else { + // return total_bytes - _mutator_bytes_at_last_sample; + // } + const size_t result = total_bytes_allocated - _mutator_bytes_at_last_sample; + _mutator_bytes_at_last_sample = total_bytes_allocated; return result; } diff --git a/src/hotspot/share/gc/shenandoah/shenandoahFullGC.cpp b/src/hotspot/share/gc/shenandoah/shenandoahFullGC.cpp index 21b1fd9e0a8..34092a744d5 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahFullGC.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahFullGC.cpp @@ -261,7 +261,7 @@ void ShenandoahFullGC::do_it(GCCause::Cause gc_cause) { for (uint i = 0; i < heap->max_workers(); i++) { delete worker_slices[i]; } - FREE_C_HEAP_ARRAY(ShenandoahHeapRegionSet*, worker_slices); + FREE_C_HEAP_ARRAY(worker_slices); heap->set_full_gc_move_in_progress(false); heap->set_full_gc_in_progress(false); @@ -688,7 +688,7 @@ void ShenandoahFullGC::distribute_slices(ShenandoahHeapRegionSet** worker_slices } } - FREE_C_HEAP_ARRAY(size_t, live); + FREE_C_HEAP_ARRAY(live); #ifdef ASSERT ResourceBitMap map(n_regions); diff --git a/src/hotspot/share/gc/shenandoah/shenandoahGeneration.cpp b/src/hotspot/share/gc/shenandoah/shenandoahGeneration.cpp index 5b26ee67653..493736f4194 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahGeneration.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahGeneration.cpp @@ -284,15 +284,6 @@ void ShenandoahGeneration::prepare_regions_and_collection_set(bool concurrent) { // along with the census done during marking, and compute the tenuring threshold. ShenandoahAgeCensus* census = ShenandoahGenerationalHeap::heap()->age_census(); census->update_census(age0_pop); -#ifndef PRODUCT - size_t total_pop = age0_cl.get_total_population(); - size_t total_census = census->get_total(); - // Usually total_pop > total_census, but not by too much. - // We use integer division so anything up to just less than 2 is considered - // reasonable, and the "+1" is to avoid divide-by-zero. - assert((total_pop+1)/(total_census+1) == 1, "Extreme divergence: " - "%zu/%zu", total_pop, total_census); -#endif } { @@ -303,8 +294,20 @@ void ShenandoahGeneration::prepare_regions_and_collection_set(bool concurrent) { ShenandoahHeapLocker locker(heap->lock()); heap->assert_pinned_region_status(this); _heuristics->choose_collection_set(collection_set); - } + if (is_generational && is_global()) { + // We have finished marking the entire heap. The mark bitmap covering old regions is complete, so + // the remembered set scan can use that to avoid walking into garbage. When the next old mark begins, we will + // use the mark bitmap to make the old regions parsable by coalescing and filling any unmarked objects. Thus, + // we prepare for old collections by remembering which regions are old at this time. Note that any objects + // promoted into old regions will be above TAMS, and so will be considered marked. However, free regions that + // become old after this point will not be covered correctly by the mark bitmap, so we must be careful not to + // coalesce those regions. Only the old regions which are not part of the collection set at this point are + // eligible for coalescing. As implemented now, this has the side effect of possibly initiating mixed-evacuations + // after a global cycle for old regions that were not included in this collection set. + heap->old_generation()->transition_old_generation_after_global_gc(); + } + } { ShenandoahGCPhase phase(concurrent ? ShenandoahPhaseTimings::final_rebuild_freeset : diff --git a/src/hotspot/share/gc/shenandoah/shenandoahGenerationalEvacuationTask.cpp b/src/hotspot/share/gc/shenandoah/shenandoahGenerationalEvacuationTask.cpp index ca15c6db443..4963d0c96ab 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahGenerationalEvacuationTask.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahGenerationalEvacuationTask.cpp @@ -78,7 +78,6 @@ void ShenandoahGenerationalEvacuationTask::do_work() { promote_regions(); } else { assert(!_heap->collection_set()->is_empty(), "Should have a collection set here"); - ShenandoahEvacOOMScope oom_evac_scope; evacuate_and_promote_regions(); } } @@ -123,6 +122,7 @@ void ShenandoahGenerationalEvacuationTask::evacuate_and_promote_regions() { if (r->is_cset()) { assert(r->has_live(), "Region %zu should have been reclaimed early", r->index()); + ShenandoahEvacOOMScope oom_evac_scope; _heap->marked_object_iterate(r, &cl); } else { promoter.maybe_promote_region(r); diff --git a/src/hotspot/share/gc/shenandoah/shenandoahHeap.cpp b/src/hotspot/share/gc/shenandoah/shenandoahHeap.cpp index 4b01ea1cd52..281db223def 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahHeap.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahHeap.cpp @@ -62,6 +62,7 @@ #include "gc/shenandoah/shenandoahMarkingContext.inline.hpp" #include "gc/shenandoah/shenandoahMemoryPool.hpp" #include "gc/shenandoah/shenandoahMonitoringSupport.hpp" +#include "gc/shenandoah/shenandoahObjArrayAllocator.hpp" #include "gc/shenandoah/shenandoahOldGeneration.hpp" #include "gc/shenandoah/shenandoahPadding.hpp" #include "gc/shenandoah/shenandoahParallelCleaning.inline.hpp" @@ -1073,6 +1074,11 @@ HeapWord* ShenandoahHeap::mem_allocate(size_t size) { return allocate_memory(req); } +oop ShenandoahHeap::array_allocate(Klass* klass, size_t size, int length, bool do_zero, TRAPS) { + ShenandoahObjArrayAllocator allocator(klass, size, length, do_zero, THREAD); + return allocator.allocate(); +} + MetaWord* ShenandoahHeap::satisfy_failed_metadata_allocation(ClassLoaderData* loader_data, size_t size, Metaspace::MetadataType mdtype) { @@ -1144,11 +1150,9 @@ public: if (_concurrent) { ShenandoahConcurrentWorkerSession worker_session(worker_id); ShenandoahSuspendibleThreadSetJoiner stsj; - ShenandoahEvacOOMScope oom_evac_scope; do_work(); } else { ShenandoahParallelWorkerSession worker_session(worker_id); - ShenandoahEvacOOMScope oom_evac_scope; do_work(); } } @@ -1159,7 +1163,10 @@ private: ShenandoahHeapRegion* r; while ((r =_cs->claim_next()) != nullptr) { assert(r->has_live(), "Region %zu should have been reclaimed early", r->index()); - _sh->marked_object_iterate(r, &cl); + { + ShenandoahEvacOOMScope oom_evac_scope; + _sh->marked_object_iterate(r, &cl); + } if (_sh->check_cancelled_gc_and_yield(_concurrent)) { break; @@ -2279,6 +2286,11 @@ void ShenandoahHeap::stw_unload_classes(bool full_gc) { } // Resize and verify metaspace MetaspaceGC::compute_new_size(); + + if (mode()->is_generational()) { + old_generation()->set_parsable(false); + } + DEBUG_ONLY(MetaspaceUtils::verify();) } @@ -2345,24 +2357,23 @@ address ShenandoahHeap::in_cset_fast_test_addr() { void ShenandoahHeap::reset_bytes_allocated_since_gc_start() { // It is important to force_alloc_rate_sample() before the associated generation's bytes_allocated has been reset. - // Note that there is no lock to prevent additional alloations between sampling bytes_allocated_since_gc_start() and - // reset_bytes_allocated_since_gc_start(). If additional allocations happen, they will be ignored in the average - // allocation rate computations. This effect is considered to be be negligible. - - // unaccounted_bytes is the bytes not accounted for by our forced sample. If the sample interval is too short, - // the "forced sample" will not happen, and any recently allocated bytes are "unaccounted for". We pretend these - // bytes are allocated after the start of subsequent gc. - size_t unaccounted_bytes; - ShenandoahFreeSet* _free_set = free_set(); - size_t bytes_allocated = _free_set->get_bytes_allocated_since_gc_start(); - if (mode()->is_generational()) { - unaccounted_bytes = young_generation()->heuristics()->force_alloc_rate_sample(bytes_allocated); - } else { - // Single-gen Shenandoah uses global heuristics. - unaccounted_bytes = heuristics()->force_alloc_rate_sample(bytes_allocated); + // Note that we obtain heap lock to prevent additional allocations between sampling bytes_allocated_since_gc_start() + // and reset_bytes_allocated_since_gc_start() + { + ShenandoahHeapLocker locker(lock()); + // unaccounted_bytes is the bytes not accounted for by our forced sample. If the sample interval is too short, + // the "forced sample" will not happen, and any recently allocated bytes are "unaccounted for". We pretend these + // bytes are allocated after the start of subsequent gc. + size_t unaccounted_bytes; + size_t bytes_allocated = _free_set->get_bytes_allocated_since_gc_start(); + if (mode()->is_generational()) { + unaccounted_bytes = young_generation()->heuristics()->force_alloc_rate_sample(bytes_allocated); + } else { + // Single-gen Shenandoah uses global heuristics. + unaccounted_bytes = heuristics()->force_alloc_rate_sample(bytes_allocated); + } + _free_set->reset_bytes_allocated_since_gc_start(unaccounted_bytes); } - ShenandoahHeapLocker locker(lock()); - _free_set->reset_bytes_allocated_since_gc_start(unaccounted_bytes); } void ShenandoahHeap::set_degenerated_gc_in_progress(bool in_progress) { diff --git a/src/hotspot/share/gc/shenandoah/shenandoahHeap.hpp b/src/hotspot/share/gc/shenandoah/shenandoahHeap.hpp index bed26a093d0..be40220e40f 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahHeap.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahHeap.hpp @@ -709,6 +709,7 @@ private: public: HeapWord* allocate_memory(ShenandoahAllocRequest& request); HeapWord* mem_allocate(size_t size) override; + oop array_allocate(Klass* klass, size_t size, int length, bool do_zero, TRAPS) override; MetaWord* satisfy_failed_metadata_allocation(ClassLoaderData* loader_data, size_t size, Metaspace::MetadataType mdtype) override; diff --git a/src/hotspot/share/gc/shenandoah/shenandoahHeap.inline.hpp b/src/hotspot/share/gc/shenandoah/shenandoahHeap.inline.hpp index 6d77cccaa6a..ce5b821b73c 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahHeap.inline.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahHeap.inline.hpp @@ -258,6 +258,7 @@ inline bool ShenandoahHeap::cancelled_gc() const { inline bool ShenandoahHeap::check_cancelled_gc_and_yield(bool sts_active) { if (sts_active && !cancelled_gc()) { + assert(!ShenandoahEvacOOMHandler::is_active(), "Potential deadlock: cannot yield while OOM evac handler is active"); if (SuspendibleThreadSet::should_yield()) { SuspendibleThreadSet::yield(); } diff --git a/src/hotspot/share/gc/shenandoah/shenandoahHeapRegion.cpp b/src/hotspot/share/gc/shenandoah/shenandoahHeapRegion.cpp index c031569b7c6..5c3f40775ca 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahHeapRegion.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahHeapRegion.cpp @@ -577,7 +577,7 @@ void ShenandoahHeapRegion::recycle_internal() { } if (ZapUnusedHeapArea) { - SpaceMangler::mangle_region(MemRegion(bottom(), end())); + SpaceMangler::mangle_region(MemRegion(bottom(), top())); } set_top(bottom()); set_affiliation(FREE); @@ -668,13 +668,6 @@ size_t ShenandoahHeapRegion::block_size(const HeapWord* p) const { } size_t ShenandoahHeapRegion::setup_sizes(size_t max_heap_size) { - // Absolute minimums we should not ever break. - static const size_t MIN_REGION_SIZE = 256*K; - - if (FLAG_IS_DEFAULT(ShenandoahMinRegionSize)) { - FLAG_SET_DEFAULT(ShenandoahMinRegionSize, MIN_REGION_SIZE); - } - // Generational Shenandoah needs this alignment for card tables. if (strcmp(ShenandoahGCMode, "generational") == 0) { max_heap_size = align_up(max_heap_size , CardTable::ct_max_alignment_constraint()); @@ -682,47 +675,13 @@ size_t ShenandoahHeapRegion::setup_sizes(size_t max_heap_size) { size_t region_size; if (FLAG_IS_DEFAULT(ShenandoahRegionSize)) { - if (ShenandoahMinRegionSize > max_heap_size / MIN_NUM_REGIONS) { - err_msg message("Max heap size (%zu%s) is too low to afford the minimum number " - "of regions (%zu) of minimum region size (%zu%s).", - byte_size_in_proper_unit(max_heap_size), proper_unit_for_byte_size(max_heap_size), - MIN_NUM_REGIONS, - byte_size_in_proper_unit(ShenandoahMinRegionSize), proper_unit_for_byte_size(ShenandoahMinRegionSize)); - vm_exit_during_initialization("Invalid -XX:ShenandoahMinRegionSize option", message); - } - if (ShenandoahMinRegionSize < MIN_REGION_SIZE) { - err_msg message("%zu%s should not be lower than minimum region size (%zu%s).", - byte_size_in_proper_unit(ShenandoahMinRegionSize), proper_unit_for_byte_size(ShenandoahMinRegionSize), - byte_size_in_proper_unit(MIN_REGION_SIZE), proper_unit_for_byte_size(MIN_REGION_SIZE)); - vm_exit_during_initialization("Invalid -XX:ShenandoahMinRegionSize option", message); - } - if (ShenandoahMinRegionSize < MinTLABSize) { - err_msg message("%zu%s should not be lower than TLAB size size (%zu%s).", - byte_size_in_proper_unit(ShenandoahMinRegionSize), proper_unit_for_byte_size(ShenandoahMinRegionSize), - byte_size_in_proper_unit(MinTLABSize), proper_unit_for_byte_size(MinTLABSize)); - vm_exit_during_initialization("Invalid -XX:ShenandoahMinRegionSize option", message); - } - if (ShenandoahMaxRegionSize < MIN_REGION_SIZE) { - err_msg message("%zu%s should not be lower than min region size (%zu%s).", - byte_size_in_proper_unit(ShenandoahMaxRegionSize), proper_unit_for_byte_size(ShenandoahMaxRegionSize), - byte_size_in_proper_unit(MIN_REGION_SIZE), proper_unit_for_byte_size(MIN_REGION_SIZE)); - vm_exit_during_initialization("Invalid -XX:ShenandoahMaxRegionSize option", message); - } - if (ShenandoahMinRegionSize > ShenandoahMaxRegionSize) { - err_msg message("Minimum (%zu%s) should be larger than maximum (%zu%s).", - byte_size_in_proper_unit(ShenandoahMinRegionSize), proper_unit_for_byte_size(ShenandoahMinRegionSize), - byte_size_in_proper_unit(ShenandoahMaxRegionSize), proper_unit_for_byte_size(ShenandoahMaxRegionSize)); - vm_exit_during_initialization("Invalid -XX:ShenandoahMinRegionSize or -XX:ShenandoahMaxRegionSize", message); - } - // We rapidly expand to max_heap_size in most scenarios, so that is the measure // for usual heap sizes. Do not depend on initial_heap_size here. region_size = max_heap_size / ShenandoahTargetNumRegions; // Now make sure that we don't go over or under our limits. - region_size = MAX2(ShenandoahMinRegionSize, region_size); - region_size = MIN2(ShenandoahMaxRegionSize, region_size); - + region_size = MAX2(MIN_REGION_SIZE, region_size); + region_size = MIN2(MAX_REGION_SIZE, region_size); } else { if (ShenandoahRegionSize > max_heap_size / MIN_NUM_REGIONS) { err_msg message("Max heap size (%zu%s) is too low to afford the minimum number " @@ -732,16 +691,16 @@ size_t ShenandoahHeapRegion::setup_sizes(size_t max_heap_size) { byte_size_in_proper_unit(ShenandoahRegionSize), proper_unit_for_byte_size(ShenandoahRegionSize)); vm_exit_during_initialization("Invalid -XX:ShenandoahRegionSize option", message); } - if (ShenandoahRegionSize < ShenandoahMinRegionSize) { + if (ShenandoahRegionSize < MIN_REGION_SIZE) { err_msg message("Heap region size (%zu%s) should be larger than min region size (%zu%s).", byte_size_in_proper_unit(ShenandoahRegionSize), proper_unit_for_byte_size(ShenandoahRegionSize), - byte_size_in_proper_unit(ShenandoahMinRegionSize), proper_unit_for_byte_size(ShenandoahMinRegionSize)); + byte_size_in_proper_unit(MIN_REGION_SIZE), proper_unit_for_byte_size(MIN_REGION_SIZE)); vm_exit_during_initialization("Invalid -XX:ShenandoahRegionSize option", message); } - if (ShenandoahRegionSize > ShenandoahMaxRegionSize) { + if (ShenandoahRegionSize > MAX_REGION_SIZE) { err_msg message("Heap region size (%zu%s) should be lower than max region size (%zu%s).", byte_size_in_proper_unit(ShenandoahRegionSize), proper_unit_for_byte_size(ShenandoahRegionSize), - byte_size_in_proper_unit(ShenandoahMaxRegionSize), proper_unit_for_byte_size(ShenandoahMaxRegionSize)); + byte_size_in_proper_unit(MAX_REGION_SIZE), proper_unit_for_byte_size(MAX_REGION_SIZE)); vm_exit_during_initialization("Invalid -XX:ShenandoahRegionSize option", message); } region_size = ShenandoahRegionSize; diff --git a/src/hotspot/share/gc/shenandoah/shenandoahHeapRegion.hpp b/src/hotspot/share/gc/shenandoah/shenandoahHeapRegion.hpp index e27bbbb737d..1054a23ea28 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahHeapRegion.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahHeapRegion.hpp @@ -277,7 +277,10 @@ private: public: ShenandoahHeapRegion(HeapWord* start, size_t index, bool committed); + // Absolute minimums and maximums we should not ever break. static const size_t MIN_NUM_REGIONS = 10; + static const size_t MIN_REGION_SIZE = 256*K; + static const size_t MAX_REGION_SIZE = 32*M; // Return adjusted max heap size static size_t setup_sizes(size_t max_heap_size); diff --git a/src/hotspot/share/gc/shenandoah/shenandoahHeapRegionCounters.cpp b/src/hotspot/share/gc/shenandoah/shenandoahHeapRegionCounters.cpp index aaf152e2890..3e809ea84b9 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahHeapRegionCounters.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahHeapRegionCounters.cpp @@ -77,8 +77,8 @@ ShenandoahHeapRegionCounters::ShenandoahHeapRegionCounters() : } ShenandoahHeapRegionCounters::~ShenandoahHeapRegionCounters() { - if (_name_space != nullptr) FREE_C_HEAP_ARRAY(char, _name_space); - if (_regions_data != nullptr) FREE_C_HEAP_ARRAY(PerfVariable*, _regions_data); + if (_name_space != nullptr) FREE_C_HEAP_ARRAY(_name_space); + if (_regions_data != nullptr) FREE_C_HEAP_ARRAY(_regions_data); } void ShenandoahHeapRegionCounters::write_snapshot(PerfLongVariable** regions, diff --git a/src/hotspot/share/gc/shenandoah/shenandoahHeapRegionSet.cpp b/src/hotspot/share/gc/shenandoah/shenandoahHeapRegionSet.cpp index 560de816db9..1d2cd97b75d 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahHeapRegionSet.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahHeapRegionSet.cpp @@ -47,7 +47,7 @@ ShenandoahHeapRegionSet::ShenandoahHeapRegionSet() : } ShenandoahHeapRegionSet::~ShenandoahHeapRegionSet() { - FREE_C_HEAP_ARRAY(jbyte, _set_map); + FREE_C_HEAP_ARRAY(_set_map); } void ShenandoahHeapRegionSet::add_region(ShenandoahHeapRegion* r) { diff --git a/src/hotspot/share/gc/shenandoah/shenandoahNMethod.cpp b/src/hotspot/share/gc/shenandoah/shenandoahNMethod.cpp index 594ad614d90..1b9532b3748 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahNMethod.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahNMethod.cpp @@ -48,7 +48,7 @@ ShenandoahNMethod::ShenandoahNMethod(nmethod* nm, GrowableArray& oops, boo ShenandoahNMethod::~ShenandoahNMethod() { if (_oops != nullptr) { - FREE_C_HEAP_ARRAY(oop*, _oops); + FREE_C_HEAP_ARRAY(_oops); } } @@ -60,7 +60,7 @@ void ShenandoahNMethod::update() { detect_reloc_oops(nm(), oops, non_immediate_oops); if (oops.length() != _oops_count) { if (_oops != nullptr) { - FREE_C_HEAP_ARRAY(oop*, _oops); + FREE_C_HEAP_ARRAY(_oops); _oops = nullptr; } @@ -394,7 +394,7 @@ ShenandoahNMethodList::ShenandoahNMethodList(int size) : ShenandoahNMethodList::~ShenandoahNMethodList() { assert(_list != nullptr, "Sanity"); assert(_ref_count == 0, "Must be"); - FREE_C_HEAP_ARRAY(ShenandoahNMethod*, _list); + FREE_C_HEAP_ARRAY(_list); } void ShenandoahNMethodList::transfer(ShenandoahNMethodList* const list, int limit) { diff --git a/src/hotspot/share/gc/shenandoah/shenandoahNumberSeq.cpp b/src/hotspot/share/gc/shenandoah/shenandoahNumberSeq.cpp index 1ddd8e1c032..82b027faca2 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahNumberSeq.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahNumberSeq.cpp @@ -39,10 +39,10 @@ HdrSeq::~HdrSeq() { for (int c = 0; c < MagBuckets; c++) { int* sub = _hdr[c]; if (sub != nullptr) { - FREE_C_HEAP_ARRAY(int, sub); + FREE_C_HEAP_ARRAY(sub); } } - FREE_C_HEAP_ARRAY(int*, _hdr); + FREE_C_HEAP_ARRAY(_hdr); } void HdrSeq::add(double val) { @@ -191,7 +191,7 @@ BinaryMagnitudeSeq::BinaryMagnitudeSeq() { } BinaryMagnitudeSeq::~BinaryMagnitudeSeq() { - FREE_C_HEAP_ARRAY(size_t, _mags); + FREE_C_HEAP_ARRAY(_mags); } void BinaryMagnitudeSeq::clear() { diff --git a/src/hotspot/share/gc/shenandoah/shenandoahObjArrayAllocator.cpp b/src/hotspot/share/gc/shenandoah/shenandoahObjArrayAllocator.cpp new file mode 100644 index 00000000000..e2215ea58ef --- /dev/null +++ b/src/hotspot/share/gc/shenandoah/shenandoahObjArrayAllocator.cpp @@ -0,0 +1,127 @@ +/* + * 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. + * + */ + +#include "gc/shared/memAllocator.hpp" +#include "gc/shenandoah/shenandoahBarrierSet.inline.hpp" +#include "gc/shenandoah/shenandoahHeap.inline.hpp" +#include "gc/shenandoah/shenandoahHeapRegion.hpp" +#include "gc/shenandoah/shenandoahObjArrayAllocator.hpp" +#include "gc/shenandoah/shenandoahThreadLocalData.hpp" +#include "memory/universe.hpp" +#include "oops/arrayKlass.hpp" +#include "oops/arrayOop.hpp" +#include "runtime/interfaceSupport.inline.hpp" +#include "utilities/copy.hpp" +#include "utilities/globalDefinitions.hpp" + +ShenandoahObjArrayAllocator::ShenandoahObjArrayAllocator( + Klass* klass, size_t word_size, int length, bool do_zero, Thread* thread) + : ObjArrayAllocator(klass, word_size, length, do_zero, thread) { + assert(_length >= 0, "length should be non-negative"); +} + +oop ShenandoahObjArrayAllocator::initialize(HeapWord* mem) const { + // threshold of object size, while above this size current mutator will yield to safepoint + // when it clears the array content. + constexpr size_t THRESHOLD = 64 * K / BytesPerWord; + + ShenandoahHeap* const heap = ShenandoahHeap::heap(); + + // Fast path: delegate to base class for small arrays or no-zero case. + // In no-zero case(_do_zero is false), the content of the array won't be zeroed, therefore no need to fall into slow-path. + if (!_do_zero || _word_size <= THRESHOLD) { + return ObjArrayAllocator::initialize(mem); + } + + // Slow path: yield to safepoint when clearing for large arrays + + // Compute clearing bounds + const BasicType element_type = ArrayKlass::cast(_klass)->element_type(); + const size_t base_offset_in_bytes = (size_t)arrayOopDesc::base_offset_in_bytes(element_type); + const size_t process_start_offset_in_bytes = align_up(base_offset_in_bytes, (size_t)BytesPerWord); + + const size_t process_start = process_start_offset_in_bytes / BytesPerWord; + const size_t process_size = _word_size - process_start; + + // Pin the region before clearing to avoid moving the object until it is done + ShenandoahHeapRegion* region = heap->heap_region_containing(mem); + region->record_pin(); + + // Always initialize the mem with primitive array first so GC won't look into the elements in the array. + // For obj array, the header will be corrected to object array after clearing the memory. + Klass* filling_klass = _klass; + int filling_array_length = _length; + const bool is_ref_type = is_reference_type(element_type, true); + + if (is_ref_type) { + const bool is_narrow_oop = element_type == T_NARROWOOP; + size_t filling_element_byte_size = is_narrow_oop ? T_INT_aelem_bytes : T_LONG_aelem_bytes; + filling_klass = is_narrow_oop ? Universe::intArrayKlass() : Universe::longArrayKlass(); + filling_array_length = (int) ((process_size << LogBytesPerWord) / filling_element_byte_size); + } + ObjArrayAllocator filling_array_allocator(filling_klass, _word_size, filling_array_length , /* do_zero */ false); + filling_array_allocator.initialize(mem); + + // Invisible roots will be scanned and marked at the end of marking. + ShenandoahThreadLocalData::set_invisible_root(_thread, mem, _word_size); + + { + // The mem has been initialized as primitive array, the entire clearing work is safe for safepoint + ThreadBlockInVM tbivm(JavaThread::cast(_thread)); // Allow safepoint to proceed. + // Handle potential 4-byte alignment gap before array data + if (process_start_offset_in_bytes != base_offset_in_bytes) { + assert(process_start_offset_in_bytes - base_offset_in_bytes == 4, "Must be 4-byte aligned"); + *reinterpret_cast(reinterpret_cast(mem) + base_offset_in_bytes) = 0; + } + + Copy::zero_to_words(mem + process_start, process_size); + + if (!is_ref_type) { + // zap paddings + mem_zap_start_padding(mem); + mem_zap_end_padding(mem); + } + } + + // reference array, header need to be overridden to its own. + if (is_ref_type) { + arrayOopDesc::set_length(mem, _length); + finish(mem); + // zap paddings after setting correct klass + mem_zap_start_padding(mem); + mem_zap_end_padding(mem); + } + + oop arrayObj = cast_to_oop(mem); + if (heap->is_concurrent_young_mark_in_progress() && !heap->marking_context()->allocated_after_mark_start(arrayObj)) { + // Keep the obj alive because we don't know the progress of marking, + // current concurrent marking could have done and VM is calling safepoint for final mark. + heap->keep_alive(arrayObj); + } + ShenandoahThreadLocalData::clear_invisible_root(_thread); + + region->record_unpin(); + + return arrayObj; +} diff --git a/src/hotspot/share/gc/shenandoah/shenandoahObjArrayAllocator.hpp b/src/hotspot/share/gc/shenandoah/shenandoahObjArrayAllocator.hpp new file mode 100644 index 00000000000..7605b69eb7e --- /dev/null +++ b/src/hotspot/share/gc/shenandoah/shenandoahObjArrayAllocator.hpp @@ -0,0 +1,40 @@ +/* + * 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. + * + */ + +#ifndef SHARE_GC_SHENANDOAH_SHENANDOAHOBJARRAYALLOCATOR_HPP +#define SHARE_GC_SHENANDOAH_SHENANDOAHOBJARRAYALLOCATOR_HPP + +#include "gc/shared/memAllocator.hpp" + +class ShenandoahObjArrayAllocator : public ObjArrayAllocator { +private: + // Override: clearing with safepoint yields for large arrays + oop initialize(HeapWord* mem) const override; + +public: + ShenandoahObjArrayAllocator(Klass* klass, size_t word_size, int length, + bool do_zero, Thread* thread); +}; + +#endif // SHARE_GC_SHENANDOAH_SHENANDOAHOBJARRAYALLOCATOR_HPP diff --git a/src/hotspot/share/gc/shenandoah/shenandoahRootProcessor.inline.hpp b/src/hotspot/share/gc/shenandoah/shenandoahRootProcessor.inline.hpp index 4504ac96819..fa24b2bab3f 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahRootProcessor.inline.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahRootProcessor.inline.hpp @@ -141,6 +141,49 @@ public: } }; +class ShenandoahInvisibleRootsMarkClosure : public ThreadClosure { +public: + void do_thread(Thread* t) { + assert_at_safepoint(); + + HeapWord* invisible_root = ShenandoahThreadLocalData::get_invisible_root(t); + if (invisible_root == nullptr) { + return; + } + size_t invisible_root_word_size = ShenandoahThreadLocalData::get_invisible_root_word_size(t); + + ShenandoahHeap* const heap = ShenandoahHeap::heap(); + ShenandoahMarkingContext* const marking_context = heap->marking_context(); + // Mark the invisible root if it is not marked. + if (!marking_context->is_marked(invisible_root)) { + bool was_upgraded = false; + if (!marking_context->mark_strong(cast_to_oop(invisible_root), was_upgraded)) { + return; + } + + // Update region liveness data + ShenandoahHeapRegion* region = heap->heap_region_containing(invisible_root); + if (region->is_regular() || region->is_regular_pinned()) { + assert(!ShenandoahHeapRegion::requires_humongous(invisible_root_word_size), "Must not be humongous."); + region->increase_live_data_alloc_words(invisible_root_word_size); + } else if (region->is_humongous_start()) { + DEBUG_ONLY(size_t total_live_words = 0;) + do { + size_t current = region->get_live_data_words(); + size_t region_used_words = region->used() >> LogHeapWordSize; + DEBUG_ONLY(total_live_words += region_used_words;) + assert(current == 0 || current == region_used_words, "Must be"); + if (current == 0) { + region->increase_live_data_alloc_words(region_used_words); + } + region = heap->get_region(region->index() + 1); + } while (region != nullptr && region->is_humongous_continuation()); + assert(total_live_words == invisible_root_word_size, "Must be"); + } + } + } +}; + // The rationale for selecting the roots to scan is as follows: // a. With unload_classes = true, we only want to scan the actual strong roots from the // code cache. This will allow us to identify the dead classes, unload them, *and* diff --git a/src/hotspot/share/gc/shenandoah/shenandoahRuntime.cpp b/src/hotspot/share/gc/shenandoah/shenandoahRuntime.cpp index 0bee8b4cf42..e106cc37627 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahRuntime.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahRuntime.cpp @@ -49,27 +49,27 @@ JRT_LEAF(void, ShenandoahRuntime::write_barrier_pre(oopDesc* orig)) JRT_END JRT_LEAF(oopDesc*, ShenandoahRuntime::load_reference_barrier_strong(oopDesc* src, oop* load_addr)) - return ShenandoahBarrierSet::barrier_set()->load_reference_barrier_mutator(src, load_addr); + return ShenandoahBarrierSet::barrier_set()->load_reference_barrier_mutator(src, load_addr); JRT_END JRT_LEAF(oopDesc*, ShenandoahRuntime::load_reference_barrier_strong_narrow(oopDesc* src, narrowOop* load_addr)) - return ShenandoahBarrierSet::barrier_set()->load_reference_barrier_mutator(src, load_addr); + return ShenandoahBarrierSet::barrier_set()->load_reference_barrier_mutator(src, load_addr); JRT_END JRT_LEAF(oopDesc*, ShenandoahRuntime::load_reference_barrier_weak(oopDesc* src, oop* load_addr)) - return (oopDesc*) ShenandoahBarrierSet::barrier_set()->load_reference_barrier(ON_WEAK_OOP_REF, oop(src), load_addr); + return ShenandoahBarrierSet::barrier_set()->load_reference_barrier_mutator(src, load_addr); JRT_END JRT_LEAF(oopDesc*, ShenandoahRuntime::load_reference_barrier_weak_narrow(oopDesc* src, narrowOop* load_addr)) - return (oopDesc*) ShenandoahBarrierSet::barrier_set()->load_reference_barrier(ON_WEAK_OOP_REF, oop(src), load_addr); + return ShenandoahBarrierSet::barrier_set()->load_reference_barrier_mutator(src, load_addr); JRT_END JRT_LEAF(oopDesc*, ShenandoahRuntime::load_reference_barrier_phantom(oopDesc* src, oop* load_addr)) - return (oopDesc*) ShenandoahBarrierSet::barrier_set()->load_reference_barrier(ON_PHANTOM_OOP_REF, oop(src), load_addr); + return ShenandoahBarrierSet::barrier_set()->load_reference_barrier_mutator(src, load_addr); JRT_END JRT_LEAF(oopDesc*, ShenandoahRuntime::load_reference_barrier_phantom_narrow(oopDesc* src, narrowOop* load_addr)) - return (oopDesc*) ShenandoahBarrierSet::barrier_set()->load_reference_barrier(ON_PHANTOM_OOP_REF, oop(src), load_addr); + return ShenandoahBarrierSet::barrier_set()->load_reference_barrier_mutator(src, load_addr); JRT_END JRT_LEAF(void, ShenandoahRuntime::clone_barrier(oopDesc* src)) diff --git a/src/hotspot/share/gc/shenandoah/shenandoahSTWMark.cpp b/src/hotspot/share/gc/shenandoah/shenandoahSTWMark.cpp index 5b4ce6d0bc9..73935ed4e91 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahSTWMark.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahSTWMark.cpp @@ -104,6 +104,12 @@ void ShenandoahSTWMark::mark() { heap->workers()->run_task(&task); assert(task_queues()->is_empty(), "Should be empty"); + + if (!generation()->is_old()) { + // Lastly, ensure all the invisible roots are marked. + ShenandoahInvisibleRootsMarkClosure cl; + Threads::java_threads_do(&cl); + } } _generation->set_mark_complete(); diff --git a/src/hotspot/share/gc/shenandoah/shenandoahScanRemembered.hpp b/src/hotspot/share/gc/shenandoah/shenandoahScanRemembered.hpp index 53f00e64a03..244ed7edd4c 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahScanRemembered.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahScanRemembered.hpp @@ -413,7 +413,7 @@ public: } ~ShenandoahCardCluster() { - FREE_C_HEAP_ARRAY(crossing_info, _object_starts); + FREE_C_HEAP_ARRAY(_object_starts); _object_starts = nullptr; } @@ -751,7 +751,7 @@ public: for (uint i = 0; i < ParallelGCThreads; i++) { delete _card_stats[i]; } - FREE_C_HEAP_ARRAY(HdrSeq*, _card_stats); + FREE_C_HEAP_ARRAY(_card_stats); _card_stats = nullptr; } assert(_card_stats == nullptr, "Error"); diff --git a/src/hotspot/share/gc/shenandoah/shenandoahSimpleBitMap.cpp b/src/hotspot/share/gc/shenandoah/shenandoahSimpleBitMap.cpp index 82a759e34db..d0029b60167 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahSimpleBitMap.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahSimpleBitMap.cpp @@ -35,7 +35,7 @@ ShenandoahSimpleBitMap::ShenandoahSimpleBitMap(idx_t num_bits) : ShenandoahSimpleBitMap::~ShenandoahSimpleBitMap() { if (_bitmap != nullptr) { - FREE_C_HEAP_ARRAY(uintx, _bitmap); + FREE_C_HEAP_ARRAY(_bitmap); } } diff --git a/src/hotspot/share/gc/shenandoah/shenandoahThreadLocalData.cpp b/src/hotspot/share/gc/shenandoah/shenandoahThreadLocalData.cpp index 1f3ce76cc1c..5295af51eff 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahThreadLocalData.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahThreadLocalData.cpp @@ -38,7 +38,9 @@ ShenandoahThreadLocalData::ShenandoahThreadLocalData() : _gclab(nullptr), _gclab_size(0), _shenandoah_plab(nullptr), - _evacuation_stats(new ShenandoahEvacuationStats()) { + _evacuation_stats(new ShenandoahEvacuationStats()), + _invisible_root(nullptr), + _invisible_root_word_size(0) { } ShenandoahThreadLocalData::~ShenandoahThreadLocalData() { diff --git a/src/hotspot/share/gc/shenandoah/shenandoahThreadLocalData.hpp b/src/hotspot/share/gc/shenandoah/shenandoahThreadLocalData.hpp index b1b923bbfce..e9a5cf99fdd 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahThreadLocalData.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahThreadLocalData.hpp @@ -67,6 +67,9 @@ private: ShenandoahEvacuationStats* _evacuation_stats; + Atomic _invisible_root; + Atomic _invisible_root_word_size; + ShenandoahThreadLocalData(); ~ShenandoahThreadLocalData(); @@ -206,6 +209,25 @@ public: static ByteSize card_table_offset() { return Thread::gc_data_offset() + byte_offset_of(ShenandoahThreadLocalData, _card_table); } + + // invisible root are the partially initialized obj array set by ShenandoahObjArrayAllocator + static void set_invisible_root(Thread* thread, HeapWord* invisible_root, size_t word_size) { + data(thread)->_invisible_root.store_relaxed(invisible_root); + data(thread)->_invisible_root_word_size.store_relaxed(word_size); + } + + static void clear_invisible_root(Thread* thread) { + data(thread)->_invisible_root.store_relaxed(nullptr); + data(thread)->_invisible_root_word_size.store_relaxed(0); + } + + static HeapWord* get_invisible_root(Thread* thread) { + return data(thread)->_invisible_root.load_relaxed(); + } + + static size_t get_invisible_root_word_size(Thread* thread) { + return data(thread)->_invisible_root_word_size.load_relaxed(); + } }; STATIC_ASSERT(sizeof(ShenandoahThreadLocalData) <= sizeof(GCThreadLocalData)); diff --git a/src/hotspot/share/gc/shenandoah/shenandoahVerifier.cpp b/src/hotspot/share/gc/shenandoah/shenandoahVerifier.cpp index 8299cbe62c6..5df88c0fc0a 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahVerifier.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahVerifier.cpp @@ -1073,7 +1073,7 @@ void ShenandoahVerifier::verify_at_safepoint(ShenandoahGeneration* generation, log_info(gc)("Verify %s, Level %zd (%zu reachable, %zu marked)", label, ShenandoahVerifyLevel, count_reachable, count_marked); - FREE_C_HEAP_ARRAY(ShenandoahLivenessData, ld); + FREE_C_HEAP_ARRAY(ld); } void ShenandoahVerifier::verify_generic(ShenandoahGeneration* generation, VerifyOption vo) { @@ -1187,7 +1187,7 @@ void ShenandoahVerifier::verify_after_update_refs(ShenandoahGeneration* generati "After Updating References", _verify_remembered_disable, // do not verify remembered set _verify_forwarded_none, // no forwarded references - _verify_marked_complete, // bitmaps might be stale, but alloc-after-mark should be well + _verify_marked_disable, // no need to check unreachable objects, end of cycle _verify_cset_none, // no cset references, all updated _verify_liveness_disable, // no reliable liveness data anymore _verify_regions_nocset, // no cset regions, trash regions have appeared @@ -1204,7 +1204,7 @@ void ShenandoahVerifier::verify_after_gc(ShenandoahGeneration* generation) { "After GC", _verify_remembered_disable, // do not verify remembered set _verify_forwarded_none, // no forwarded references - _verify_marked_complete, // bitmaps might be stale, but alloc-after-mark should be well + _verify_marked_disable, // no need to check unreachable objects, end of cycle _verify_cset_none, // no cset references, all updated _verify_liveness_disable, // no reliable liveness data anymore _verify_regions_nocset, // no cset regions, trash regions have appeared @@ -1220,7 +1220,7 @@ void ShenandoahVerifier::verify_after_degenerated(ShenandoahGeneration* generati "After Degenerated GC", _verify_remembered_disable, // do not verify remembered set _verify_forwarded_none, // all objects are non-forwarded - _verify_marked_complete, // all objects are marked in complete bitmap + _verify_marked_disable, // no need to check unreachable objects, end of cycle _verify_cset_none, // no cset references _verify_liveness_disable, // no reliable liveness data anymore _verify_regions_notrash_nocset, // no trash, no cset @@ -1248,14 +1248,14 @@ void ShenandoahVerifier::verify_after_fullgc(ShenandoahGeneration* generation) { verify_at_safepoint( generation, "After Full GC", - _verify_remembered_after_full_gc, // verify read-write remembered set - _verify_forwarded_none, // all objects are non-forwarded - _verify_marked_incomplete, // all objects are marked in incomplete bitmap - _verify_cset_none, // no cset references - _verify_liveness_disable, // no reliable liveness data anymore - _verify_regions_notrash_nocset, // no trash, no cset - _verify_size_exact, // expect generation and heap sizes to match exactly - _verify_gcstate_stable // full gc cleaned up everything + _verify_remembered_after_full_gc, // verify read-write remembered set + _verify_forwarded_none, // all objects are non-forwarded + _verify_marked_disable, // no need to check unreachable objects, end of cycle + _verify_cset_none, // no cset references + _verify_liveness_disable, // no reliable liveness data anymore + _verify_regions_notrash_nocset, // no trash, no cset + _verify_size_exact, // expect generation and heap sizes to match exactly + _verify_gcstate_stable // full gc cleaned up everything ); } diff --git a/src/hotspot/share/gc/shenandoah/shenandoah_globals.hpp b/src/hotspot/share/gc/shenandoah/shenandoah_globals.hpp index 2c5ba726ef2..d26959edf89 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoah_globals.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoah_globals.hpp @@ -196,14 +196,6 @@ "of regions that would be used, within min/max region size " \ "limits.") \ \ - product(size_t, ShenandoahMinRegionSize, 256 * K, EXPERIMENTAL, \ - "With automatic region sizing, the regions would be at least " \ - "this large.") \ - \ - product(size_t, ShenandoahMaxRegionSize, 32 * M, EXPERIMENTAL, \ - "With automatic region sizing, the regions would be at most " \ - "this large.") \ - \ product(ccstr, ShenandoahGCMode, "satb", \ "GC mode to use. Among other things, this defines which " \ "barriers are in in use. Possible values are:" \ diff --git a/src/hotspot/share/gc/z/zForwardingAllocator.cpp b/src/hotspot/share/gc/z/zForwardingAllocator.cpp index 451a1d62754..37b5b8f520c 100644 --- a/src/hotspot/share/gc/z/zForwardingAllocator.cpp +++ b/src/hotspot/share/gc/z/zForwardingAllocator.cpp @@ -30,11 +30,11 @@ ZForwardingAllocator::ZForwardingAllocator() _top(nullptr) {} ZForwardingAllocator::~ZForwardingAllocator() { - FREE_C_HEAP_ARRAY(char, _start); + FREE_C_HEAP_ARRAY(_start); } void ZForwardingAllocator::reset(size_t size) { - _start = REALLOC_C_HEAP_ARRAY(char, _start, size, mtGC); + _start = REALLOC_C_HEAP_ARRAY(_start, size, mtGC); _top.store_relaxed(_start); _end = _start + size; } diff --git a/src/hotspot/share/interpreter/bytecodeTracer.cpp b/src/hotspot/share/interpreter/bytecodeTracer.cpp index 4578a3eec4e..cbe28e92c51 100644 --- a/src/hotspot/share/interpreter/bytecodeTracer.cpp +++ b/src/hotspot/share/interpreter/bytecodeTracer.cpp @@ -40,21 +40,17 @@ #include "utilities/align.hpp" // Prints the current bytecode and its attributes using bytecode-specific information. +// Printing bytecodes is not an idempotent operation, as this relies on modifying state. +// An instance of this class is thus intended to only print a single bytecode. All state +// shared between multiple bytecodes needs to be in BytecodeTracerData. class BytecodePrinter { private: - // %%% This field is not GC-ed, and so can contain garbage - // between critical sections. Use only pointer-comparison - // operations on the pointer, except within a critical section. - // (Also, ensure that occasional false positives are benign.) - Method* _current_method; - bool _is_wide; - Bytecodes::Code _code; - address _next_pc; // current decoding position - int _flags; - bool _use_cp_cache; + BytecodeTracerData* _data; + int _flags; + Bytecodes::Code _raw_code; // note: some methods translate this to the Java bytecode + address _next_pc; // current decoding position, destructive - bool use_cp_cache() const { return _use_cp_cache; } void align() { _next_pc = align_up(_next_pc, sizeof(jint)); } int get_byte() { return *(jbyte*) _next_pc++; } // signed int get_index_u1() { return *(address)_next_pc++; } // returns 0x00 - 0xff as an int @@ -65,11 +61,22 @@ class BytecodePrinter { int get_Java_index_u2() { int i = Bytes::get_Java_u2 (_next_pc); _next_pc += 2; return i; } int get_Java_index_u4() { int i = Bytes::get_Java_u4 (_next_pc); _next_pc += 4; return i; } int get_index_special() { return (is_wide()) ? get_Java_index_u2() : get_index_u1(); } - Method* method() const { return _current_method; } - bool is_wide() const { return _is_wide; } - Bytecodes::Code raw_code() const { return Bytecodes::Code(_code); } - ConstantPool* constants() const { return method()->constants(); } - ConstantPoolCache* cpcache() const { assert(use_cp_cache(), "must be"); return constants()->cache(); } + + // Warning: only do pointer comparison between critical sections. + Method* method() const { return _data->current_method(); } + void set_method(Method* current) { _data->set_current_method(current); } + + // Warning: should only be used for comparison and not dereferenced. + intptr_t* fp() const { return _data->current_fp(); } + void set_fp(intptr_t* current) { _data->set_current_fp(current); } + + bool is_wide() const { return _data->is_wide(); } + void set_wide(bool wide) { _data->set_wide(wide); } + + ConstantPool* constants() const { return method()->constants(); } + // This may be called during linking after bytecodes are rewritten to point to the cpCache. + bool use_cp_cache() const { return constants()->cache() != nullptr; } + ConstantPoolCache* cpcache() const { assert(use_cp_cache(), "must be"); return constants()->cache(); } void print_constant(int i, outputStream* st); void print_cpcache_entry(int cpc_index, outputStream* st); @@ -81,35 +88,32 @@ class BytecodePrinter { void print_method_data_at(int bci, outputStream* st); public: - BytecodePrinter(int flags = 0) : _is_wide(false), _code(Bytecodes::_illegal), _flags(flags) {} + BytecodePrinter(BytecodeTracerData* data, int flags = 0) : + _data(data), + _flags(flags), + _raw_code(Bytecodes::_illegal), + _next_pc(nullptr) {} #ifndef PRODUCT - BytecodePrinter(Method* prev_method) : BytecodePrinter(0) { - _current_method = prev_method; - } - // This method is called while executing the raw bytecodes, so none of // the adjustments that BytecodeStream performs applies. - void trace(const methodHandle& method, address bcp, uintptr_t tos, uintptr_t tos2, outputStream* st) { + void trace(const methodHandle& method, intptr_t* fp, address bcp, uintptr_t tos, uintptr_t tos2, outputStream* st) { + assert(_raw_code == Bytecodes::_illegal, "invariant"); ResourceMark rm; - bool method_changed = _current_method != method(); - _current_method = method(); - _use_cp_cache = method->constants()->cache() != nullptr; + // Method changes can be another method getting called, or a self-recursive call. + bool method_changed = (this->method() != method()) || (this->fp() != fp); + set_method(method()); + set_fp(fp); assert(method->method_holder()->is_linked(), "this function must be called on methods that are already executing"); - + // If the method changed (new method call, return to previous method after call finishes), + // the signature needs to be re-printed for interpretability. if (method_changed) { - // Note 1: This code will not work as expected with true MT/MP. - // Need an explicit lock or a different solution. - // It is possible for this block to be skipped, if a garbage - // _current_method pointer happens to have the same bits as - // the incoming method. We could lose a line of trace output. - // This is acceptable in a debug-only feature. - st->cr(); st->print("[%zu] ", Thread::current()->osthread()->thread_id_for_printing()); method->print_name(st); st->cr(); } + Bytecodes::Code code; if (is_wide()) { // bcp wasn't advanced if previous bytecode was _wide. @@ -117,14 +121,13 @@ class BytecodePrinter { } else { code = Bytecodes::code_at(method(), bcp); } - _code = code; + _raw_code = code; _next_pc = is_wide() ? bcp+2 : bcp+1; + + bool is_terminal = Bytecodes::is_terminal(code); // Trace each bytecode unless we're truncating the tracing output, then only print the first - // bytecode in every method as well as returns/throws that pop control flow - if (!TraceBytecodesTruncated || method_changed || - code == Bytecodes::_athrow || - code == Bytecodes::_return_register_finalizer || - (code >= Bytecodes::_ireturn && code <= Bytecodes::_return)) { + // bytecode in every method as well as returns/throws that pop control flow. + if (!TraceBytecodesTruncated || method_changed || is_terminal) { int bci = (int)(bcp - method->code_base()); st->print("[%zu] ", Thread::current()->osthread()->thread_id_for_printing()); if (Verbose) { @@ -138,8 +141,16 @@ class BytecodePrinter { } // Set is_wide for the next one, since the caller of this doesn't skip // the next bytecode. - _is_wide = (code == Bytecodes::_wide); - _code = Bytecodes::_illegal; + set_wide(code == Bytecodes::_wide); + // Finished using the code, reset to illegal. + _raw_code = Bytecodes::_illegal; + + // Invalidate the current method to force a signature change. In some + // rare cases, the method and frame pointers aren't enough to determine + // a new method invocation, so this ensures the signature is re-printed. + if (is_terminal) { + set_method(nullptr); + } if (TraceBytecodesStopAt != 0 && BytecodeCounter::counter_value() >= TraceBytecodesStopAt) { TraceBytecodes = false; @@ -150,17 +161,16 @@ class BytecodePrinter { // Used for Method::print_codes(). The input bcp comes from // BytecodeStream, which will skip wide bytecodes. void trace(const methodHandle& method, address bcp, outputStream* st) { - _current_method = method(); - // This may be called during linking after bytecodes are rewritten to point to the cpCache. - _use_cp_cache = method->constants()->cache() != nullptr; + assert(_raw_code == Bytecodes::_illegal, "invariant"); + set_method(method()); ResourceMark rm; Bytecodes::Code code = Bytecodes::code_at(method(), bcp); // Set is_wide - _is_wide = (code == Bytecodes::_wide); + set_wide(code == Bytecodes::_wide); if (is_wide()) { code = Bytecodes::code_at(method(), bcp+1); } - _code = code; + _raw_code = code; int bci = (int)(bcp - method->code_base()); // Print bytecode index and name if (ClassPrinter::has_mode(_flags, ClassPrinter::PRINT_BYTECODE_ADDR)) { @@ -180,26 +190,20 @@ class BytecodePrinter { }; #ifndef PRODUCT -// We need a global instance to keep track of the method being printed so we can report that -// the method has changed. If this method is redefined and removed, that's ok because the method passed -// in won't match, and this will print the method passed in again. Racing threads changing this global -// will result in reprinting the method passed in again. -static Method* _method_currently_being_printed = nullptr; - -void BytecodeTracer::trace_interpreter(const methodHandle& method, address bcp, uintptr_t tos, uintptr_t tos2, outputStream* st) { +void BytecodeTracer::trace_interpreter(const methodHandle& method, intptr_t* fp, address bcp, uintptr_t tos, uintptr_t tos2, outputStream* st) { if (TraceBytecodes && BytecodeCounter::counter_value() >= TraceBytecodesAt) { - BytecodePrinter printer(AtomicAccess::load_acquire(&_method_currently_being_printed)); - stringStream buf; - printer.trace(method, bcp, tos, tos2, &buf); - st->print("%s", buf.freeze()); - // Save method currently being printed to detect when method printing changes. - AtomicAccess::release_store(&_method_currently_being_printed, method()); + BytecodeTracerData* data = JavaThread::current()->bytecode_tracer_data(); + BytecodePrinter printer(data); + printer.trace(method, fp, bcp, tos, tos2, st); } } #endif void BytecodeTracer::print_method_codes(const methodHandle& method, int from, int to, outputStream* st, int flags, bool buffered) { - BytecodePrinter method_printer(flags); + // Debug builds can't re-use the data in the Java Thread as that is used for tracing + // the current bytecodes, rather than to print diagnostic information as is the + // case here. Always stack-allocate for this printing. + BytecodeTracerData data; BytecodeStream s(method); s.set_interval(from, to); @@ -207,6 +211,7 @@ void BytecodeTracer::print_method_codes(const methodHandle& method, int from, in stringStream ss; outputStream* out = buffered ? &ss : st; while (s.next() >= 0) { + BytecodePrinter method_printer(&data, flags); method_printer.trace(method, s.bcp(), out); } if (buffered) { @@ -345,7 +350,7 @@ void BytecodePrinter::print_bsm(int cp_index, outputStream* st) { void BytecodePrinter::print_attributes(int bci, outputStream* st) { // Show attributes of pre-rewritten codes - Bytecodes::Code code = Bytecodes::java_code(raw_code()); + Bytecodes::Code code = Bytecodes::java_code(_raw_code); // If the code doesn't have any fields there's nothing to print. // note this is ==1 because the tableswitch and lookupswitch are // zero size (for some reason) and we want to print stuff out for them. @@ -366,7 +371,7 @@ void BytecodePrinter::print_attributes(int bci, outputStream* st) { case Bytecodes::_ldc: { int cp_index; - if (Bytecodes::uses_cp_cache(raw_code())) { + if (Bytecodes::uses_cp_cache(_raw_code)) { assert(use_cp_cache(), "fast ldc bytecode must be in linked classes"); int obj_index = get_index_u1(); cp_index = constants()->object_to_cp_index(obj_index); @@ -381,7 +386,7 @@ void BytecodePrinter::print_attributes(int bci, outputStream* st) { case Bytecodes::_ldc2_w: { int cp_index; - if (Bytecodes::uses_cp_cache(raw_code())) { + if (Bytecodes::uses_cp_cache(_raw_code)) { assert(use_cp_cache(), "fast ldc bytecode must be in linked classes"); int obj_index = get_native_index_u2(); cp_index = constants()->object_to_cp_index(obj_index); @@ -533,7 +538,7 @@ void BytecodePrinter::print_attributes(int bci, outputStream* st) { cp_index = method_entry->constant_pool_index(); print_field_or_method(cp_index, st); - if (raw_code() == Bytecodes::_invokehandle && + if (_raw_code == Bytecodes::_invokehandle && ClassPrinter::has_mode(_flags, ClassPrinter::PRINT_METHOD_HANDLE)) { assert(use_cp_cache(), "invokehandle is only in rewritten methods"); method_entry->print_on(st); diff --git a/src/hotspot/share/interpreter/bytecodeTracer.hpp b/src/hotspot/share/interpreter/bytecodeTracer.hpp index ab66030b6cd..03340fbe5bf 100644 --- a/src/hotspot/share/interpreter/bytecodeTracer.hpp +++ b/src/hotspot/share/interpreter/bytecodeTracer.hpp @@ -25,21 +25,54 @@ #ifndef SHARE_INTERPRETER_BYTECODETRACER_HPP #define SHARE_INTERPRETER_BYTECODETRACER_HPP +#include "interpreter/bytecodes.hpp" #include "memory/allStatic.hpp" #include "utilities/globalDefinitions.hpp" -// The BytecodeTracer is a helper class used by the interpreter for run-time -// bytecode tracing. If TraceBytecodes turned on, trace_interpreter() will be called -// for each bytecode. - +class Method; class methodHandle; class outputStream; - class BytecodeClosure; + +// The BytecodeTracer is a helper class used by the interpreter for run-time +// bytecode tracing. If TraceBytecodes is turned on, trace_interpreter() will be called +// for each bytecode. class BytecodeTracer: AllStatic { public: - NOT_PRODUCT(static void trace_interpreter(const methodHandle& method, address bcp, uintptr_t tos, uintptr_t tos2, outputStream* st);) + NOT_PRODUCT(static void trace_interpreter(const methodHandle& method, intptr_t* fp, address bcp, uintptr_t tos, uintptr_t tos2, outputStream* st);) static void print_method_codes(const methodHandle& method, int from, int to, outputStream* st, int flags, bool buffered = true); }; +// Provides tracing-centric context whose lifespan exceeds the printing of +// a single bytecode. For instance, it is needed to determine method switches +// in order to print the appropriate signature once a switch happens. +class BytecodeTracerData { + private: + Method* _current_method; // for method switches + intptr_t* _current_fp; // for self-recursion + bool _is_wide; // to parse the next bytecode properly + + public: + BytecodeTracerData() : _current_method(nullptr), + _current_fp(nullptr), + _is_wide(false) {} + + // The current method may point to a stale/garbage Method. While pointer + // comparison is safe, it should only be dereferenced while guaranteed to + // be valid. For example, if the current method is set to the result of a + // methodHandle call, current_method() may be dereferenced while the handle + // is live. It is always up to the caller to ensure that current_method() + // is safe to dereference. + Method* current_method() const { return _current_method; } + void set_current_method(Method* current) { _current_method = current; } + + // The frame pointer should only ever be used for pointer comparison and may + // never be dereferenced. + intptr_t* current_fp() const { return _current_fp; } + void set_current_fp(intptr_t* current) { _current_fp = current; } + + bool is_wide() const { return _is_wide; } + void set_wide(bool wide) { _is_wide = wide; } +}; + #endif // SHARE_INTERPRETER_BYTECODETRACER_HPP diff --git a/src/hotspot/share/interpreter/bytecodes.hpp b/src/hotspot/share/interpreter/bytecodes.hpp index 629cca706ae..6f77e95f5bd 100644 --- a/src/hotspot/share/interpreter/bytecodes.hpp +++ b/src/hotspot/share/interpreter/bytecodes.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -418,6 +418,9 @@ class Bytecodes: AllStatic { static bool is_zero_const (Code code) { return (code == _aconst_null || code == _iconst_0 || code == _fconst_0 || code == _dconst_0); } static bool is_return (Code code) { return (_ireturn <= code && code <= _return); } + static bool is_terminal (Code code) { return is_return(code) || + code == _return_register_finalizer || + code == _athrow; } static bool is_invoke (Code code) { return (_invokevirtual <= code && code <= _invokedynamic); } static bool is_field_code (Code code) { return (_getstatic <= java_code(code) && java_code(code) <= _putfield); } static bool has_receiver (Code code) { assert(is_invoke(code), ""); return code == _invokevirtual || diff --git a/src/hotspot/share/interpreter/interpreterRuntime.cpp b/src/hotspot/share/interpreter/interpreterRuntime.cpp index cd0a062ebc8..dd183f36ea2 100644 --- a/src/hotspot/share/interpreter/interpreterRuntime.cpp +++ b/src/hotspot/share/interpreter/interpreterRuntime.cpp @@ -1517,7 +1517,9 @@ JRT_LEAF(intptr_t, InterpreterRuntime::trace_bytecode(JavaThread* current, intpt LastFrameAccessor last_frame(current); assert(last_frame.is_interpreted_frame(), "must be an interpreted frame"); methodHandle mh(current, last_frame.method()); - BytecodeTracer::trace_interpreter(mh, last_frame.bcp(), tos, tos2, tty); + stringStream st; + BytecodeTracer::trace_interpreter(mh, last_frame.get_frame().real_fp(), last_frame.bcp(), tos, tos2, &st); + tty->print("%s", st.freeze()); return preserve_this_value; JRT_END #endif // !PRODUCT diff --git a/src/hotspot/share/interpreter/oopMapCache.cpp b/src/hotspot/share/interpreter/oopMapCache.cpp index af45f7f9bed..34e226b00bf 100644 --- a/src/hotspot/share/interpreter/oopMapCache.cpp +++ b/src/hotspot/share/interpreter/oopMapCache.cpp @@ -156,7 +156,7 @@ InterpreterOopMap::InterpreterOopMap() { InterpreterOopMap::~InterpreterOopMap() { if (has_valid_mask() && mask_size() > small_mask_limit) { assert(_bit_mask[0] != 0, "should have pointer to C heap"); - FREE_C_HEAP_ARRAY(uintptr_t, _bit_mask[0]); + FREE_C_HEAP_ARRAY((uintptr_t*)_bit_mask[0]); } } @@ -288,7 +288,7 @@ void OopMapCacheEntry::deallocate_bit_mask() { if (mask_size() > small_mask_limit && _bit_mask[0] != 0) { assert(!Thread::current()->resource_area()->contains((void*)_bit_mask[0]), "This bit mask should not be in the resource area"); - FREE_C_HEAP_ARRAY(uintptr_t, _bit_mask[0]); + FREE_C_HEAP_ARRAY((uintptr_t*)_bit_mask[0]); DEBUG_ONLY(_bit_mask[0] = 0;) } } diff --git a/src/hotspot/share/jfr/jni/jfrJavaSupport.cpp b/src/hotspot/share/jfr/jni/jfrJavaSupport.cpp index a6e97ab227a..32710595d27 100644 --- a/src/hotspot/share/jfr/jni/jfrJavaSupport.cpp +++ b/src/hotspot/share/jfr/jni/jfrJavaSupport.cpp @@ -528,7 +528,7 @@ const char* JfrJavaSupport::c_str(jstring string, Thread* thread, bool c_heap /* void JfrJavaSupport::free_c_str(const char* str, bool c_heap) { if (c_heap) { - FREE_C_HEAP_ARRAY(char, str); + FREE_C_HEAP_ARRAY(str); } } diff --git a/src/hotspot/share/jfr/leakprofiler/leakProfiler.cpp b/src/hotspot/share/jfr/leakprofiler/leakProfiler.cpp index e8ad79783c0..9098a0af6b3 100644 --- a/src/hotspot/share/jfr/leakprofiler/leakProfiler.cpp +++ b/src/hotspot/share/jfr/leakprofiler/leakProfiler.cpp @@ -34,9 +34,15 @@ #include "runtime/vmThread.hpp" bool LeakProfiler::is_supported() { - if (UseShenandoahGC) { + if (UseShenandoahGC || UseZGC) { // Leak Profiler uses mark words in the ways that might interfere // with concurrent GC uses of them. This affects Shenandoah. + // + // Generational ZGC only does weak reference processing in the old generation. + // All objects that would usually die, because we are sampling stuff + // that immediately becomes garbage, will be artificially kept alive + // until an old-generation collection. This incurs a significant + // performance hit by causing allocation stalls. return false; } return true; @@ -58,7 +64,8 @@ bool LeakProfiler::start(int sample_count) { // Exit cleanly if not supported if (!is_supported()) { - log_trace(jfr, system)("Object sampling is not supported"); + log_info(jfr, system)("jdk.OldObjectSample event is currently not supported for %s.", + UseShenandoahGC ? "ShenandoahGC" : "ZGC"); return false; } diff --git a/src/hotspot/share/jfr/leakprofiler/sampling/samplePriorityQueue.cpp b/src/hotspot/share/jfr/leakprofiler/sampling/samplePriorityQueue.cpp index 644cd25ec8a..5eac068467f 100644 --- a/src/hotspot/share/jfr/leakprofiler/sampling/samplePriorityQueue.cpp +++ b/src/hotspot/share/jfr/leakprofiler/sampling/samplePriorityQueue.cpp @@ -36,7 +36,7 @@ SamplePriorityQueue::SamplePriorityQueue(size_t size) : } SamplePriorityQueue::~SamplePriorityQueue() { - FREE_C_HEAP_ARRAY(ObjectSample*, _items); + FREE_C_HEAP_ARRAY(_items); _items = nullptr; } diff --git a/src/hotspot/share/jfr/periodic/jfrNetworkUtilization.cpp b/src/hotspot/share/jfr/periodic/jfrNetworkUtilization.cpp index 11e211f6505..1650ad7d9c0 100644 --- a/src/hotspot/share/jfr/periodic/jfrNetworkUtilization.cpp +++ b/src/hotspot/share/jfr/periodic/jfrNetworkUtilization.cpp @@ -46,7 +46,7 @@ static GrowableArray* _interfaces = nullptr; void JfrNetworkUtilization::destroy() { if (_interfaces != nullptr) { for (int i = 0; i < _interfaces->length(); ++i) { - FREE_C_HEAP_ARRAY(char, _interfaces->at(i).name); + FREE_C_HEAP_ARRAY(_interfaces->at(i).name); } delete _interfaces; _interfaces = nullptr; diff --git a/src/hotspot/share/jfr/recorder/service/jfrOptionSet.cpp b/src/hotspot/share/jfr/recorder/service/jfrOptionSet.cpp index b212ee4ccba..ec8ab36d75a 100644 --- a/src/hotspot/share/jfr/recorder/service/jfrOptionSet.cpp +++ b/src/hotspot/share/jfr/recorder/service/jfrOptionSet.cpp @@ -799,7 +799,7 @@ void JfrOptionSet::release_start_flight_recording_options() { if (start_flight_recording_options_array != nullptr) { const int length = start_flight_recording_options_array->length(); for (int i = 0; i < length; ++i) { - FREE_C_HEAP_ARRAY(char, start_flight_recording_options_array->at(i)); + FREE_C_HEAP_ARRAY(start_flight_recording_options_array->at(i)); } delete start_flight_recording_options_array; start_flight_recording_options_array = nullptr; diff --git a/src/hotspot/share/jfr/recorder/stacktrace/jfrStackFilter.cpp b/src/hotspot/share/jfr/recorder/stacktrace/jfrStackFilter.cpp index 1eb057b564e..39a1c621888 100644 --- a/src/hotspot/share/jfr/recorder/stacktrace/jfrStackFilter.cpp +++ b/src/hotspot/share/jfr/recorder/stacktrace/jfrStackFilter.cpp @@ -55,6 +55,6 @@ JfrStackFilter::~JfrStackFilter() { Symbol::maybe_decrement_refcount(_method_names[i]); Symbol::maybe_decrement_refcount(_class_names[i]); } - FREE_C_HEAP_ARRAY(Symbol*, _method_names); - FREE_C_HEAP_ARRAY(Symbol*, _class_names); + FREE_C_HEAP_ARRAY(_method_names); + FREE_C_HEAP_ARRAY(_class_names); } diff --git a/src/hotspot/share/jfr/recorder/stacktrace/jfrStackFilterRegistry.cpp b/src/hotspot/share/jfr/recorder/stacktrace/jfrStackFilterRegistry.cpp index 0721604b1c1..cb9811e7cae 100644 --- a/src/hotspot/share/jfr/recorder/stacktrace/jfrStackFilterRegistry.cpp +++ b/src/hotspot/share/jfr/recorder/stacktrace/jfrStackFilterRegistry.cpp @@ -43,8 +43,8 @@ int64_t JfrStackFilterRegistry::add(jobjectArray classes, jobjectArray methods, Symbol** method_names = JfrJavaSupport::symbol_array(methods, jt, &m_size, true); assert(method_names != nullptr, "invariant"); if (c_size != m_size) { - FREE_C_HEAP_ARRAY(Symbol*, class_names); - FREE_C_HEAP_ARRAY(Symbol*, method_names); + FREE_C_HEAP_ARRAY(class_names); + FREE_C_HEAP_ARRAY(method_names); JfrJavaSupport::throw_internal_error("Method array size doesn't match class array size", jt); return STACK_FILTER_ERROR_CODE; } diff --git a/src/hotspot/share/jfr/support/methodtracer/jfrFilter.cpp b/src/hotspot/share/jfr/support/methodtracer/jfrFilter.cpp index 2a977f9e823..767036b57f2 100644 --- a/src/hotspot/share/jfr/support/methodtracer/jfrFilter.cpp +++ b/src/hotspot/share/jfr/support/methodtracer/jfrFilter.cpp @@ -51,10 +51,10 @@ JfrFilter::~JfrFilter() { Symbol::maybe_decrement_refcount(_method_names[i]); Symbol::maybe_decrement_refcount(_annotation_names[i]); } - FREE_C_HEAP_ARRAY(Symbol*, _class_names); - FREE_C_HEAP_ARRAY(Symbol*, _method_names); - FREE_C_HEAP_ARRAY(Symbol*, _annotation_names); - FREE_C_HEAP_ARRAY(int, _modifications); + FREE_C_HEAP_ARRAY(_class_names); + FREE_C_HEAP_ARRAY(_method_names); + FREE_C_HEAP_ARRAY(_annotation_names); + FREE_C_HEAP_ARRAY(_modifications); } bool JfrFilter::can_instrument_module(const ModuleEntry* module) const { diff --git a/src/hotspot/share/jfr/support/methodtracer/jfrFilterManager.cpp b/src/hotspot/share/jfr/support/methodtracer/jfrFilterManager.cpp index d9081efa08c..ea031f9f205 100644 --- a/src/hotspot/share/jfr/support/methodtracer/jfrFilterManager.cpp +++ b/src/hotspot/share/jfr/support/methodtracer/jfrFilterManager.cpp @@ -130,10 +130,10 @@ bool JfrFilterManager::install(jobjectArray classes, jobjectArray methods, jobje modifications[i] = modification_tah->int_at(i); } if (class_size != method_size || class_size != annotation_size || class_size != modification_size) { - FREE_C_HEAP_ARRAY(Symbol*, class_names); - FREE_C_HEAP_ARRAY(Symbol*, method_names); - FREE_C_HEAP_ARRAY(Symbol*, annotation_names); - FREE_C_HEAP_ARRAY(int, modifications); + FREE_C_HEAP_ARRAY(class_names); + FREE_C_HEAP_ARRAY(method_names); + FREE_C_HEAP_ARRAY(annotation_names); + FREE_C_HEAP_ARRAY(modifications); JfrJavaSupport::throw_internal_error("Method array sizes don't match", jt); return false; } diff --git a/src/hotspot/share/jfr/utilities/jfrConcurrentHashtable.inline.hpp b/src/hotspot/share/jfr/utilities/jfrConcurrentHashtable.inline.hpp index 6d6908234a3..22028a96e55 100644 --- a/src/hotspot/share/jfr/utilities/jfrConcurrentHashtable.inline.hpp +++ b/src/hotspot/share/jfr/utilities/jfrConcurrentHashtable.inline.hpp @@ -59,7 +59,7 @@ inline JfrConcurrentHashtable::JfrConcurrentHashtable(uns template class TableEntry> inline JfrConcurrentHashtable::~JfrConcurrentHashtable() { - FREE_C_HEAP_ARRAY(Bucket, _buckets); + FREE_C_HEAP_ARRAY(_buckets); } template class TableEntry> diff --git a/src/hotspot/share/jfr/utilities/jfrHashtable.hpp b/src/hotspot/share/jfr/utilities/jfrHashtable.hpp index 0be2d92ed19..ce4c920cf8b 100644 --- a/src/hotspot/share/jfr/utilities/jfrHashtable.hpp +++ b/src/hotspot/share/jfr/utilities/jfrHashtable.hpp @@ -93,7 +93,7 @@ class JfrBasicHashtable : public CHeapObj { --_number_of_entries; } void free_buckets() { - FREE_C_HEAP_ARRAY(Bucket, _buckets); + FREE_C_HEAP_ARRAY(_buckets); } TableEntry* bucket(size_t i) { return _buckets[i].get_entry();} TableEntry** bucket_addr(size_t i) { return _buckets[i].entry_addr(); } diff --git a/src/hotspot/share/jfr/utilities/jfrSet.hpp b/src/hotspot/share/jfr/utilities/jfrSet.hpp index c443434800a..3e828d51ec3 100644 --- a/src/hotspot/share/jfr/utilities/jfrSet.hpp +++ b/src/hotspot/share/jfr/utilities/jfrSet.hpp @@ -82,7 +82,7 @@ class JfrSetStorage : public AnyObj { ~JfrSetStorage() { if (CONFIG::alloc_type() == C_HEAP) { - FREE_C_HEAP_ARRAY(K, _table); + FREE_C_HEAP_ARRAY(_table); } } @@ -160,7 +160,7 @@ class JfrSet : public JfrSetStorage { } } if (CONFIG::alloc_type() == AnyObj::C_HEAP) { - FREE_C_HEAP_ARRAY(K, old_table); + FREE_C_HEAP_ARRAY(old_table); } assert(_table_mask + 1 == this->_table_size, "invariant"); assert(_resize_threshold << 1 == this->_table_size, "invariant"); diff --git a/src/hotspot/share/libadt/vectset.cpp b/src/hotspot/share/libadt/vectset.cpp index 176660d8302..bd9e97d9877 100644 --- a/src/hotspot/share/libadt/vectset.cpp +++ b/src/hotspot/share/libadt/vectset.cpp @@ -51,7 +51,7 @@ void VectorSet::grow(uint new_word_capacity) { assert(new_word_capacity < (1U << 30), ""); uint x = next_power_of_2(new_word_capacity); if (x > _data_size) { - _data = REALLOC_ARENA_ARRAY(_set_arena, uint32_t, _data, _size, x); + _data = REALLOC_ARENA_ARRAY(_set_arena, _data, _size, x); _data_size = x; } Copy::zero_to_bytes(_data + _size, (x - _size) * sizeof(uint32_t)); diff --git a/src/hotspot/share/logging/logAsyncWriter.hpp b/src/hotspot/share/logging/logAsyncWriter.hpp index a93b1ca58f6..933482929c7 100644 --- a/src/hotspot/share/logging/logAsyncWriter.hpp +++ b/src/hotspot/share/logging/logAsyncWriter.hpp @@ -124,7 +124,7 @@ class AsyncLogWriter : public NonJavaThread { } ~Buffer() { - FREE_C_HEAP_ARRAY(char, _buf); + FREE_C_HEAP_ARRAY(_buf); } void push_flush_token(); diff --git a/src/hotspot/share/logging/logConfiguration.cpp b/src/hotspot/share/logging/logConfiguration.cpp index b883dbccacf..1ba45cc050f 100644 --- a/src/hotspot/share/logging/logConfiguration.cpp +++ b/src/hotspot/share/logging/logConfiguration.cpp @@ -123,7 +123,7 @@ void LogConfiguration::initialize(jlong vm_start_time) { void LogConfiguration::finalize() { disable_outputs(); - FREE_C_HEAP_ARRAY(LogOutput*, _outputs); + FREE_C_HEAP_ARRAY(_outputs); } // Normalizes the given LogOutput name to type=name form. @@ -206,7 +206,7 @@ LogOutput* LogConfiguration::new_output(const char* name, size_t LogConfiguration::add_output(LogOutput* output) { size_t idx = _n_outputs++; - _outputs = REALLOC_C_HEAP_ARRAY(LogOutput*, _outputs, _n_outputs, mtLogging); + _outputs = REALLOC_C_HEAP_ARRAY(_outputs, _n_outputs, mtLogging); _outputs[idx] = output; return idx; } @@ -218,7 +218,7 @@ void LogConfiguration::delete_output(size_t idx) { LogOutput* output = _outputs[idx]; // Swap places with the last output and shrink the array _outputs[idx] = _outputs[--_n_outputs]; - _outputs = REALLOC_C_HEAP_ARRAY(LogOutput*, _outputs, _n_outputs, mtLogging); + _outputs = REALLOC_C_HEAP_ARRAY(_outputs, _n_outputs, mtLogging); delete output; } @@ -546,7 +546,7 @@ bool LogConfiguration::parse_log_arguments(const char* outputstr, } } - FREE_C_HEAP_ARRAY(char, normalized); + FREE_C_HEAP_ARRAY(normalized); if (idx == SIZE_MAX) { return false; } @@ -724,8 +724,7 @@ void LogConfiguration::register_update_listener(UpdateListenerFunction cb) { assert(cb != nullptr, "Should not register nullptr as listener"); ConfigurationLock cl; size_t idx = _n_listener_callbacks++; - _listener_callbacks = REALLOC_C_HEAP_ARRAY(UpdateListenerFunction, - _listener_callbacks, + _listener_callbacks = REALLOC_C_HEAP_ARRAY(_listener_callbacks, _n_listener_callbacks, mtLogging); _listener_callbacks[idx] = cb; diff --git a/src/hotspot/share/logging/logFileOutput.cpp b/src/hotspot/share/logging/logFileOutput.cpp index 9d6d19d739e..c805a3e1077 100644 --- a/src/hotspot/share/logging/logFileOutput.cpp +++ b/src/hotspot/share/logging/logFileOutput.cpp @@ -160,8 +160,8 @@ static uint next_file_number(const char* filename, } } - FREE_C_HEAP_ARRAY(char, oldest_name); - FREE_C_HEAP_ARRAY(char, archive_name); + FREE_C_HEAP_ARRAY(oldest_name); + FREE_C_HEAP_ARRAY(archive_name); return next_num; } diff --git a/src/hotspot/share/logging/logMessageBuffer.cpp b/src/hotspot/share/logging/logMessageBuffer.cpp index 8f308b1f015..4714cd65f8a 100644 --- a/src/hotspot/share/logging/logMessageBuffer.cpp +++ b/src/hotspot/share/logging/logMessageBuffer.cpp @@ -31,7 +31,7 @@ static void grow(T*& buffer, size_t& capacity, size_t minimum_length = 0) { if (new_size < minimum_length) { new_size = minimum_length; } - buffer = REALLOC_C_HEAP_ARRAY(T, buffer, new_size, mtLogging); + buffer = REALLOC_C_HEAP_ARRAY(buffer, new_size, mtLogging); capacity = new_size; } @@ -48,8 +48,8 @@ LogMessageBuffer::LogMessageBuffer() : _message_buffer_size(0), LogMessageBuffer::~LogMessageBuffer() { if (_allocated) { - FREE_C_HEAP_ARRAY(char, _message_buffer); - FREE_C_HEAP_ARRAY(LogLine, _lines); + FREE_C_HEAP_ARRAY(_message_buffer); + FREE_C_HEAP_ARRAY(_lines); } } diff --git a/src/hotspot/share/logging/logOutput.cpp b/src/hotspot/share/logging/logOutput.cpp index e3c68b49b13..f74e614e539 100644 --- a/src/hotspot/share/logging/logOutput.cpp +++ b/src/hotspot/share/logging/logOutput.cpp @@ -181,7 +181,7 @@ static void add_selections(LogSelection** selections, // Ensure there's enough room for both wildcard_match and exact_match if (*n_selections + 2 > *selections_cap) { *selections_cap *= 2; - *selections = REALLOC_C_HEAP_ARRAY(LogSelection, *selections, *selections_cap, mtLogging); + *selections = REALLOC_C_HEAP_ARRAY(*selections, *selections_cap, mtLogging); } // Add found matching selections to the result array @@ -317,8 +317,8 @@ void LogOutput::update_config_string(const size_t on_level[LogLevel::Count]) { break; } } - FREE_C_HEAP_ARRAY(LogTagSet*, deviates); - FREE_C_HEAP_ARRAY(Selection, selections); + FREE_C_HEAP_ARRAY(deviates); + FREE_C_HEAP_ARRAY(selections); } bool LogOutput::parse_options(const char* options, outputStream* errstream) { diff --git a/src/hotspot/share/logging/logTagSet.cpp b/src/hotspot/share/logging/logTagSet.cpp index 667c76ec306..28b0d697b14 100644 --- a/src/hotspot/share/logging/logTagSet.cpp +++ b/src/hotspot/share/logging/logTagSet.cpp @@ -215,5 +215,5 @@ void LogTagSet::list_all_tagsets(outputStream* out) { os::free(tagset_labels[idx]); } out->cr(); - FREE_C_HEAP_ARRAY(char*, tagset_labels); + FREE_C_HEAP_ARRAY(tagset_labels); } diff --git a/src/hotspot/share/memory/allocation.cpp b/src/hotspot/share/memory/allocation.cpp index 2a109688ca6..f5e4e1f3df6 100644 --- a/src/hotspot/share/memory/allocation.cpp +++ b/src/hotspot/share/memory/allocation.cpp @@ -28,6 +28,7 @@ #include "memory/metaspace.hpp" #include "memory/resourceArea.hpp" #include "nmt/memTracker.hpp" +#include "runtime/atomicAccess.hpp" #include "runtime/os.hpp" #include "runtime/task.hpp" #include "utilities/ostream.hpp" @@ -66,9 +67,24 @@ void FreeHeap(void* p) { os::free(p); } +// These are used by the Serviceability Agent even if CDS is disabled void* MetaspaceObj::_aot_metaspace_base = nullptr; void* MetaspaceObj::_aot_metaspace_top = nullptr; +#if INCLUDE_CDS +volatile bool MetaspaceObj::_aot_metaspace_range_initialized = false; + +void MetaspaceObj::set_aot_metaspace_range(void* base, void* top) { + _aot_metaspace_base = base; + _aot_metaspace_top = top; + AtomicAccess::release_store(&_aot_metaspace_range_initialized, true); +} + +bool MetaspaceObj::aot_metaspace_range_initialized() { + return AtomicAccess::load_acquire(&_aot_metaspace_range_initialized); +} +#endif + void* MetaspaceObj::operator new(size_t size, ClassLoaderData* loader_data, size_t word_size, MetaspaceObj::Type type, TRAPS) throw() { @@ -168,7 +184,8 @@ void AnyObj::set_in_aot_cache() { } bool AnyObj::in_aot_cache() const { - if (AOTMetaspace::in_aot_cache(this)) { + if (MetaspaceObj::is_pointer_in_aot_cache(this)) { + // "this" can be AOT space only if aot_metaspace_range_initialized() precond(_allocation_t[0] == 0); precond(_allocation_t[1] == 0); return true; diff --git a/src/hotspot/share/memory/allocation.hpp b/src/hotspot/share/memory/allocation.hpp index 15b7750a363..a49f9ce9a0b 100644 --- a/src/hotspot/share/memory/allocation.hpp +++ b/src/hotspot/share/memory/allocation.hpp @@ -95,7 +95,7 @@ typedef AllocFailStrategy::AllocFailEnum AllocFailType; // // char* AllocateHeap(size_t size, MemTag mem_tag, const NativeCallStack& stack, AllocFailType alloc_failmode = AllocFailStrategy::EXIT_OOM); // char* AllocateHeap(size_t size, MemTag mem_tag, AllocFailType alloc_failmode = AllocFailStrategy::EXIT_OOM); -// char* ReallocateHeap(char *old, size_t size, MemTag mem_tag, AllocFailType alloc_failmode = AllocFailStrategy::EXIT_OOM); +// char* ReallocateHeap(char* old, size_t size, MemTag mem_tag, AllocFailType alloc_failmode = AllocFailStrategy::EXIT_OOM); // void FreeHeap(void* p); // @@ -112,7 +112,7 @@ char* AllocateHeap(size_t size, MemTag mem_tag, AllocFailType alloc_failmode = AllocFailStrategy::EXIT_OOM); -char* ReallocateHeap(char *old, +char* ReallocateHeap(char* old, size_t size, MemTag mem_tag, AllocFailType alloc_failmode = AllocFailStrategy::EXIT_OOM); @@ -260,11 +260,8 @@ class MetaspaceObj { // void deallocate_contents(ClassLoaderData* loader_data); friend class VMStructs; - // All metsapce objects in the AOT cache (CDS archive) are mapped - // into a single contiguous memory block, so we can use these - // two pointers to quickly determine if a MetaspaceObj is in the - // AOT cache. - // When AOT/CDS is not enabled, both pointers are set to null. + + // These are used by the Serviceability Agent even if CDS is disabled static void* _aot_metaspace_base; // (inclusive) low address static void* _aot_metaspace_top; // (exclusive) high address @@ -275,28 +272,48 @@ class MetaspaceObj { // regular- or aot metaspace. static bool is_valid(const MetaspaceObj* p); -#if INCLUDE_CDS - static bool in_aot_cache(const MetaspaceObj* p) { +#if !INCLUDE_CDS + static bool is_pointer_in_aot_cache(const void* p) { return false; } + static bool is_pointer_in_aot_cache_no_init_check(const void* p) { return false; } +#else +private: + // All metsapce objects in the AOT cache (CDS archive) are mapped + // into a single contiguous memory block, so we can use these + // two pointers to quickly determine if a MetaspaceObj is in the + // AOT cache. + // When AOT/CDS is not enabled, both pointers are set to null. + static volatile bool _aot_metaspace_range_initialized; + static bool aot_metaspace_range_initialized(); + +public: + inline static bool is_pointer_in_aot_cache(const void* p) { + return aot_metaspace_range_initialized() && is_pointer_in_aot_cache_no_init_check(p); + } + + // Call this ONLY if you know that the AOT metaspace has already been initialized. + inline static bool is_pointer_in_aot_cache_no_init_check(const void* p) { + precond(aot_metaspace_range_initialized()); + // If no shared metaspace regions are mapped, _aot_metaspace_{base,top} will // both be null and all values of p will be rejected quickly. - return (((void*)p) < _aot_metaspace_top && - ((void*)p) >= _aot_metaspace_base); + return (p < _aot_metaspace_top && + p >= _aot_metaspace_base); } - bool in_aot_cache() const { return MetaspaceObj::in_aot_cache(this); } -#else - static bool in_aot_cache(const MetaspaceObj* p) { return false; } - bool in_aot_cache() const { return false; } -#endif - void print_address_on(outputStream* st) const; // nonvirtual address printing - - static void set_aot_metaspace_range(void* base, void* top) { - _aot_metaspace_base = base; - _aot_metaspace_top = top; - } + static void set_aot_metaspace_range(void* base, void* top); static void* aot_metaspace_base() { return _aot_metaspace_base; } static void* aot_metaspace_top() { return _aot_metaspace_top; } +#endif // INCLUDE_CDS + + bool in_aot_cache() const { + // MetaspaceObjects are only created or loaded from the AOT cache after + // the AOT metaspace has been initialized, so we can skip init checks. + return is_pointer_in_aot_cache_no_init_check(this); + } + + void print_address_on(outputStream* st) const; // nonvirtual address printing + #define METASPACE_OBJ_TYPES_DO(f) \ f(Class) \ @@ -374,9 +391,9 @@ extern char* resource_allocate_bytes(size_t size, AllocFailType alloc_failmode = AllocFailStrategy::EXIT_OOM); extern char* resource_allocate_bytes(Thread* thread, size_t size, AllocFailType alloc_failmode = AllocFailStrategy::EXIT_OOM); -extern char* resource_reallocate_bytes( char *old, size_t old_size, size_t new_size, +extern char* resource_reallocate_bytes(char* old, size_t old_size, size_t new_size, AllocFailType alloc_failmode = AllocFailStrategy::EXIT_OOM); -extern void resource_free_bytes( Thread* thread, char *old, size_t size ); +extern void resource_free_bytes(Thread* thread, char* obj, size_t size); //---------------------------------------------------------------------- // Base class for objects allocated in the resource area. @@ -479,6 +496,8 @@ protected: #endif // PRODUCT }; +#define REALLOC_RETURN_TYPE(old) typename std::remove_reference::type + // One of the following macros must be used when allocating an array // or object to determine whether it should reside in the C heap on in // the resource area. @@ -495,21 +514,18 @@ protected: #define NEW_RESOURCE_ARRAY_IN_THREAD_RETURN_NULL(thread, type, size)\ (type*) resource_allocate_bytes(thread, (size) * sizeof(type), AllocFailStrategy::RETURN_NULL) -#define REALLOC_RESOURCE_ARRAY(type, old, old_size, new_size)\ - (type*) resource_reallocate_bytes((char*)(old), (old_size) * sizeof(type), (new_size) * sizeof(type)) +#define REALLOC_RESOURCE_ARRAY(old, old_size, new_size)\ + (REALLOC_RETURN_TYPE(old)) resource_reallocate_bytes((char*)(old), (old_size) * sizeof(*old), (new_size) * sizeof(*old)) -#define REALLOC_RESOURCE_ARRAY_RETURN_NULL(type, old, old_size, new_size)\ - (type*) resource_reallocate_bytes((char*)(old), (old_size) * sizeof(type),\ - (new_size) * sizeof(type), AllocFailStrategy::RETURN_NULL) +#define REALLOC_RESOURCE_ARRAY_RETURN_NULL(old, old_size, new_size)\ + (REALLOC_RETURN_TYPE(old)) resource_reallocate_bytes((char*)(old), (old_size) * sizeof(*old), \ + (new_size) * sizeof(*old), AllocFailStrategy::RETURN_NULL) -#define FREE_RESOURCE_ARRAY(type, old, size)\ - resource_free_bytes(Thread::current(), (char*)(old), (size) * sizeof(type)) +#define FREE_RESOURCE_ARRAY(obj, size)\ + resource_free_bytes(Thread::current(), (char*)(obj), (size) * sizeof(*obj)) -#define FREE_RESOURCE_ARRAY_IN_THREAD(thread, type, old, size)\ - resource_free_bytes(thread, (char*)(old), (size) * sizeof(type)) - -#define FREE_FAST(old)\ - /* nop */ +#define FREE_RESOURCE_ARRAY_IN_THREAD(thread, obj, size)\ + resource_free_bytes(thread, (char*)(obj), (size) * sizeof(*obj)) #define NEW_RESOURCE_OBJ(type)\ NEW_RESOURCE_ARRAY(type, 1) @@ -532,14 +548,14 @@ protected: #define NEW_C_HEAP_ARRAY_RETURN_NULL(type, size, mem_tag)\ NEW_C_HEAP_ARRAY2(type, (size), mem_tag, AllocFailStrategy::RETURN_NULL) -#define REALLOC_C_HEAP_ARRAY(type, old, size, mem_tag)\ - (type*) (ReallocateHeap((char*)(old), (size) * sizeof(type), mem_tag)) +#define REALLOC_C_HEAP_ARRAY(old, size, mem_tag)\ + (REALLOC_RETURN_TYPE(old)) ReallocateHeap((char*)(old), (size) * sizeof(*old), mem_tag) -#define REALLOC_C_HEAP_ARRAY_RETURN_NULL(type, old, size, mem_tag)\ - (type*) (ReallocateHeap((char*)(old), (size) * sizeof(type), mem_tag, AllocFailStrategy::RETURN_NULL)) +#define REALLOC_C_HEAP_ARRAY_RETURN_NULL(old, size, mem_tag)\ + (REALLOC_RETURN_TYPE(old)) ReallocateHeap((char*)(old), (size) * sizeof(*old), mem_tag, AllocFailStrategy::RETURN_NULL) -#define FREE_C_HEAP_ARRAY(type, old) \ - FreeHeap((char*)(old)) +#define FREE_C_HEAP_ARRAY(obj) \ + FreeHeap((void*)(obj)) // allocate type in heap without calling ctor #define NEW_C_HEAP_OBJ(type, mem_tag)\ @@ -548,9 +564,9 @@ protected: #define NEW_C_HEAP_OBJ_RETURN_NULL(type, mem_tag)\ NEW_C_HEAP_ARRAY_RETURN_NULL(type, 1, mem_tag) -// deallocate obj of type in heap without calling dtor -#define FREE_C_HEAP_OBJ(objname)\ - FreeHeap((char*)objname); +// deallocate obj in heap without calling dtor +#define FREE_C_HEAP_OBJ(obj)\ + FREE_C_HEAP_ARRAY(obj) //------------------------------ReallocMark--------------------------------- diff --git a/src/hotspot/share/memory/arena.hpp b/src/hotspot/share/memory/arena.hpp index 7d88c79ca52..252e511f615 100644 --- a/src/hotspot/share/memory/arena.hpp +++ b/src/hotspot/share/memory/arena.hpp @@ -240,12 +240,12 @@ private: #define NEW_ARENA_ARRAY(arena, type, size) \ (type*) (arena)->Amalloc((size) * sizeof(type)) -#define REALLOC_ARENA_ARRAY(arena, type, old, old_size, new_size) \ - (type*) (arena)->Arealloc((char*)(old), (old_size) * sizeof(type), \ - (new_size) * sizeof(type) ) +#define REALLOC_ARENA_ARRAY(arena, old, old_size, new_size) \ + (REALLOC_RETURN_TYPE(old)) (arena)->Arealloc((char*)(old), (old_size) * sizeof(*old), \ + (new_size) * sizeof(*old) ) -#define FREE_ARENA_ARRAY(arena, type, old, size) \ - (arena)->Afree((char*)(old), (size) * sizeof(type)) +#define FREE_ARENA_ARRAY(arena, obj, size) \ + (arena)->Afree((char*)(obj), (size) * sizeof(*obj)) #define NEW_ARENA_OBJ(arena, type) \ NEW_ARENA_ARRAY(arena, type, 1) diff --git a/src/hotspot/share/memory/heapInspection.cpp b/src/hotspot/share/memory/heapInspection.cpp index aae3c99a634..5abb7e4ddcc 100644 --- a/src/hotspot/share/memory/heapInspection.cpp +++ b/src/hotspot/share/memory/heapInspection.cpp @@ -189,7 +189,7 @@ KlassInfoTable::~KlassInfoTable() { for (int index = 0; index < _num_buckets; index++) { _buckets[index].empty(); } - FREE_C_HEAP_ARRAY(KlassInfoBucket, _buckets); + FREE_C_HEAP_ARRAY(_buckets); _buckets = nullptr; } } diff --git a/src/hotspot/share/memory/memRegion.cpp b/src/hotspot/share/memory/memRegion.cpp index 3c481926025..dde4b0ace9a 100644 --- a/src/hotspot/share/memory/memRegion.cpp +++ b/src/hotspot/share/memory/memRegion.cpp @@ -115,5 +115,5 @@ void MemRegion::destroy_array(MemRegion* array, size_t length) { for (size_t i = 0; i < length; i++) { array[i].~MemRegion(); } - FREE_C_HEAP_ARRAY(MemRegion, array); + FREE_C_HEAP_ARRAY(array); } diff --git a/src/hotspot/share/memory/metaspace.cpp b/src/hotspot/share/memory/metaspace.cpp index da6ebc991c8..b97ae9ab540 100644 --- a/src/hotspot/share/memory/metaspace.cpp +++ b/src/hotspot/share/memory/metaspace.cpp @@ -739,6 +739,9 @@ void Metaspace::global_initialize() { AOTMetaspace::initialize_runtime_shared_and_meta_spaces(); // If any of the archived space fails to map, UseSharedSpaces // is reset to false. + } else { + // Trivially set the range to empty to satisfy the assert in MetaspaceObj::is_pointer_in_aot_cache() + MetaspaceObj::set_aot_metaspace_range(nullptr, nullptr); } #endif // INCLUDE_CDS diff --git a/src/hotspot/share/memory/metaspace/rootChunkArea.cpp b/src/hotspot/share/memory/metaspace/rootChunkArea.cpp index a178e122788..39407b46999 100644 --- a/src/hotspot/share/memory/metaspace/rootChunkArea.cpp +++ b/src/hotspot/share/memory/metaspace/rootChunkArea.cpp @@ -473,7 +473,7 @@ RootChunkAreaLUT::~RootChunkAreaLUT() { for (int i = 0; i < _num; i++) { _arr[i].~RootChunkArea(); } - FREE_C_HEAP_ARRAY(RootChunkArea, _arr); + FREE_C_HEAP_ARRAY(_arr); } #ifdef ASSERT diff --git a/src/hotspot/share/memory/metaspaceClosure.hpp b/src/hotspot/share/memory/metaspaceClosure.hpp index ac42dd13c6c..20e5528e9bc 100644 --- a/src/hotspot/share/memory/metaspaceClosure.hpp +++ b/src/hotspot/share/memory/metaspaceClosure.hpp @@ -37,19 +37,6 @@ #include "utilities/macros.hpp" #include "utilities/resizableHashTable.hpp" -// This macro just check for the existence of a member with the name "metaspace_pointers_do". If the -// parameter list is not (MetaspaceClosure* it), you will get a compilation error. -#define HAS_METASPACE_POINTERS_DO(T) HasMetaspacePointersDo::value - -template -class HasMetaspacePointersDo { - template static void* test(decltype(&U::metaspace_pointers_do)); - template static int test(...); - using test_type = decltype(test(nullptr)); -public: - static constexpr bool value = std::is_pointer_v; -}; - // class MetaspaceClosure -- // // This class is used for iterating the class metadata objects. It @@ -98,7 +85,6 @@ public: // only in the Metadata class. // // To work around the lack of a vtable, we use the Ref class with templates - // (see MSORef, OtherArrayRef, MSOArrayRef, and MSOPointerArrayRef) // so that we can statically discover the type of a object. The use of Ref // depends on the fact that: // @@ -194,15 +180,6 @@ private: return obj->size_in_heapwords(); } - static MetaspaceClosureType as_type(MetaspaceClosureType t) { - return t; - } - - static MetaspaceClosureType as_type(MetaspaceObj::Type msotype) { - precond(msotype < MetaspaceObj::_number_of_types); - return (MetaspaceClosureType)msotype; - } - // MSORef -- iterate an instance of T, where T::metaspace_pointers_do() exists. template class MSORef : public Ref { T** _mpp; @@ -210,99 +187,22 @@ private: return strip_tags(*_mpp); } protected: - virtual void** mpp() const { + virtual void** mpp() const override { return (void**)_mpp; } public: MSORef(T** mpp, Writability w) : Ref(w), _mpp(mpp) {} - virtual bool is_read_only_by_default() const { return T::is_read_only_by_default(); } - virtual bool not_null() const { return dereference() != nullptr; } - virtual int size() const { return get_size(dereference()); } - virtual MetaspaceClosureType type() const { return as_type(dereference()->type()); } - - virtual void metaspace_pointers_do(MetaspaceClosure *it) const { + virtual bool is_read_only_by_default() const override { return T::is_read_only_by_default(); } + virtual bool not_null() const override { return dereference() != nullptr; } + virtual int size() const override { return get_size(dereference()); } + virtual MetaspaceClosureType type() const override { return as_type(dereference()->type()); } + virtual void metaspace_pointers_do(MetaspaceClosure *it) const override { dereference()->metaspace_pointers_do(it); } }; - //--------------------- - // Support for Array - //--------------------- - - // Abstract base class for MSOArrayRef, MSOPointerArrayRef and OtherArrayRef. - // These are used for iterating Array. - template class ArrayRef : public Ref { - Array** _mpp; - protected: - Array* dereference() const { - return strip_tags(*_mpp); - } - virtual void** mpp() const { - return (void**)_mpp; - } - - ArrayRef(Array** mpp, Writability w) : Ref(w), _mpp(mpp) {} - - // all Arrays are read-only by default - virtual bool is_read_only_by_default() const { return true; } - virtual bool not_null() const { return dereference() != nullptr; } - virtual int size() const { return dereference()->size(); } - virtual MetaspaceClosureType type() const { return as_type(MetaspaceObj::array_type(sizeof(T))); } - }; - - // OtherArrayRef -- iterate an instance of Array, where T does NOT have metaspace_pointer_do(). - // T can be a primitive type, such as int, or a structure. However, we do not scan - // the fields inside T, so you should not embed any pointers inside T. - template class OtherArrayRef : public ArrayRef { - public: - OtherArrayRef(Array** mpp, Writability w) : ArrayRef(mpp, w) {} - - virtual void metaspace_pointers_do(MetaspaceClosure *it) const { - Array* array = ArrayRef::dereference(); - log_trace(aot)("Iter(OtherArray): %p [%d]", array, array->length()); - } - }; - - // MSOArrayRef -- iterate an instance of Array, where T has metaspace_pointer_do(). - // We recursively call T::metaspace_pointers_do() for each element in this array. - template class MSOArrayRef : public ArrayRef { - public: - MSOArrayRef(Array** mpp, Writability w) : ArrayRef(mpp, w) {} - - virtual void metaspace_pointers_do(MetaspaceClosure *it) const { - metaspace_pointers_do_at_impl(it, ArrayRef::dereference()); - } - private: - void metaspace_pointers_do_at_impl(MetaspaceClosure *it, Array* array) const { - log_trace(aot)("Iter(MSOArray): %p [%d]", array, array->length()); - for (int i = 0; i < array->length(); i++) { - T* elm = array->adr_at(i); - elm->metaspace_pointers_do(it); - } - } - }; - - // MSOPointerArrayRef -- iterate an instance of Array, where T has metaspace_pointer_do(). - // We recursively call MetaspaceClosure::push() for each pointer in this array. - template class MSOPointerArrayRef : public ArrayRef { - public: - MSOPointerArrayRef(Array** mpp, Writability w) : ArrayRef(mpp, w) {} - - virtual void metaspace_pointers_do(MetaspaceClosure *it) const { - metaspace_pointers_do_at_impl(it, ArrayRef::dereference()); - } - private: - void metaspace_pointers_do_at_impl(MetaspaceClosure *it, Array* array) const { - log_trace(aot)("Iter(MSOPointerArray): %p [%d]", array, array->length()); - for (int i = 0; i < array->length(); i++) { - T** mpp = array->adr_at(i); - it->push(mpp); - } - } - }; - //-------------------------------- // Support for GrowableArray //-------------------------------- @@ -314,28 +214,27 @@ private: return *_mpp; } - public: - GrowableArrayRef(GrowableArray** mpp, Writability w) : Ref(w), _mpp(mpp) {} - - virtual void** mpp() const { + protected: + virtual void** mpp() const override { return (void**)_mpp; } - virtual void metaspace_pointers_do(MetaspaceClosure *it) const { + public: + GrowableArrayRef(GrowableArray** mpp, Writability w) : Ref(w), _mpp(mpp) {} + + virtual bool is_read_only_by_default() const override { return false; } + virtual bool not_null() const override { return dereference() != nullptr; } + virtual int size() const override { return (int)heap_word_size(sizeof(*dereference())); } + virtual MetaspaceClosureType type() const override { return MetaspaceClosureType::GrowableArrayType; } + virtual void metaspace_pointers_do(MetaspaceClosure *it) const override { GrowableArray* array = dereference(); log_trace(aot)("Iter(GrowableArray): %p [%d]", array, array->length()); array->assert_on_C_heap(); it->push_c_array(array->data_addr(), array->capacity()); } - - virtual bool is_read_only_by_default() const { return false; } - virtual bool not_null() const { return dereference() != nullptr; } - virtual int size() const { return (int)heap_word_size(sizeof(*dereference())); } - virtual MetaspaceClosureType type() const { return MetaspaceClosureType::GrowableArrayType; } }; - // Abstract base class for MSOCArrayRef, MSOPointerCArrayRef and OtherCArrayRef. - // These are used for iterating the buffer held by GrowableArray. + // For iterating the buffer held by GrowableArray. template class CArrayRef : public Ref { T** _mpp; int _num_elems; // Number of elements @@ -344,83 +243,57 @@ private: return _num_elems * sizeof(T); } - protected: - // C pointer arrays don't support tagged pointers. + // Gives you back the GrowableArray::_data T* dereference() const { return *_mpp; } - virtual void** mpp() const { - return (void**)_mpp; - } + int num_elems() const { return _num_elems; } + + protected: + virtual void** mpp() const override { + return (void**)_mpp; + } + public: CArrayRef(T** mpp, int num_elems, Writability w) : Ref(w), _mpp(mpp), _num_elems(num_elems) { assert(is_aligned(byte_size(), BytesPerWord), "must be"); } - virtual bool is_read_only_by_default() const { return false; } - virtual bool not_null() const { return dereference() != nullptr; } - virtual int size() const { return (int)heap_word_size(byte_size()); } - virtual MetaspaceClosureType type() const { return MetaspaceClosureType::CArrayType; } - }; - - // OtherCArrayRef -- iterate a C array of type T, where T does NOT have metaspace_pointer_do(). - // T can be a primitive type, such as int, or a structure. However, we do not scan - // the fields inside T, so you should not embed any pointers inside T. - template class OtherCArrayRef : public CArrayRef { - public: - OtherCArrayRef(T** mpp, int num_elems, Writability w) : CArrayRef(mpp, num_elems, w) {} - - virtual void metaspace_pointers_do(MetaspaceClosure *it) const { - T* array = CArrayRef::dereference(); - log_trace(aot)("Iter(OtherCArray): %p [%d]", array, CArrayRef::num_elems()); + virtual bool is_read_only_by_default() const override { return false; } + virtual bool not_null() const override { precond(dereference() != nullptr); return true; } + virtual int size() const override { return (int)heap_word_size(byte_size()); } + virtual MetaspaceClosureType type() const override { return MetaspaceClosureType::CArrayType; } + virtual void metaspace_pointers_do(MetaspaceClosure *it) const override { + metaspace_pointers_do_impl(it, dereference()); } - }; - // MSOCArrayRef -- iterate a C array of type T, where T has metaspace_pointer_do(). - // We recursively call T::metaspace_pointers_do() for each element in this array. - // This is for supporting GrowableArray. - // - // E.g., PackageEntry* _pkg_entry_pointers[2]; // a buffer that has 2 PackageEntry objects - // ... - // it->push(&_pkg_entry_pointers, 2); - // /* calls _pkg_entry_pointers[0].metaspace_pointers_do(it); */ - // /* calls _pkg_entry_pointers[1].metaspace_pointers_do(it); */ - template class MSOCArrayRef : public CArrayRef { - public: - MSOCArrayRef(T** mpp, int num_elems, Writability w) : CArrayRef(mpp, num_elems, w) {} + private: + // E.g., GrowableArray + template ::value && !HAS_METASPACE_POINTERS_DO(U))> + void metaspace_pointers_do_impl(MetaspaceClosure* it, T* array) const { + log_trace(aot)("Iter(OtherCArray): %p [%d]", array, num_elems()); + } - virtual void metaspace_pointers_do(MetaspaceClosure *it) const { - T* array = CArrayRef::dereference(); - log_trace(aot)("Iter(MSOCArray): %p [%d]", array, CArrayRef::num_elems()); - for (int i = 0; i < CArrayRef::num_elems(); i++) { + // E.g., GrowableArray + template ::value && HAS_METASPACE_POINTERS_DO(U))> + void metaspace_pointers_do_impl(MetaspaceClosure* it, T* array) const { + log_trace(aot)("Iter(MSOCArray): %p [%d]", array, num_elems()); + for (int i = 0; i < num_elems(); i++) { T* elm = array + i; elm->metaspace_pointers_do(it); } } - }; - // MSOPointerCArrayRef -- iterate a C array of type T*, where T has metaspace_pointer_do(). - // We recursively call MetaspaceClosure::push() for each pointer in this array. - // This is for supporting GrowableArray. - // - // E.g., PackageEntry** _pkg_entry_pointers[2]; // a buffer that has 2 PackageEntry pointers - // ... - // it->push(&_pkg_entry_pointers, 2); - // /* calls _pkg_entry_pointers[0]->metaspace_pointers_do(it); */ - // /* calls _pkg_entry_pointers[1]->metaspace_pointers_do(it); */ - template class MSOPointerCArrayRef : public CArrayRef { - public: - MSOPointerCArrayRef(T*** mpp, int num_elems, Writability w) : CArrayRef(mpp, num_elems, w) {} - - virtual void metaspace_pointers_do(MetaspaceClosure *it) const { - T** array = CArrayRef::dereference(); - log_trace(aot)("Iter(MSOPointerCArray): %p [%d]", array, CArrayRef::num_elems()); - for (int i = 0; i < CArrayRef::num_elems(); i++) { - T** mpp = array + i; + // E.g., GrowableArray + template ::value && HAS_METASPACE_POINTERS_DO(typename std::remove_pointer::type))> + void metaspace_pointers_do_impl(MetaspaceClosure* it, T* array) const { + log_trace(aot)("Iter(MSOPointerCArray): %p [%d]", array, num_elems()); + for (int i = 0; i < num_elems(); i++) { + T* mpp = array + i; it->push(mpp); } } @@ -462,17 +335,12 @@ public: // // MetaspaceClosure* it = ...; // Klass* o = ...; it->push(&o); => MSORef - // Array* a1 = ...; it->push(&a1); => OtherArrayRef - // Array* a2 = ...; it->push(&a2); => MSOArrayRef - // Array* a3 = ...; it->push(&a3); => MSOPointerArrayRef - // Array*>* a4 = ...; it->push(&a4); => MSOPointerArrayRef - // Array* a5 = ...; it->push(&a5); => MSOPointerArrayRef // // GrowableArrays have a separate "C array" buffer, so they are scanned in two steps: // - // GrowableArray* ga1 = ...; it->push(&ga1); => GrowableArrayRef => OtherCArrayRef - // GrowableArray* ga2 = ...; it->push(&ga2); => GrowableArrayRef => MSOCArrayRef - // GrowableArray* ga3 = ...; it->push(&ga3); => GrowableArrayRef => MSOPointerCArrayRef + // GrowableArray* ga1 = ...; it->push(&ga1); => GrowableArrayRef => CArrayRef + // GrowableArray* ga2 = ...; it->push(&ga2); => GrowableArrayRef => CArrayRef + // GrowableArray* ga3 = ...; it->push(&ga3); => GrowableArrayRef => CArrayRef // // Note that the following will fail to compile: // @@ -487,43 +355,15 @@ public: push_with_ref>(mpp, w); } - // --- Array - template - void push(Array** mpp, Writability w = _default) { - push_with_ref>(mpp, w); - } - - template - void push(Array** mpp, Writability w = _default) { - push_with_ref>(mpp, w); - } - - template - void push(Array** mpp, Writability w = _default) { - static_assert(HAS_METASPACE_POINTERS_DO(T), "Do not push Arrays of arbitrary pointer types"); - push_with_ref>(mpp, w); - } - template void push(GrowableArray** mpp, Writability w = _default) { push_with_ref>(mpp, w); } // --- The buffer of GrowableArray - template - void push_c_array(T** mpp, int num_elems, Writability w = _default) { - push_impl(new OtherCArrayRef(mpp, num_elems, w)); - } - - template - void push_c_array(T** mpp, int num_elems, Writability w = _default) { - push_impl(new MSOCArrayRef(mpp, num_elems, w)); - } - template - void push_c_array(T*** mpp, int num_elems, Writability w = _default) { - static_assert(HAS_METASPACE_POINTERS_DO(T), "Do not push C arrays of arbitrary pointer types"); - push_impl(new MSOPointerCArrayRef(mpp, num_elems, w)); + void push_c_array(T** mpp, int num_elems, Writability w = _default) { + push_impl(new CArrayRef(mpp, num_elems, w)); } }; diff --git a/src/hotspot/share/memory/metaspaceClosureType.hpp b/src/hotspot/share/memory/metaspaceClosureType.hpp index adf6805521b..2dbba34ab67 100644 --- a/src/hotspot/share/memory/metaspaceClosureType.hpp +++ b/src/hotspot/share/memory/metaspaceClosureType.hpp @@ -26,6 +26,7 @@ #define SHARE_MEMORY_METASPACECLOSURETYPE_HPP #include "memory/allocation.hpp" +#include "metaprogramming/enableIf.hpp" // MetaspaceClosure is able to iterate on MetaspaceObjs, plus the following classes #define METASPACE_CLOSURE_TYPES_DO(f) \ @@ -42,5 +43,29 @@ enum class MetaspaceClosureType : int { _number_of_types }; +inline MetaspaceClosureType as_type(MetaspaceClosureType t) { + return t; +} + +inline MetaspaceClosureType as_type(MetaspaceObj::Type msotype) { + precond(msotype < MetaspaceObj::_number_of_types); + return (MetaspaceClosureType)msotype; +} + +// This macro checks for the existence of a member with the name metaspace_pointers_do +#define HAS_METASPACE_POINTERS_DO(T) HasMetaspacePointersDo::value + +template +class HasMetaspacePointersDo { + template static void* test(decltype(&U::metaspace_pointers_do)); + template static int test(...); + + // - If the first template matches, test_type will be void* + // - If the first template doesn't match, test will match second template, + // and test_type will be int + using test_type = decltype(test(nullptr)); +public: + static constexpr bool value = std::is_pointer_v; +}; #endif // SHARE_MEMORY_METASPACECLOSURETYPE_HPP diff --git a/src/hotspot/share/memory/resourceArea.cpp b/src/hotspot/share/memory/resourceArea.cpp index bab652c17ea..63f7ed61d17 100644 --- a/src/hotspot/share/memory/resourceArea.cpp +++ b/src/hotspot/share/memory/resourceArea.cpp @@ -70,10 +70,10 @@ extern char* resource_allocate_bytes(Thread* thread, size_t size, AllocFailType return thread->resource_area()->allocate_bytes(size, alloc_failmode); } -extern char* resource_reallocate_bytes( char *old, size_t old_size, size_t new_size, AllocFailType alloc_failmode){ +extern char* resource_reallocate_bytes(char* old, size_t old_size, size_t new_size, AllocFailType alloc_failmode){ return (char*)Thread::current()->resource_area()->Arealloc(old, old_size, new_size, alloc_failmode); } -extern void resource_free_bytes( Thread* thread, char *old, size_t size ) { - thread->resource_area()->Afree(old, size); +extern void resource_free_bytes(Thread* thread, char* obj, size_t size) { + thread->resource_area()->Afree(obj, size); } diff --git a/src/hotspot/share/memory/universe.cpp b/src/hotspot/share/memory/universe.cpp index a78b245cc07..aecaa1cac22 100644 --- a/src/hotspot/share/memory/universe.cpp +++ b/src/hotspot/share/memory/universe.cpp @@ -1256,7 +1256,7 @@ void Universe::initialize_verify_flags() { } token = strtok_r(nullptr, delimiter, &save_ptr); } - FREE_C_HEAP_ARRAY(char, subset_list); + FREE_C_HEAP_ARRAY(subset_list); } bool Universe::should_verify_subset(uint subset) { diff --git a/src/hotspot/share/nmt/nmtNativeCallStackStorage.cpp b/src/hotspot/share/nmt/nmtNativeCallStackStorage.cpp index 9a2ecd57ecc..bbf93c5d898 100644 --- a/src/hotspot/share/nmt/nmtNativeCallStackStorage.cpp +++ b/src/hotspot/share/nmt/nmtNativeCallStackStorage.cpp @@ -55,7 +55,7 @@ NativeCallStackStorage::NativeCallStackStorage(bool is_detailed_mode, int table_ } } NativeCallStackStorage::~NativeCallStackStorage() { - FREE_C_HEAP_ARRAY(LinkPtr, _table); + FREE_C_HEAP_ARRAY(_table); } NativeCallStackStorage::NativeCallStackStorage(const NativeCallStackStorage& other) diff --git a/src/hotspot/share/nmt/vmatree.cpp b/src/hotspot/share/nmt/vmatree.cpp index 6c5ab691f6d..1fc05133d22 100644 --- a/src/hotspot/share/nmt/vmatree.cpp +++ b/src/hotspot/share/nmt/vmatree.cpp @@ -807,7 +807,7 @@ void VMATree::SummaryDiff::grow_and_rehash() { // Clear previous -- if applicable if (_members != _small) { - FREE_C_HEAP_ARRAY(KVEntry, _members); + FREE_C_HEAP_ARRAY(_members); } _members = NEW_C_HEAP_ARRAY(KVEntry, new_len, mtNMT); @@ -847,7 +847,7 @@ void VMATree::SummaryDiff::add(const SummaryDiff& other) { void VMATree::SummaryDiff::clear() { if (_members != _small) { - FREE_C_HEAP_ARRAY(KVEntry, _members); + FREE_C_HEAP_ARRAY(_members); } memset(_small, 0, sizeof(_small)); } diff --git a/src/hotspot/share/nmt/vmatree.hpp b/src/hotspot/share/nmt/vmatree.hpp index ae732a4b0d3..7054249319f 100644 --- a/src/hotspot/share/nmt/vmatree.hpp +++ b/src/hotspot/share/nmt/vmatree.hpp @@ -264,7 +264,7 @@ public: } ~SummaryDiff() { if (_members != _small) { - FREE_C_HEAP_ARRAY(KVEntry, _members); + FREE_C_HEAP_ARRAY(_members); } } diff --git a/src/hotspot/share/oops/accessDecorators.hpp b/src/hotspot/share/oops/accessDecorators.hpp index b972c54a064..bbf5cd8722e 100644 --- a/src/hotspot/share/oops/accessDecorators.hpp +++ b/src/hotspot/share/oops/accessDecorators.hpp @@ -108,7 +108,8 @@ const DecoratorSet INTERNAL_DECORATOR_MASK = INTERNAL_CONVERT_COMPRESS // - Guarantees from relaxed loads hold. // * MO_SEQ_CST: Sequentially consistent loads. // - These loads observe MO_SEQ_CST stores in the same order on other processors -// - Preceding loads and stores in program order are not reordered with subsequent loads and stores in program order. +// - Preceding MO_SEQ_CST loads and stores in program order are not reordered with +// subsequent MO_SEQ_CST loads and stores in program order. // - Guarantees from acquiring loads hold. // === Atomic Cmpxchg === // * MO_RELAXED: Atomic but relaxed cmpxchg. diff --git a/src/hotspot/share/oops/array.hpp b/src/hotspot/share/oops/array.hpp index 82067e007ea..0c720c85478 100644 --- a/src/hotspot/share/oops/array.hpp +++ b/src/hotspot/share/oops/array.hpp @@ -25,6 +25,7 @@ #ifndef SHARE_OOPS_ARRAY_HPP #define SHARE_OOPS_ARRAY_HPP +#include "memory/metaspaceClosureType.hpp" #include "runtime/atomicAccess.hpp" #include "utilities/align.hpp" #include "utilities/exceptions.hpp" @@ -159,8 +160,48 @@ protected: st->print("Array(" PTR_FORMAT ")", p2i(this)); } - // This function does nothing. The iteration of the elements are done inside metaspaceClosure.hpp - void metaspace_pointers_do(MetaspaceClosure* it) {} + MetaspaceClosureType type() const { return as_type(MetaspaceObj::array_type(sizeof(T))); } + + static bool is_read_only_by_default() { + return is_read_only_by_default_impl(); + } + +private: + // Elements are neither pointers nor metadata objects => no need to relocate, so put the array + // in read-only region by default. + template ::value && !HAS_METASPACE_POINTERS_DO(U))> + static bool is_read_only_by_default_impl() { + return true; + } + + // The opposite of the above => the array may contain relocatable pointers, so put it + // in read-write region by default. + template ::value || HAS_METASPACE_POINTERS_DO(U))> + static bool is_read_only_by_default_impl() { + return false; + } + +public: + void metaspace_pointers_do(MetaspaceClosure* it) { + metaspace_pointers_do_impl(it); + } + +private: + // E.g., Array + template ::value && !HAS_METASPACE_POINTERS_DO(U))> + void metaspace_pointers_do_impl(MetaspaceClosure* it) { + // No pointers to follow + } + + // E.g., Array + template ::value && HAS_METASPACE_POINTERS_DO(U))> + void metaspace_pointers_do_impl(MetaspaceClosure* it); + + // E.g., Array + template ::value && HAS_METASPACE_POINTERS_DO(typename std::remove_pointer::type))> + void metaspace_pointers_do_impl(MetaspaceClosure* it); + +public: #ifndef PRODUCT void print(outputStream* st) { diff --git a/src/hotspot/share/oops/array.inline.hpp b/src/hotspot/share/oops/array.inline.hpp index 30cf2e38f77..e6c8ef94a12 100644 --- a/src/hotspot/share/oops/array.inline.hpp +++ b/src/hotspot/share/oops/array.inline.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -29,6 +29,7 @@ #include "memory/allocation.hpp" #include "memory/metaspace.hpp" +#include "memory/metaspaceClosure.hpp" template inline void* Array::operator new(size_t size, ClassLoaderData* loader_data, int length, TRAPS) throw() { @@ -52,4 +53,26 @@ inline void* Array::operator new(size_t size, int length, MemTag flags) throw return p; } +// E.g., Array +template +template ::value && HAS_METASPACE_POINTERS_DO(U))> +void Array::metaspace_pointers_do_impl(MetaspaceClosure* it) { + log_trace(aot)("Iter(MSOArray): %p [%d]", this, length()); + for (int i = 0; i < length(); i++) { + T* elm = adr_at(i); + elm->metaspace_pointers_do(it); + } +} + +// E.g., Array +template +template ::value && HAS_METASPACE_POINTERS_DO(typename std::remove_pointer::type))> +void Array::metaspace_pointers_do_impl(MetaspaceClosure* it) { + log_trace(aot)("Iter(MSOPtrArray): %p [%d]", this, length()); + for (int i = 0; i < length(); i++) { + T* mpp = adr_at(i); + it->push(mpp); + } +} + #endif // SHARE_OOPS_ARRAY_INLINE_HPP diff --git a/src/hotspot/share/oops/instanceKlass.cpp b/src/hotspot/share/oops/instanceKlass.cpp index d675e61cc05..fd1cf1b1457 100644 --- a/src/hotspot/share/oops/instanceKlass.cpp +++ b/src/hotspot/share/oops/instanceKlass.cpp @@ -2542,7 +2542,7 @@ void InstanceKlass::update_methods_jmethod_cache() { new_cache[i] = cache[i]; } _methods_jmethod_ids = new_cache; - FREE_C_HEAP_ARRAY(jmethodID, cache); + FREE_C_HEAP_ARRAY(cache); } } } @@ -3016,7 +3016,7 @@ void InstanceKlass::release_C_heap_structures(bool release_sub_metadata) { } #endif - FREE_C_HEAP_ARRAY(char, _source_debug_extension); + FREE_C_HEAP_ARRAY(_source_debug_extension); if (release_sub_metadata) { constants()->release_C_heap_structures(); @@ -3702,13 +3702,27 @@ const char* InstanceKlass::init_state_name() const { return state_names[init_state()]; } +void InstanceKlass::print_class_flags(outputStream* st) const { + AccessFlags flags(compute_modifier_flags()); + if (flags.is_public ()) st->print("public "); + if (flags.is_private ()) st->print("private "); + if (flags.is_protected ()) st->print("protected "); + if (flags.is_static ()) st->print("static "); + if (flags.is_final ()) st->print("final "); + if (flags.is_interface ()) st->print("interface "); + if (flags.is_abstract ()) st->print("abstract "); + if (flags.is_annotation()) st->print("annotation "); + if (flags.is_enum ()) st->print("enum "); + if (flags.is_synthetic ()) st->print("synthetic "); +} + void InstanceKlass::print_on(outputStream* st) const { assert(is_klass(), "must be klass"); Klass::print_on(st); st->print(BULLET"instance size: %d", size_helper()); st->cr(); st->print(BULLET"klass size: %d", size()); st->cr(); - st->print(BULLET"access: "); access_flags().print_on(st); st->cr(); + st->print(BULLET"access: "); print_class_flags(st); st->cr(); st->print(BULLET"flags: "); _misc_flags.print_on(st); st->cr(); st->print(BULLET"state: "); st->print_cr("%s", init_state_name()); st->print(BULLET"name: "); name()->print_value_on(st); st->cr(); @@ -3848,7 +3862,7 @@ void InstanceKlass::print_on(outputStream* st) const { void InstanceKlass::print_value_on(outputStream* st) const { assert(is_klass(), "must be klass"); - if (Verbose || WizardMode) access_flags().print_on(st); + if (Verbose || WizardMode) print_class_flags(st); name()->print_value_on(st); } diff --git a/src/hotspot/share/oops/instanceKlass.hpp b/src/hotspot/share/oops/instanceKlass.hpp index dd563ad3492..983f0f91699 100644 --- a/src/hotspot/share/oops/instanceKlass.hpp +++ b/src/hotspot/share/oops/instanceKlass.hpp @@ -330,9 +330,6 @@ class InstanceKlass: public Klass { bool defined_by_other_loaders() const { return _misc_flags.defined_by_other_loaders(); } void set_class_loader_type() { _misc_flags.set_class_loader_type(_class_loader_data); } - // Check if the class can be shared in CDS - bool is_shareable() const; - bool shared_loading_failed() const { return _misc_flags.shared_loading_failed(); } void set_shared_loading_failed() { _misc_flags.set_shared_loading_failed(true); } @@ -1136,8 +1133,6 @@ private: void link_previous_versions(InstanceKlass* pv) { _previous_versions = pv; } void mark_newly_obsolete_methods(Array* old_methods, int emcp_method_count); #endif - // log class name to classlist - void log_to_classlist() const; public: #if INCLUDE_CDS @@ -1169,6 +1164,7 @@ public: // Printing void print_on(outputStream* st) const override; void print_value_on(outputStream* st) const override; + void print_class_flags(outputStream* st) const; void oop_print_value_on(oop obj, outputStream* st) override; diff --git a/src/hotspot/share/oops/klassVtable.cpp b/src/hotspot/share/oops/klassVtable.cpp index ead413dfa2c..5fefcdfbaaf 100644 --- a/src/hotspot/share/oops/klassVtable.cpp +++ b/src/hotspot/share/oops/klassVtable.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -1066,7 +1066,7 @@ void klassVtable::dump_vtable() { Method* m = unchecked_method_at(i); if (m != nullptr) { tty->print(" (%5d) ", i); - m->access_flags().print_on(tty); + m->print_access_flags(tty); if (m->is_default_method()) { tty->print("default "); } @@ -1421,7 +1421,7 @@ void klassItable::dump_itable() { Method* m = ime->method(); if (m != nullptr) { tty->print(" (%5d) ", i); - m->access_flags().print_on(tty); + m->print_access_flags(tty); if (m->is_default_method()) { tty->print("default "); } diff --git a/src/hotspot/share/oops/method.cpp b/src/hotspot/share/oops/method.cpp index 949441585d8..d0d31ae115a 100644 --- a/src/hotspot/share/oops/method.cpp +++ b/src/hotspot/share/oops/method.cpp @@ -184,24 +184,30 @@ address Method::get_c2i_no_clinit_check_entry() { return adapter()->get_c2i_no_clinit_check_entry(); } -char* Method::name_and_sig_as_C_string() const { - return name_and_sig_as_C_string(constants()->pool_holder(), name(), signature()); +char* Method::name_and_sig_as_C_string(bool use_double_colon) const { + return name_and_sig_as_C_string(constants()->pool_holder(), name(), signature(), use_double_colon); } char* Method::name_and_sig_as_C_string(char* buf, int size) const { return name_and_sig_as_C_string(constants()->pool_holder(), name(), signature(), buf, size); } -char* Method::name_and_sig_as_C_string(Klass* klass, Symbol* method_name, Symbol* signature) { +char* Method::name_and_sig_as_C_string(Klass* klass, Symbol* method_name, Symbol* signature, bool use_double_colon) { const char* klass_name = klass->external_name(); int klass_name_len = (int)strlen(klass_name); int method_name_len = method_name->utf8_length(); - int len = klass_name_len + 1 + method_name_len + signature->utf8_length(); + int separator_len = use_double_colon ? 2 : 1; + int len = klass_name_len + separator_len + method_name_len + signature->utf8_length(); char* dest = NEW_RESOURCE_ARRAY(char, len + 1); strcpy(dest, klass_name); - dest[klass_name_len] = '.'; - strcpy(&dest[klass_name_len + 1], method_name->as_C_string()); - strcpy(&dest[klass_name_len + 1 + method_name_len], signature->as_C_string()); + if (use_double_colon) { + dest[klass_name_len + 0] = ':'; + dest[klass_name_len + 1] = ':'; + } else { + dest[klass_name_len] = '.'; + } + strcpy(&dest[klass_name_len + separator_len], method_name->as_C_string()); + strcpy(&dest[klass_name_len + separator_len + method_name_len], signature->as_C_string()); dest[len] = 0; return dest; } @@ -2204,7 +2210,7 @@ void Method::print_on(outputStream* st) const { st->print (" - method holder: "); method_holder()->print_value_on(st); st->cr(); st->print (" - constants: " PTR_FORMAT " ", p2i(constants())); constants()->print_value_on(st); st->cr(); - st->print (" - access: 0x%x ", access_flags().as_method_flags()); access_flags().print_on(st); st->cr(); + st->print (" - access: 0x%x ", access_flags().as_method_flags()); print_access_flags(st); st->cr(); st->print (" - flags: 0x%x ", _flags.as_int()); _flags.print_on(st); st->cr(); st->print (" - name: "); name()->print_value_on(st); st->cr(); st->print (" - signature: "); signature()->print_value_on(st); st->cr(); @@ -2278,8 +2284,8 @@ void Method::print_on(outputStream* st) const { } } -void Method::print_linkage_flags(outputStream* st) { - access_flags().print_on(st); +void Method::print_linkage_flags(outputStream* st) const { + print_access_flags(st); if (is_default_method()) { st->print("default "); } @@ -2289,6 +2295,22 @@ void Method::print_linkage_flags(outputStream* st) { } #endif //PRODUCT +void Method::print_access_flags(outputStream* st) const { + AccessFlags flags = access_flags(); + if (flags.is_public ()) st->print("public "); + if (flags.is_private ()) st->print("private "); + if (flags.is_protected ()) st->print("protected "); + if (flags.is_static ()) st->print("static "); + if (flags.is_final ()) st->print("final "); + if (flags.is_synchronized()) st->print("synchronized "); + if (flags.is_bridge ()) st->print("bridge "); + if (flags.is_varargs ()) st->print("varargs "); + if (flags.is_native ()) st->print("native "); + if (flags.is_abstract ()) st->print("abstract "); + if (flags.is_strictfp ()) st->print("strict "); + if (flags.is_synthetic ()) st->print("synthetic "); +} + void Method::print_value_on(outputStream* st) const { assert(is_method(), "must be method"); st->print("%s", internal_name()); diff --git a/src/hotspot/share/oops/method.hpp b/src/hotspot/share/oops/method.hpp index e7479671dcf..5ef23595037 100644 --- a/src/hotspot/share/oops/method.hpp +++ b/src/hotspot/share/oops/method.hpp @@ -171,11 +171,11 @@ class Method : public Metadata { // C string, for the purpose of providing more useful // fatal error handling. The string is allocated in resource // area if a buffer is not provided by the caller. - char* name_and_sig_as_C_string() const; + char* name_and_sig_as_C_string(bool use_double_colon = false) const; char* name_and_sig_as_C_string(char* buf, int size) const; // Static routine in the situations we don't have a Method* - static char* name_and_sig_as_C_string(Klass* klass, Symbol* method_name, Symbol* signature); + static char* name_and_sig_as_C_string(Klass* klass, Symbol* method_name, Symbol* signature, bool use_double_colon = false); static char* name_and_sig_as_C_string(Klass* klass, Symbol* method_name, Symbol* signature, char* buf, int size); // Get return type + klass name + "." + method name + ( parameters types ) @@ -859,7 +859,8 @@ public: void print_on(outputStream* st) const; #endif void print_value_on(outputStream* st) const; - void print_linkage_flags(outputStream* st) PRODUCT_RETURN; + void print_access_flags(outputStream* st) const; + void print_linkage_flags(outputStream* st) const PRODUCT_RETURN; const char* internal_name() const { return "{method}"; } diff --git a/src/hotspot/share/oops/methodData.hpp b/src/hotspot/share/oops/methodData.hpp index 45529618afb..7e5466b91a3 100644 --- a/src/hotspot/share/oops/methodData.hpp +++ b/src/hotspot/share/oops/methodData.hpp @@ -34,6 +34,7 @@ #include "runtime/mutex.hpp" #include "utilities/align.hpp" #include "utilities/copy.hpp" +#include "utilities/integerCast.hpp" class BytecodeStream; @@ -206,7 +207,7 @@ public: } bool set_flag_at(u1 flag_number) { - const u1 bit = 1 << flag_number; + const u1 bit = integer_cast(1 << flag_number); u1 compare_value; do { compare_value = _header._struct._flags; @@ -219,7 +220,7 @@ public: } bool clear_flag_at(u1 flag_number) { - const u1 bit = 1 << flag_number; + const u1 bit = integer_cast(1 << flag_number); u1 compare_value; u1 exchange_value; do { diff --git a/src/hotspot/share/oops/trainingData.cpp b/src/hotspot/share/oops/trainingData.cpp index 7976da35374..f14ed36daa8 100644 --- a/src/hotspot/share/oops/trainingData.cpp +++ b/src/hotspot/share/oops/trainingData.cpp @@ -727,7 +727,7 @@ void TrainingData::metaspace_pointers_do(MetaspaceClosure* iter) { } bool TrainingData::Key::can_compute_cds_hash(const Key* const& k) { - return k->meta() == nullptr || MetaspaceObj::in_aot_cache(k->meta()); + return k->meta() == nullptr || k->meta()->in_aot_cache(); } uint TrainingData::Key::cds_hash(const Key* const& k) { diff --git a/src/hotspot/share/oops/trainingData.hpp b/src/hotspot/share/oops/trainingData.hpp index a6decdce7f0..50f97153d8c 100644 --- a/src/hotspot/share/oops/trainingData.hpp +++ b/src/hotspot/share/oops/trainingData.hpp @@ -31,6 +31,7 @@ #include "compiler/compilerDefinitions.hpp" #include "memory/allocation.hpp" #include "memory/metaspaceClosure.hpp" +#include "oops/array.inline.hpp" #include "oops/instanceKlass.hpp" #include "oops/method.hpp" #include "oops/objArrayKlass.hpp" diff --git a/src/hotspot/share/opto/block.cpp b/src/hotspot/share/opto/block.cpp index a93e2e43a29..1da63ce8180 100644 --- a/src/hotspot/share/opto/block.cpp +++ b/src/hotspot/share/opto/block.cpp @@ -1430,7 +1430,7 @@ void UnionFind::extend( uint from_idx, uint to_idx ) { if( from_idx >= _max ) { uint size = 16; while( size <= from_idx ) size <<=1; - _indices = REALLOC_RESOURCE_ARRAY( uint, _indices, _max, size ); + _indices = REALLOC_RESOURCE_ARRAY( _indices, _max, size ); _max = size; } while( _cnt <= from_idx ) _indices[_cnt++] = 0; diff --git a/src/hotspot/share/opto/chaitin.cpp b/src/hotspot/share/opto/chaitin.cpp index ef017ee15ec..606d45d4a12 100644 --- a/src/hotspot/share/opto/chaitin.cpp +++ b/src/hotspot/share/opto/chaitin.cpp @@ -265,7 +265,7 @@ PhaseChaitin::PhaseChaitin(uint unique, PhaseCFG &cfg, Matcher &matcher, bool sc assert((&buckets[0][0] + nr_blocks) == offset, "should be"); // Free the now unused memory - FREE_RESOURCE_ARRAY(Block*, buckets[1], (NUMBUCKS-1)*nr_blocks); + FREE_RESOURCE_ARRAY(buckets[1], (NUMBUCKS-1)*nr_blocks); // Finally, point the _blks to our memory _blks = buckets[0]; diff --git a/src/hotspot/share/opto/compile.cpp b/src/hotspot/share/opto/compile.cpp index e05df8ea716..6d185a9746e 100644 --- a/src/hotspot/share/opto/compile.cpp +++ b/src/hotspot/share/opto/compile.cpp @@ -1618,7 +1618,7 @@ void Compile::grow_alias_types() { const int new_ats = old_ats; // how many more? const int grow_ats = old_ats+new_ats; // how many now? _max_alias_types = grow_ats; - _alias_types = REALLOC_ARENA_ARRAY(comp_arena(), AliasType*, _alias_types, old_ats, grow_ats); + _alias_types = REALLOC_ARENA_ARRAY(comp_arena(), _alias_types, old_ats, grow_ats); AliasType* ats = NEW_ARENA_ARRAY(comp_arena(), AliasType, new_ats); Copy::zero_to_bytes(ats, sizeof(AliasType)*new_ats); for (int i = 0; i < new_ats; i++) _alias_types[old_ats+i] = &ats[i]; @@ -2584,14 +2584,13 @@ void Compile::Optimize() { assert(igvn._worklist.size() == 0, "not empty"); - assert(_late_inlines.length() == 0 || IncrementalInlineMH || IncrementalInlineVirtual, "not empty"); - if (_late_inlines.length() > 0) { // More opportunities to optimize virtual and MH calls. // Though it's maybe too late to perform inlining, strength-reducing them to direct calls is still an option. process_late_inline_calls_no_inline(igvn); if (failing()) return; } + assert(_late_inlines.length() == 0, "late inline queue must be drained"); } // (End scope of igvn; run destructor if necessary for asserts.) check_no_dead_use(); @@ -3235,6 +3234,12 @@ void Compile::final_graph_reshaping_impl(Node *n, Final_Reshape_Counts& frc, Uni assert(mb->trailing_membar()->leading_membar() == mb, "bad membar pair"); } } + if (n->is_CallLeafPure()) { + // A pure call whose result projection is unused should have been + // eliminated by CallLeafPureNode::Ideal during IGVN. + assert(n->as_CallLeafPure()->proj_out_or_null(TypeFunc::Parms) != nullptr, + "unused CallLeafPureNode should have been removed before final graph reshaping"); + } #endif // Count FPU ops and common calls, implements item (3) bool gc_handled = BarrierSet::barrier_set()->barrier_set_c2()->final_graph_reshaping(this, n, nop, dead_nodes); diff --git a/src/hotspot/share/opto/gcm.cpp b/src/hotspot/share/opto/gcm.cpp index e3d3108a22e..ce1ea8a59e2 100644 --- a/src/hotspot/share/opto/gcm.cpp +++ b/src/hotspot/share/opto/gcm.cpp @@ -1743,6 +1743,9 @@ void PhaseCFG::schedule_late(VectorSet &visited, Node_Stack &stack) { // are needed make sure that after placement in a block we don't // need any new precedence edges. verify_anti_dependences(late, self); + if (C->failing()) { + return; + } } #endif } // Loop until all nodes have been visited diff --git a/src/hotspot/share/opto/library_call.cpp b/src/hotspot/share/opto/library_call.cpp index ff7bc2c10d3..f6a9014c9e1 100644 --- a/src/hotspot/share/opto/library_call.cpp +++ b/src/hotspot/share/opto/library_call.cpp @@ -6932,7 +6932,8 @@ bool LibraryCallKit::inline_reference_get0() { DecoratorSet decorators = IN_HEAP | ON_WEAK_OOP_REF; Node* result = load_field_from_object(reference_obj, "referent", "Ljava/lang/Object;", - decorators, /*is_static*/ false, nullptr); + decorators, /*is_static*/ false, + env()->Reference_klass()); if (result == nullptr) return false; // Add memory barrier to prevent commoning reads from this field @@ -6955,7 +6956,8 @@ bool LibraryCallKit::inline_reference_refersTo0(bool is_phantom) { DecoratorSet decorators = IN_HEAP | AS_NO_KEEPALIVE; decorators |= (is_phantom ? ON_PHANTOM_OOP_REF : ON_WEAK_OOP_REF); Node* referent = load_field_from_object(reference_obj, "referent", "Ljava/lang/Object;", - decorators, /*is_static*/ false, nullptr); + decorators, /*is_static*/ false, + env()->Reference_klass()); if (referent == nullptr) return false; // Add memory barrier to prevent commoning reads from this field @@ -7042,8 +7044,6 @@ Node* LibraryCallKit::load_field_from_object(Node* fromObj, const char* fieldNam assert(tinst != nullptr, "obj is null"); assert(tinst->is_loaded(), "obj is not loaded"); fromKls = tinst->instance_klass(); - } else { - assert(is_static, "only for static field access"); } ciField* field = fromKls->get_field_by_name(ciSymbol::make(fieldName), ciSymbol::make(fieldTypeString), diff --git a/src/hotspot/share/opto/loopnode.cpp b/src/hotspot/share/opto/loopnode.cpp index 35a9108892c..13feeb77947 100644 --- a/src/hotspot/share/opto/loopnode.cpp +++ b/src/hotspot/share/opto/loopnode.cpp @@ -5938,8 +5938,8 @@ void PhaseIdealLoop::set_idom(Node* d, Node* n, uint dom_depth) { uint idx = d->_idx; if (idx >= _idom_size) { uint newsize = next_power_of_2(idx); - _idom = REALLOC_ARENA_ARRAY(&_arena, Node*, _idom,_idom_size,newsize); - _dom_depth = REALLOC_ARENA_ARRAY(&_arena, uint, _dom_depth,_idom_size,newsize); + _idom = REALLOC_ARENA_ARRAY(&_arena, _idom, _idom_size, newsize); + _dom_depth = REALLOC_ARENA_ARRAY(&_arena, _dom_depth, _idom_size, newsize); memset( _dom_depth + _idom_size, 0, (newsize - _idom_size) * sizeof(uint) ); _idom_size = newsize; } diff --git a/src/hotspot/share/opto/loopnode.hpp b/src/hotspot/share/opto/loopnode.hpp index 26b82259327..4eef2fed415 100644 --- a/src/hotspot/share/opto/loopnode.hpp +++ b/src/hotspot/share/opto/loopnode.hpp @@ -914,7 +914,7 @@ class PhaseIdealLoop : public PhaseTransform { void reallocate_preorders() { _nesting.check(); // Check if a potential re-allocation in the resource arena is safe if ( _max_preorder < C->unique() ) { - _preorders = REALLOC_RESOURCE_ARRAY(uint, _preorders, _max_preorder, C->unique()); + _preorders = REALLOC_RESOURCE_ARRAY(_preorders, _max_preorder, C->unique()); _max_preorder = C->unique(); } memset(_preorders, 0, sizeof(uint) * _max_preorder); @@ -926,7 +926,7 @@ class PhaseIdealLoop : public PhaseTransform { _nesting.check(); // Check if a potential re-allocation in the resource arena is safe if ( _max_preorder < C->unique() ) { uint newsize = _max_preorder<<1; // double size of array - _preorders = REALLOC_RESOURCE_ARRAY(uint, _preorders, _max_preorder, newsize); + _preorders = REALLOC_RESOURCE_ARRAY(_preorders, _max_preorder, newsize); memset(&_preorders[_max_preorder],0,sizeof(uint)*(newsize-_max_preorder)); _max_preorder = newsize; } diff --git a/src/hotspot/share/opto/memnode.cpp b/src/hotspot/share/opto/memnode.cpp index a49d4708d32..1521f89af4e 100644 --- a/src/hotspot/share/opto/memnode.cpp +++ b/src/hotspot/share/opto/memnode.cpp @@ -442,7 +442,7 @@ Node *MemNode::Ideal_common(PhaseGVN *phase, bool can_reshape) { // and 'DomResult::EncounteredDeadCode' if we can't decide due to // dead code, but at the end of IGVN, we know the definite result // once the dead code is cleaned up. -Node::DomResult MemNode::maybe_all_controls_dominate(Node* dom, Node* sub) { +Node::DomResult MemNode::maybe_all_controls_dominate(Node* dom, Node* sub, PhaseGVN* phase) { if (dom == nullptr || dom->is_top() || sub == nullptr || sub->is_top()) { return DomResult::EncounteredDeadCode; // Conservative answer for dead code } @@ -522,6 +522,9 @@ Node::DomResult MemNode::maybe_all_controls_dominate(Node* dom, Node* sub) { return dom_result; } } else { + if (n->Value(phase) == Type::TOP) { + return DomResult::EncounteredDeadCode; + } // First, own control edge. Node* m = n->find_exact_control(n->in(0)); if (m != nullptr) { @@ -552,7 +555,7 @@ Node::DomResult MemNode::maybe_all_controls_dominate(Node* dom, Node* sub) { // if any, which have been previously discovered by the caller. bool MemNode::detect_ptr_independence(Node* p1, AllocateNode* a1, Node* p2, AllocateNode* a2, - PhaseTransform* phase) { + PhaseGVN* phase) { // Trivial case: Non-overlapping values. Be careful, we can cast a raw pointer to an oop (e.g. in // the allocation pattern) so joining the types only works if both are oops. join may also give // an incorrect result when both pointers are nullable and the result is supposed to be @@ -575,9 +578,9 @@ bool MemNode::detect_ptr_independence(Node* p1, AllocateNode* a1, return (a1 != a2); } else if (a1 != nullptr) { // one allocation a1 // (Note: p2->is_Con implies p2->in(0)->is_Root, which dominates.) - return all_controls_dominate(p2, a1); + return all_controls_dominate(p2, a1, phase); } else { //(a2 != null) // one allocation a2 - return all_controls_dominate(p1, a2); + return all_controls_dominate(p1, a2, phase); } return false; } @@ -695,7 +698,7 @@ ArrayCopyNode* MemNode::find_array_copy_clone(Node* ld_alloc, Node* mem) const { // specific to loads and stores, so they are handled by the callers. // (Currently, only LoadNode::Ideal has steps (c), (d). More later.) // -Node* MemNode::find_previous_store(PhaseValues* phase) { +Node* MemNode::find_previous_store(PhaseGVN* phase) { AccessAnalyzer analyzer(phase, this); Node* mem = in(MemNode::Memory); // start searching here... @@ -771,7 +774,7 @@ uint8_t MemNode::barrier_data(const Node* n) { return 0; } -AccessAnalyzer::AccessAnalyzer(PhaseValues* phase, MemNode* n) +AccessAnalyzer::AccessAnalyzer(PhaseGVN* phase, MemNode* n) : _phase(phase), _n(n), _memory_size(n->memory_size()), _alias_idx(-1) { Node* adr = _n->in(MemNode::Address); _offset = 0; @@ -883,7 +886,7 @@ AccessAnalyzer::AccessIndependence AccessAnalyzer::detect_access_independence(No known_identical = true; } else if (_alloc != nullptr) { known_independent = true; - } else if (MemNode::all_controls_dominate(_n, st_alloc)) { + } else if (MemNode::all_controls_dominate(_n, st_alloc, _phase)) { known_independent = true; } @@ -1684,11 +1687,11 @@ bool LoadNode::can_split_through_phi_base(PhaseGVN* phase) { } if (!mem->is_Phi()) { - if (!MemNode::all_controls_dominate(mem, base->in(0))) { + if (!MemNode::all_controls_dominate(mem, base->in(0), phase)) { return false; } } else if (base->in(0) != mem->in(0)) { - if (!MemNode::all_controls_dominate(mem, base->in(0))) { + if (!MemNode::all_controls_dominate(mem, base->in(0), phase)) { return false; } } @@ -1783,20 +1786,20 @@ Node* LoadNode::split_through_phi(PhaseGVN* phase, bool ignore_missing_instance_ region = mem->in(0); // Skip if the region dominates some control edge of the address. // We will check `dom_result` later. - dom_result = MemNode::maybe_all_controls_dominate(address, region); + dom_result = MemNode::maybe_all_controls_dominate(address, region, phase); } else if (!mem->is_Phi()) { assert(base_is_phi, "sanity"); region = base->in(0); // Skip if the region dominates some control edge of the memory. // We will check `dom_result` later. - dom_result = MemNode::maybe_all_controls_dominate(mem, region); + dom_result = MemNode::maybe_all_controls_dominate(mem, region, phase); } else if (base->in(0) != mem->in(0)) { assert(base_is_phi && mem->is_Phi(), "sanity"); - dom_result = MemNode::maybe_all_controls_dominate(mem, base->in(0)); + dom_result = MemNode::maybe_all_controls_dominate(mem, base->in(0), phase); if (dom_result == DomResult::Dominate) { region = base->in(0); } else { - dom_result = MemNode::maybe_all_controls_dominate(address, mem->in(0)); + dom_result = MemNode::maybe_all_controls_dominate(address, mem->in(0), phase); if (dom_result == DomResult::Dominate) { region = mem->in(0); } @@ -1964,7 +1967,7 @@ Node *LoadNode::Ideal(PhaseGVN *phase, bool can_reshape) { if (in(MemNode::Control) != nullptr && can_remove_control() && phase->type(base)->higher_equal(TypePtr::NOTNULL) - && all_controls_dominate(base, phase->C->start())) { + && all_controls_dominate(base, phase->C->start(), phase)) { // A method-invariant, non-null address (constant or 'this' argument). set_req(MemNode::Control, nullptr); return this; @@ -4829,7 +4832,7 @@ bool InitializeNode::detect_init_independence(Node* value, PhaseGVN* phase) { // must have preceded the init, or else be equal to the init. // Even after loop optimizations (which might change control edges) // a store is never pinned *before* the availability of its inputs. - if (!MemNode::all_controls_dominate(n, this)) { + if (!MemNode::all_controls_dominate(n, this, phase)) { return false; // failed to prove a good control } } diff --git a/src/hotspot/share/opto/memnode.hpp b/src/hotspot/share/opto/memnode.hpp index 8efb5521e7c..f3f65608972 100644 --- a/src/hotspot/share/opto/memnode.hpp +++ b/src/hotspot/share/opto/memnode.hpp @@ -103,15 +103,15 @@ public: // Helpers for the optimizer. Documented in memnode.cpp. static bool detect_ptr_independence(Node* p1, AllocateNode* a1, Node* p2, AllocateNode* a2, - PhaseTransform* phase); + PhaseGVN* phase); static bool adr_phi_is_loop_invariant(Node* adr_phi, Node* cast); static Node *optimize_simple_memory_chain(Node *mchain, const TypeOopPtr *t_oop, Node *load, PhaseGVN *phase); static Node *optimize_memory_chain(Node *mchain, const TypePtr *t_adr, Node *load, PhaseGVN *phase); // The following two should probably be phase-specific functions: - static DomResult maybe_all_controls_dominate(Node* dom, Node* sub); - static bool all_controls_dominate(Node* dom, Node* sub) { - DomResult dom_result = maybe_all_controls_dominate(dom, sub); + static DomResult maybe_all_controls_dominate(Node* dom, Node* sub, PhaseGVN* phase); + static bool all_controls_dominate(Node* dom, Node* sub, PhaseGVN* phase) { + DomResult dom_result = maybe_all_controls_dominate(dom, sub, phase); return dom_result == DomResult::Dominate; } @@ -156,7 +156,7 @@ public: // Search through memory states which precede this node (load or store). // Look for an exact match for the address, with no intervening // aliased stores. - Node* find_previous_store(PhaseValues* phase); + Node* find_previous_store(PhaseGVN* phase); // Can this node (load or store) accurately see a stored value in // the given memory state? (The state may or may not be in(Memory).) @@ -186,7 +186,7 @@ public: // Analyze a MemNode to try to prove that it is independent from other memory accesses class AccessAnalyzer : StackObj { private: - PhaseValues* const _phase; + PhaseGVN* const _phase; MemNode* const _n; Node* _base; intptr_t _offset; @@ -197,7 +197,7 @@ private: int _alias_idx; public: - AccessAnalyzer(PhaseValues* phase, MemNode* n); + AccessAnalyzer(PhaseGVN* phase, MemNode* n); // The result of deciding whether a memory node 'other' writes into the memory which '_n' // observes. diff --git a/src/hotspot/share/opto/node.cpp b/src/hotspot/share/opto/node.cpp index 3eafd97d7c1..997ce92fe1c 100644 --- a/src/hotspot/share/opto/node.cpp +++ b/src/hotspot/share/opto/node.cpp @@ -3095,7 +3095,7 @@ void Node_Stack::grow() { size_t old_top = pointer_delta(_inode_top,_inodes,sizeof(INode)); // save _top size_t old_max = pointer_delta(_inode_max,_inodes,sizeof(INode)); size_t max = old_max << 1; // max * 2 - _inodes = REALLOC_ARENA_ARRAY(_a, INode, _inodes, old_max, max); + _inodes = REALLOC_ARENA_ARRAY(_a, _inodes, old_max, max); _inode_max = _inodes + max; _inode_top = _inodes + old_top; // restore _top } @@ -3213,4 +3213,3 @@ Node* TypeNode::Ideal(PhaseGVN* phase, bool can_reshape) { return Node::Ideal(phase, can_reshape); } - diff --git a/src/hotspot/share/opto/phasetype.hpp b/src/hotspot/share/opto/phasetype.hpp index 2b599ace03a..3d316112b2d 100644 --- a/src/hotspot/share/opto/phasetype.hpp +++ b/src/hotspot/share/opto/phasetype.hpp @@ -204,7 +204,7 @@ class PhaseNameValidator { ~PhaseNameValidator() { if (_bad != nullptr) { - FREE_C_HEAP_ARRAY(char, _bad); + FREE_C_HEAP_ARRAY(_bad); } } diff --git a/src/hotspot/share/opto/regmask.hpp b/src/hotspot/share/opto/regmask.hpp index 421031fdf61..99b10c1c557 100644 --- a/src/hotspot/share/opto/regmask.hpp +++ b/src/hotspot/share/opto/regmask.hpp @@ -285,8 +285,9 @@ class RegMask { _rm_word_ext = NEW_ARENA_ARRAY(_arena, uintptr_t, new_ext_size); } else { assert(_original_ext_address == &_rm_word_ext, "clone sanity check"); - _rm_word_ext = REALLOC_ARENA_ARRAY(_arena, uintptr_t, _rm_word_ext, + _rm_word_ext = REALLOC_ARENA_ARRAY(_arena, _rm_word_ext, old_ext_size, new_ext_size); + } if (initialize_by_infinite_stack) { int fill = 0; diff --git a/src/hotspot/share/opto/subnode.cpp b/src/hotspot/share/opto/subnode.cpp index 548df58eb35..014f41f82cc 100644 --- a/src/hotspot/share/opto/subnode.cpp +++ b/src/hotspot/share/opto/subnode.cpp @@ -981,15 +981,6 @@ const Type *CmpPNode::sub( const Type *t1, const Type *t2 ) const { const TypeKlassPtr* k0 = r0->isa_klassptr(); const TypeKlassPtr* k1 = r1->isa_klassptr(); if ((p0 && p1) || (k0 && k1)) { - if (p0 && p1) { - Node* in1 = in(1)->uncast(); - Node* in2 = in(2)->uncast(); - AllocateNode* alloc1 = AllocateNode::Ideal_allocation(in1); - AllocateNode* alloc2 = AllocateNode::Ideal_allocation(in2); - if (MemNode::detect_ptr_independence(in1, alloc1, in2, alloc2, nullptr)) { - return TypeInt::CC_GT; // different pointers - } - } bool xklass0 = p0 ? p0->klass_is_exact() : k0->klass_is_exact(); bool xklass1 = p1 ? p1->klass_is_exact() : k1->klass_is_exact(); bool unrelated_classes = false; @@ -1192,6 +1183,24 @@ Node *CmpPNode::Ideal( PhaseGVN *phase, bool can_reshape ) { return this; } +const Type* CmpPNode::Value(PhaseGVN* phase) const { + const Type* res = CmpNode::Value(phase); + if (res == TypeInt::CC) { + const TypeOopPtr* p0 = phase->type(in(1))->isa_oopptr(); + const TypeOopPtr* p1 = phase->type(in(2))->isa_oopptr(); + if (p0 != nullptr && p1 != nullptr) { + Node* in1 = in(1)->uncast(); + Node* in2 = in(2)->uncast(); + AllocateNode* alloc1 = AllocateNode::Ideal_allocation(in1); + AllocateNode* alloc2 = AllocateNode::Ideal_allocation(in2); + if (MemNode::detect_ptr_independence(in1, alloc1, in2, alloc2, phase)) { + return TypeInt::CC_GT; // different pointers + } + } + } + return res; +} + //============================================================================= //------------------------------sub-------------------------------------------- // Simplify an CmpN (compare 2 pointers) node, based on local information. diff --git a/src/hotspot/share/opto/subnode.hpp b/src/hotspot/share/opto/subnode.hpp index 54cb1d20cd0..387c1c46ba9 100644 --- a/src/hotspot/share/opto/subnode.hpp +++ b/src/hotspot/share/opto/subnode.hpp @@ -198,6 +198,7 @@ public: CmpPNode( Node *in1, Node *in2 ) : CmpNode(in1,in2) {} virtual int Opcode() const; virtual Node *Ideal(PhaseGVN *phase, bool can_reshape); + virtual const Type* Value(PhaseGVN* phase) const; virtual const Type *sub( const Type *, const Type * ) const; }; diff --git a/src/hotspot/share/opto/traceAutoVectorizationTag.hpp b/src/hotspot/share/opto/traceAutoVectorizationTag.hpp index 4f67aff9b07..47def1aed1e 100644 --- a/src/hotspot/share/opto/traceAutoVectorizationTag.hpp +++ b/src/hotspot/share/opto/traceAutoVectorizationTag.hpp @@ -142,7 +142,7 @@ class TraceAutoVectorizationTagValidator { ~TraceAutoVectorizationTagValidator() { if (_bad != nullptr) { - FREE_C_HEAP_ARRAY(char, _bad); + FREE_C_HEAP_ARRAY(_bad); } } diff --git a/src/hotspot/share/opto/traceMergeStoresTag.hpp b/src/hotspot/share/opto/traceMergeStoresTag.hpp index 214173c02f7..32ade413673 100644 --- a/src/hotspot/share/opto/traceMergeStoresTag.hpp +++ b/src/hotspot/share/opto/traceMergeStoresTag.hpp @@ -111,7 +111,7 @@ namespace TraceMergeStores { ~TagValidator() { if (_bad != nullptr) { - FREE_C_HEAP_ARRAY(char, _bad); + FREE_C_HEAP_ARRAY(_bad); } } diff --git a/src/hotspot/share/prims/jni.cpp b/src/hotspot/share/prims/jni.cpp index 73082c6047d..d6a435d34d1 100644 --- a/src/hotspot/share/prims/jni.cpp +++ b/src/hotspot/share/prims/jni.cpp @@ -2895,7 +2895,7 @@ JNI_ENTRY(void, jni_ReleaseStringCritical(JNIEnv *env, jstring str, const jchar if (is_latin1) { // For latin1 string, free jchar array allocated by earlier call to GetStringCritical. // This assumes that ReleaseStringCritical bookends GetStringCritical. - FREE_C_HEAP_ARRAY(jchar, chars); + FREE_C_HEAP_ARRAY(chars); } else { // StringDedup can have replaced the value array, so don't fetch the array from 's'. // Instead, we calculate the address based on the jchar array exposed with GetStringCritical. diff --git a/src/hotspot/share/prims/jvmtiAgent.cpp b/src/hotspot/share/prims/jvmtiAgent.cpp index 66cb68b44b0..5fe5378995b 100644 --- a/src/hotspot/share/prims/jvmtiAgent.cpp +++ b/src/hotspot/share/prims/jvmtiAgent.cpp @@ -247,7 +247,7 @@ static void vm_exit(const JvmtiAgent* agent, const char* sub_msg1, const char* s jio_snprintf(buf, len, "%s%s%s%s", not_found_error_msg, agent->name(), sub_msg1, &ebuf[0]); } vm_exit_during_initialization(buf, nullptr); - FREE_C_HEAP_ARRAY(char, buf); + FREE_C_HEAP_ARRAY(buf); } #ifdef ASSERT diff --git a/src/hotspot/share/prims/jvmtiClassFileReconstituter.cpp b/src/hotspot/share/prims/jvmtiClassFileReconstituter.cpp index 5077a1743b9..3037ffa5063 100644 --- a/src/hotspot/share/prims/jvmtiClassFileReconstituter.cpp +++ b/src/hotspot/share/prims/jvmtiClassFileReconstituter.cpp @@ -955,7 +955,7 @@ address JvmtiClassFileReconstituter::writeable_address(size_t size) { * initial_buffer_size; // VM goes belly-up if the memory isn't available, so cannot do OOM processing - _buffer = REALLOC_RESOURCE_ARRAY(u1, _buffer, _buffer_size, new_buffer_size); + _buffer = REALLOC_RESOURCE_ARRAY(_buffer, _buffer_size, new_buffer_size); _buffer_size = new_buffer_size; _buffer_ptr = _buffer + used_size; } diff --git a/src/hotspot/share/prims/jvmtiExport.cpp b/src/hotspot/share/prims/jvmtiExport.cpp index fca348fda26..98d8cfd990d 100644 --- a/src/hotspot/share/prims/jvmtiExport.cpp +++ b/src/hotspot/share/prims/jvmtiExport.cpp @@ -1160,7 +1160,7 @@ class JvmtiCompiledMethodLoadEventMark : public JvmtiMethodEventMark { JvmtiCodeBlobEvents::build_jvmti_addr_location_map(nm, &_map, &_map_length); } ~JvmtiCompiledMethodLoadEventMark() { - FREE_C_HEAP_ARRAY(jvmtiAddrLocationMap, _map); + FREE_C_HEAP_ARRAY(_map); } jint code_size() { return _code_size; } diff --git a/src/hotspot/share/prims/jvmtiRedefineClasses.cpp b/src/hotspot/share/prims/jvmtiRedefineClasses.cpp index 8beddc5d406..a040812bc73 100644 --- a/src/hotspot/share/prims/jvmtiRedefineClasses.cpp +++ b/src/hotspot/share/prims/jvmtiRedefineClasses.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -4544,7 +4544,7 @@ void VM_RedefineClasses::dump_methods() { LogStreamHandle(Trace, redefine, class, dump) log_stream; Method* m = _old_methods->at(j); log_stream.print("%4d (%5d) ", j, m->vtable_index()); - m->access_flags().print_on(&log_stream); + m->print_access_flags(&log_stream); log_stream.print(" -- "); m->print_name(&log_stream); log_stream.cr(); @@ -4554,7 +4554,7 @@ void VM_RedefineClasses::dump_methods() { LogStreamHandle(Trace, redefine, class, dump) log_stream; Method* m = _new_methods->at(j); log_stream.print("%4d (%5d) ", j, m->vtable_index()); - m->access_flags().print_on(&log_stream); + m->print_access_flags(&log_stream); log_stream.print(" -- "); m->print_name(&log_stream); log_stream.cr(); @@ -4564,14 +4564,14 @@ void VM_RedefineClasses::dump_methods() { LogStreamHandle(Trace, redefine, class, dump) log_stream; Method* m = _matching_old_methods[j]; log_stream.print("%4d (%5d) ", j, m->vtable_index()); - m->access_flags().print_on(&log_stream); + m->print_access_flags(&log_stream); log_stream.print(" -- "); m->print_name(); log_stream.cr(); m = _matching_new_methods[j]; log_stream.print(" (%5d) ", m->vtable_index()); - m->access_flags().print_on(&log_stream); + m->print_access_flags(&log_stream); log_stream.cr(); } log_trace(redefine, class, dump)("_deleted_methods --"); @@ -4579,7 +4579,7 @@ void VM_RedefineClasses::dump_methods() { LogStreamHandle(Trace, redefine, class, dump) log_stream; Method* m = _deleted_methods[j]; log_stream.print("%4d (%5d) ", j, m->vtable_index()); - m->access_flags().print_on(&log_stream); + m->print_access_flags(&log_stream); log_stream.print(" -- "); m->print_name(&log_stream); log_stream.cr(); @@ -4589,7 +4589,7 @@ void VM_RedefineClasses::dump_methods() { LogStreamHandle(Trace, redefine, class, dump) log_stream; Method* m = _added_methods[j]; log_stream.print("%4d (%5d) ", j, m->vtable_index()); - m->access_flags().print_on(&log_stream); + m->print_access_flags(&log_stream); log_stream.print(" -- "); m->print_name(&log_stream); log_stream.cr(); diff --git a/src/hotspot/share/prims/jvmtiTagMap.cpp b/src/hotspot/share/prims/jvmtiTagMap.cpp index 04cb70863cd..9724a61ba3d 100644 --- a/src/hotspot/share/prims/jvmtiTagMap.cpp +++ b/src/hotspot/share/prims/jvmtiTagMap.cpp @@ -136,20 +136,6 @@ bool JvmtiTagMap::is_empty() { return hashmap()->is_empty(); } -// This checks for posting before operations that use -// this tagmap table. -void JvmtiTagMap::check_hashmap(GrowableArray* objects) { - assert(is_locked(), "checking"); - - if (is_empty()) { return; } - - if (_needs_cleaning && - objects != nullptr && - env()->is_enabled(JVMTI_EVENT_OBJECT_FREE)) { - remove_dead_entries_locked(objects); - } -} - // This checks for posting and is called from the heap walks. void JvmtiTagMap::check_hashmaps_for_heapwalk(GrowableArray* objects) { assert(SafepointSynchronize::is_at_safepoint(), "called from safepoints"); @@ -162,7 +148,7 @@ void JvmtiTagMap::check_hashmaps_for_heapwalk(GrowableArray* objects) { if (tag_map != nullptr) { // The ZDriver may be walking the hashmaps concurrently so this lock is needed. MutexLocker ml(tag_map->lock(), Mutex::_no_safepoint_check_flag); - tag_map->check_hashmap(objects); + tag_map->remove_dead_entries_locked(objects); } } } @@ -329,11 +315,6 @@ class TwoOopCallbackWrapper : public CallbackWrapper { void JvmtiTagMap::set_tag(jobject object, jlong tag) { MutexLocker ml(lock(), Mutex::_no_safepoint_check_flag); - // SetTag should not post events because the JavaThread has to - // transition to native for the callback and this cannot stop for - // safepoints with the hashmap lock held. - check_hashmap(nullptr); /* don't collect dead objects */ - // resolve the object oop o = JNIHandles::resolve_non_null(object); @@ -354,11 +335,6 @@ void JvmtiTagMap::set_tag(jobject object, jlong tag) { jlong JvmtiTagMap::get_tag(jobject object) { MutexLocker ml(lock(), Mutex::_no_safepoint_check_flag); - // GetTag should not post events because the JavaThread has to - // transition to native for the callback and this cannot stop for - // safepoints with the hashmap lock held. - check_hashmap(nullptr); /* don't collect dead objects */ - // resolve the object oop o = JNIHandles::resolve_non_null(object); @@ -716,7 +692,7 @@ static jint invoke_string_value_callback(jvmtiStringPrimitiveValueCallback cb, user_data); if (is_latin1 && s_len > 0) { - FREE_C_HEAP_ARRAY(jchar, value); + FREE_C_HEAP_ARRAY(value); } return res; } diff --git a/src/hotspot/share/prims/jvmtiTagMap.hpp b/src/hotspot/share/prims/jvmtiTagMap.hpp index 08ab52ed686..1401157911f 100644 --- a/src/hotspot/share/prims/jvmtiTagMap.hpp +++ b/src/hotspot/share/prims/jvmtiTagMap.hpp @@ -51,8 +51,6 @@ class JvmtiTagMap : public CHeapObj { // accessors inline JvmtiEnv* env() const { return _env; } - void check_hashmap(GrowableArray* objects); - void entry_iterate(JvmtiTagMapKeyClosure* closure); public: diff --git a/src/hotspot/share/prims/methodHandles.cpp b/src/hotspot/share/prims/methodHandles.cpp index 03cb98d8e75..99a58b09e75 100644 --- a/src/hotspot/share/prims/methodHandles.cpp +++ b/src/hotspot/share/prims/methodHandles.cpp @@ -267,7 +267,7 @@ oop MethodHandles::init_method_MemberName(Handle mname, CallInfo& info) { ls.print_cr("memberName: invokeinterface method_holder::method: %s, itableindex: %d, access_flags:", Method::name_and_sig_as_C_string(m->method_holder(), m->name(), m->signature()), vmindex); - m->access_flags().print_on(&ls); + m->print_access_flags(&ls); if (!m->is_abstract()) { if (!m->is_private()) { ls.print("default"); @@ -314,7 +314,7 @@ oop MethodHandles::init_method_MemberName(Handle mname, CallInfo& info) { ls.print_cr("memberName: invokevirtual method_holder::method: %s, receiver: %s, vtableindex: %d, access_flags:", Method::name_and_sig_as_C_string(m->method_holder(), m->name(), m->signature()), m_klass->internal_name(), vmindex); - m->access_flags().print_on(&ls); + m->print_access_flags(&ls); if (m->is_default_method()) { ls.print("default"); } diff --git a/src/hotspot/share/prims/scopedMemoryAccess.cpp b/src/hotspot/share/prims/scopedMemoryAccess.cpp index 26ae5bc03f5..792bf74afcf 100644 --- a/src/hotspot/share/prims/scopedMemoryAccess.cpp +++ b/src/hotspot/share/prims/scopedMemoryAccess.cpp @@ -31,11 +31,13 @@ #include "oops/access.inline.hpp" #include "oops/oop.inline.hpp" #include "prims/stackwalk.hpp" +#include "runtime/atomic.hpp" #include "runtime/deoptimization.hpp" #include "runtime/interfaceSupport.inline.hpp" #include "runtime/jniHandles.inline.hpp" #include "runtime/sharedRuntime.hpp" #include "runtime/vframe.inline.hpp" +#include "utilities/spinYield.hpp" template static void for_scoped_methods(JavaThread* jt, bool agents_loaded, const Func& func) { @@ -128,19 +130,37 @@ static frame get_last_frame(JavaThread* jt) { return last_frame; } +// There are two properties that we rely on for these handshakes to work correctly: +// 1. Async handshakes are always 'self processed' by the target thread, which means they +// only run when the target thread is itself stopped at a safepoint poll, and not when +// the thread is actively executing code, such as a memory access. +// 2. After the handshake sets the thread's pending exception, it will be thrown immediately +// when continuing execution. The important part is that no more code is executed, and +// the thread unwinds out of the scoped access it was in. class ScopedAsyncExceptionHandshakeClosure : public AsyncExceptionHandshakeClosure { OopHandle _session; + Atomic* _async_exceptions; + bool _processed; + + // non-copyable to make sure counter remains consistent + NONCOPYABLE(ScopedAsyncExceptionHandshakeClosure); public: - ScopedAsyncExceptionHandshakeClosure(OopHandle& session, OopHandle& error) - : AsyncExceptionHandshakeClosure(error), - _session(session) {} + ScopedAsyncExceptionHandshakeClosure(OopHandle& session, OopHandle& error, Atomic* async_exceptions) + : AsyncExceptionHandshakeClosure(error, "ScopedAsyncExceptionHandshakeClosure"), + _session(session), _async_exceptions(async_exceptions), _processed(false) { + _async_exceptions->add_then_fetch(1); + } ~ScopedAsyncExceptionHandshakeClosure() { + guarantee(_processed, "must process to avoid hang"); _session.release(Universe::vm_global()); } virtual void do_thread(Thread* thread) { + _processed = true; + // We are stopped, safe to free memory. + _async_exceptions->sub_then_fetch(1); JavaThread* jt = JavaThread::cast(thread); bool ignored; if (is_accessing_session(jt, _session.resolve(), ignored)) { @@ -153,12 +173,14 @@ public: class CloseScopedMemoryHandshakeClosure : public HandshakeClosure { jobject _session; jobject _error; + Atomic* _async_exceptions; public: - CloseScopedMemoryHandshakeClosure(jobject session, jobject error) - : HandshakeClosure("CloseScopedMemory") + CloseScopedMemoryHandshakeClosure(jobject session, jobject error, Atomic* async_exceptions) + : HandshakeClosure("CloseScopedMemoryHandshakeClosure") , _session(session) - , _error(error) {} + , _error(error) + , _async_exceptions(async_exceptions) {} void do_thread(Thread* thread) { JavaThread* jt = JavaThread::cast(thread); @@ -180,9 +202,16 @@ public: // An asynchronous handshake is sent to the target thread, telling it // to throw an exception, which will unwind the target thread out from // the scoped access. + // + // Since CloseScopedMemoryHandshakeClosure::do_thread may run concurrently + // with the target thread, because the target thread might be in native + // code, we may not install the async exception directly. Instead, we + // install another handshake that will deliver the exception the next + // time the target thread stops at a safepoint poll and is able to handle + // async exceptions. OopHandle session(Universe::vm_global(), JNIHandles::resolve(_session)); OopHandle error(Universe::vm_global(), JNIHandles::resolve(_error)); - jt->install_async_exception(new ScopedAsyncExceptionHandshakeClosure(session, error)); + jt->install_async_exception(new ScopedAsyncExceptionHandshakeClosure(session, error, _async_exceptions)); } else if (!in_scoped) { frame last_frame = get_last_frame(jt); if (last_frame.is_compiled_frame() && last_frame.can_be_deoptimized()) { @@ -230,14 +259,28 @@ public: /* * This function performs a thread-local handshake against all threads running at the time - * the given session (deopt) was closed. If the handshake for a given thread is processed while - * one or more threads is found inside a scoped method (that is, a method inside the ScopedMemoryAccess - * class annotated with the '@Scoped' annotation), and whose local variables mention the session being - * closed (deopt), this method returns false, signalling that the session cannot be closed safely. + * the given session was closed. If a thread is found to be accessing the given session, + * it is made to throw the given exception (error). */ JVM_ENTRY(void, ScopedMemoryAccess_closeScope(JNIEnv *env, jobject receiver, jobject session, jobject error)) - CloseScopedMemoryHandshakeClosure cl(session, error); + Atomic async_exceptions; + CloseScopedMemoryHandshakeClosure cl(session, error, &async_exceptions); + // We rely on the fact that executing a handshake + // synchronizes this thread with all other threads, + // which means that each thread will see any updates + // to the liveness bit of the session we made before + // this point, and will see the session as closed, + // after the handshake finishes. Handshake::execute(&cl); + + // Wait until any async exceptions are delivered before continuing, + // because we will free the memory after this. This guarantees the target + // thread does not continue to access the memory. + ThreadBlockInVM tbivm(thread); + SpinYield spin_yield; + while (async_exceptions.load_acquire() > 0) { + spin_yield.wait(); + } JVM_END /// JVM_RegisterUnsafeMethods diff --git a/src/hotspot/share/prims/unsafe.cpp b/src/hotspot/share/prims/unsafe.cpp index c950690e8ab..b7f5b427eda 100644 --- a/src/hotspot/share/prims/unsafe.cpp +++ b/src/hotspot/share/prims/unsafe.cpp @@ -76,30 +76,6 @@ #define UNSAFE_LEAF(result_type, header) \ JVM_LEAF(static result_type, header) -// All memory access methods (e.g. getInt, copyMemory) must use this macro. -// We call these methods "scoped" methods, as access to these methods is -// typically governed by a "scope" (a MemorySessionImpl object), and no -// access is allowed when the scope is no longer alive. -// -// Closing a scope object (cf. scopedMemoryAccess.cpp) can install -// an async exception during a safepoint. When that happens, -// scoped methods are not allowed to touch the underlying memory (as that -// memory might have been released). Therefore, when entering a scoped method -// we check if an async exception has been installed, and return immediately -// if that is the case. -// -// As a rule, we disallow safepoints in the middle of a scoped method. -// If an async exception handshake were installed in such a safepoint, -// memory access might still occur before the handshake is honored by -// the accessing thread. -// -// Corollary: as threads in native state are considered to be at a safepoint, -// scoped methods must NOT be executed while in the native thread state. -// Because of this, there can be no UNSAFE_LEAF_SCOPED. -#define UNSAFE_ENTRY_SCOPED(result_type, header) \ - JVM_ENTRY(static result_type, header) \ - if (thread->has_async_exception_condition()) {return (result_type)0;} - #define UNSAFE_END JVM_END @@ -301,11 +277,11 @@ UNSAFE_ENTRY(jobject, Unsafe_GetUncompressedObject(JNIEnv *env, jobject unsafe, #define DEFINE_GETSETOOP(java_type, Type) \ \ -UNSAFE_ENTRY_SCOPED(java_type, Unsafe_Get##Type(JNIEnv *env, jobject unsafe, jobject obj, jlong offset)) { \ +UNSAFE_ENTRY(java_type, Unsafe_Get##Type(JNIEnv *env, jobject unsafe, jobject obj, jlong offset)) { \ return MemoryAccess(thread, obj, offset).get(); \ } UNSAFE_END \ \ -UNSAFE_ENTRY_SCOPED(void, Unsafe_Put##Type(JNIEnv *env, jobject unsafe, jobject obj, jlong offset, java_type x)) { \ +UNSAFE_ENTRY(void, Unsafe_Put##Type(JNIEnv *env, jobject unsafe, jobject obj, jlong offset, java_type x)) { \ MemoryAccess(thread, obj, offset).put(x); \ } UNSAFE_END \ \ @@ -324,11 +300,11 @@ DEFINE_GETSETOOP(jdouble, Double); #define DEFINE_GETSETOOP_VOLATILE(java_type, Type) \ \ -UNSAFE_ENTRY_SCOPED(java_type, Unsafe_Get##Type##Volatile(JNIEnv *env, jobject unsafe, jobject obj, jlong offset)) { \ +UNSAFE_ENTRY(java_type, Unsafe_Get##Type##Volatile(JNIEnv *env, jobject unsafe, jobject obj, jlong offset)) { \ return MemoryAccess(thread, obj, offset).get_volatile(); \ } UNSAFE_END \ \ -UNSAFE_ENTRY_SCOPED(void, Unsafe_Put##Type##Volatile(JNIEnv *env, jobject unsafe, jobject obj, jlong offset, java_type x)) { \ +UNSAFE_ENTRY(void, Unsafe_Put##Type##Volatile(JNIEnv *env, jobject unsafe, jobject obj, jlong offset, java_type x)) { \ MemoryAccess(thread, obj, offset).put_volatile(x); \ } UNSAFE_END \ \ @@ -384,7 +360,7 @@ UNSAFE_LEAF(void, Unsafe_FreeMemory0(JNIEnv *env, jobject unsafe, jlong addr)) { os::free(p); } UNSAFE_END -UNSAFE_ENTRY_SCOPED(void, Unsafe_SetMemory0(JNIEnv *env, jobject unsafe, jobject obj, jlong offset, jlong size, jbyte value)) { +UNSAFE_ENTRY(void, Unsafe_SetMemory0(JNIEnv *env, jobject unsafe, jobject obj, jlong offset, jlong size, jbyte value)) { size_t sz = (size_t)size; oop base = JNIHandles::resolve(obj); @@ -401,7 +377,7 @@ UNSAFE_ENTRY_SCOPED(void, Unsafe_SetMemory0(JNIEnv *env, jobject unsafe, jobject } } UNSAFE_END -UNSAFE_ENTRY_SCOPED(void, Unsafe_CopyMemory0(JNIEnv *env, jobject unsafe, jobject srcObj, jlong srcOffset, jobject dstObj, jlong dstOffset, jlong size)) { +UNSAFE_ENTRY(void, Unsafe_CopyMemory0(JNIEnv *env, jobject unsafe, jobject srcObj, jlong srcOffset, jobject dstObj, jlong dstOffset, jlong size)) { size_t sz = (size_t)size; oop srcp = JNIHandles::resolve(srcObj); @@ -420,19 +396,39 @@ UNSAFE_ENTRY_SCOPED(void, Unsafe_CopyMemory0(JNIEnv *env, jobject unsafe, jobjec } } UNSAFE_END -UNSAFE_ENTRY_SCOPED(void, Unsafe_CopySwapMemory0(JNIEnv *env, jobject unsafe, jobject srcObj, jlong srcOffset, jobject dstObj, jlong dstOffset, jlong size, jlong elemSize)) { +// This function is a leaf since if the source and destination are both in native memory +// the copy may potentially be very large, and we don't want to disable GC if we can avoid it. +// If either source or destination (or both) are on the heap, the function will enter VM using +// JVM_ENTRY_FROM_LEAF +UNSAFE_LEAF(void, Unsafe_CopySwapMemory0(JNIEnv *env, jobject unsafe, jobject srcObj, jlong srcOffset, jobject dstObj, jlong dstOffset, jlong size, jlong elemSize)) { size_t sz = (size_t)size; size_t esz = (size_t)elemSize; - oop srcp = JNIHandles::resolve(srcObj); - oop dstp = JNIHandles::resolve(dstObj); - address src = (address)index_oop_from_field_offset_long(srcp, srcOffset); - address dst = (address)index_oop_from_field_offset_long(dstp, dstOffset); + if (srcObj == nullptr && dstObj == nullptr) { + // Both src & dst are in native memory + address src = (address)srcOffset; + address dst = (address)dstOffset; - { - GuardUnsafeAccess guard(thread); - Copy::conjoint_swap(src, dst, sz, esz); + { + JavaThread* thread = JavaThread::thread_from_jni_environment(env); + GuardUnsafeAccess guard(thread); + Copy::conjoint_swap(src, dst, sz, esz); + } + } else { + // At least one of src/dst are on heap, transition to VM to access raw pointers + + JVM_ENTRY_FROM_LEAF(env, void, Unsafe_CopySwapMemory0) { + oop srcp = JNIHandles::resolve(srcObj); + oop dstp = JNIHandles::resolve(dstObj); + + address src = (address)index_oop_from_field_offset_long(srcp, srcOffset); + address dst = (address)index_oop_from_field_offset_long(dstp, dstOffset); + { + GuardUnsafeAccess guard(thread); + Copy::conjoint_swap(src, dst, sz, esz); + } + } JVM_END } } UNSAFE_END @@ -702,11 +698,11 @@ static jclass Unsafe_DefineClass_impl(JNIEnv *env, jstring name, jbyteArray data result = JVM_DefineClass(env, utfName, loader, body, length, pd); if (utfName && utfName != buf) { - FREE_C_HEAP_ARRAY(char, utfName); + FREE_C_HEAP_ARRAY(utfName); } free_body: - FREE_C_HEAP_ARRAY(jbyte, body); + FREE_C_HEAP_ARRAY(body); return result; } @@ -734,13 +730,13 @@ UNSAFE_ENTRY(jobject, Unsafe_CompareAndExchangeReference(JNIEnv *env, jobject un return JNIHandles::make_local(THREAD, res); } UNSAFE_END -UNSAFE_ENTRY_SCOPED(jint, Unsafe_CompareAndExchangeInt(JNIEnv *env, jobject unsafe, jobject obj, jlong offset, jint e, jint x)) { +UNSAFE_ENTRY(jint, Unsafe_CompareAndExchangeInt(JNIEnv *env, jobject unsafe, jobject obj, jlong offset, jint e, jint x)) { oop p = JNIHandles::resolve(obj); volatile jint* addr = (volatile jint*)index_oop_from_field_offset_long(p, offset); return AtomicAccess::cmpxchg(addr, e, x); } UNSAFE_END -UNSAFE_ENTRY_SCOPED(jlong, Unsafe_CompareAndExchangeLong(JNIEnv *env, jobject unsafe, jobject obj, jlong offset, jlong e, jlong x)) { +UNSAFE_ENTRY(jlong, Unsafe_CompareAndExchangeLong(JNIEnv *env, jobject unsafe, jobject obj, jlong offset, jlong e, jlong x)) { oop p = JNIHandles::resolve(obj); volatile jlong* addr = (volatile jlong*)index_oop_from_field_offset_long(p, offset); return AtomicAccess::cmpxchg(addr, e, x); @@ -755,13 +751,13 @@ UNSAFE_ENTRY(jboolean, Unsafe_CompareAndSetReference(JNIEnv *env, jobject unsafe return ret == e; } UNSAFE_END -UNSAFE_ENTRY_SCOPED(jboolean, Unsafe_CompareAndSetInt(JNIEnv *env, jobject unsafe, jobject obj, jlong offset, jint e, jint x)) { +UNSAFE_ENTRY(jboolean, Unsafe_CompareAndSetInt(JNIEnv *env, jobject unsafe, jobject obj, jlong offset, jint e, jint x)) { oop p = JNIHandles::resolve(obj); volatile jint* addr = (volatile jint*)index_oop_from_field_offset_long(p, offset); return AtomicAccess::cmpxchg(addr, e, x) == e; } UNSAFE_END -UNSAFE_ENTRY_SCOPED(jboolean, Unsafe_CompareAndSetLong(JNIEnv *env, jobject unsafe, jobject obj, jlong offset, jlong e, jlong x)) { +UNSAFE_ENTRY(jboolean, Unsafe_CompareAndSetLong(JNIEnv *env, jobject unsafe, jobject obj, jlong offset, jlong e, jlong x)) { oop p = JNIHandles::resolve(obj); volatile jlong* addr = (volatile jlong*)index_oop_from_field_offset_long(p, offset); return AtomicAccess::cmpxchg(addr, e, x) == e; diff --git a/src/hotspot/share/runtime/abstract_vm_version.hpp b/src/hotspot/share/runtime/abstract_vm_version.hpp index 794fa4dabcf..fb8a7a3dc52 100644 --- a/src/hotspot/share/runtime/abstract_vm_version.hpp +++ b/src/hotspot/share/runtime/abstract_vm_version.hpp @@ -45,19 +45,22 @@ class outputStream; class stringStream; enum class vmIntrinsicID; +#define SINGLE_INST_WARNING_MSG " instruction is not available on this CPU" +#define MULTI_INST_WARNING_MSG " instructions are not available on this CPU" + // Helper macro to test and set VM flag and corresponding cpu feature -#define CHECK_CPU_FEATURE(feature_test_fn, feature) \ - if (feature_test_fn()) { \ - if (FLAG_IS_DEFAULT(Use##feature)) { \ - FLAG_SET_DEFAULT(Use##feature, true); \ - } else if (!Use##feature) { \ - clear_feature(CPU_##feature); \ +#define CHECK_CPU_FEATURE(vmflag, feature_id, predicate, warning_msg) \ + if (predicate) { \ + if (FLAG_IS_DEFAULT(vmflag)) { \ + FLAG_SET_DEFAULT(vmflag, true); \ + } else if (!vmflag) { \ + clear_feature(CPU_##feature_id); \ } \ - } else if (Use##feature) { \ - if (!FLAG_IS_DEFAULT(Use##feature)) { \ - warning(#feature " instructions are not available on this CPU"); \ + } else if (vmflag) { \ + if (!FLAG_IS_DEFAULT(vmflag)) { \ + warning(#feature_id warning_msg); \ } \ - FLAG_SET_DEFAULT(Use##feature, false); \ + FLAG_SET_DEFAULT(vmflag, false); \ } // Abstract_VM_Version provides information about the VM. @@ -255,8 +258,8 @@ class Abstract_VM_Version: AllStatic { // Size of the buffer must be same as returned by cpu_features_size() static void store_cpu_features(void* buf) { return; } - // features_to_test is an opaque object that stores arch specific representation of cpu features - static bool supports_features(void* features_to_test) { return false; }; + // features_buffer is an opaque object that stores arch specific representation of cpu features + static bool verify_aot_code_cache_features(void* features_buffer) { return false; }; }; #endif // SHARE_RUNTIME_ABSTRACT_VM_VERSION_HPP diff --git a/src/hotspot/share/runtime/arguments.cpp b/src/hotspot/share/runtime/arguments.cpp index 2d40ee1822a..b8b32d89c65 100644 --- a/src/hotspot/share/runtime/arguments.cpp +++ b/src/hotspot/share/runtime/arguments.cpp @@ -533,7 +533,6 @@ static SpecialFlag const special_jvm_flags[] = { { "DynamicDumpSharedSpaces", JDK_Version::jdk(18), JDK_Version::jdk(19), JDK_Version::undefined() }, { "RequireSharedSpaces", JDK_Version::jdk(18), JDK_Version::jdk(19), JDK_Version::undefined() }, { "UseSharedSpaces", JDK_Version::jdk(18), JDK_Version::jdk(19), JDK_Version::undefined() }, - { "AggressiveHeap", JDK_Version::jdk(26), JDK_Version::jdk(27), JDK_Version::jdk(28) }, // --- Deprecated alias flags (see also aliased_jvm_flags) - sorted by obsolete_in then expired_in: { "CreateMinidumpOnCrash", JDK_Version::jdk(9), JDK_Version::undefined(), JDK_Version::undefined() }, @@ -556,6 +555,7 @@ static SpecialFlag const special_jvm_flags[] = { { "AlwaysActAsServerClassMachine", JDK_Version::jdk(26), JDK_Version::jdk(27), JDK_Version::jdk(28) }, { "UseXMMForArrayCopy", JDK_Version::undefined(), JDK_Version::jdk(27), JDK_Version::jdk(28) }, { "UseNewLongLShift", JDK_Version::undefined(), JDK_Version::jdk(27), JDK_Version::jdk(28) }, + { "AggressiveHeap", JDK_Version::jdk(26), JDK_Version::jdk(27), JDK_Version::jdk(28) }, #ifdef ASSERT { "DummyObsoleteTestFlag", JDK_Version::undefined(), JDK_Version::jdk(18), JDK_Version::undefined() }, @@ -851,7 +851,7 @@ static bool set_string_flag(JVMFlag* flag, const char* value, JVMFlagOrigin orig } if (JVMFlagAccess::set_ccstr(flag, &value, origin) != JVMFlag::SUCCESS) return false; // Contract: JVMFlag always returns a pointer that needs freeing. - FREE_C_HEAP_ARRAY(char, value); + FREE_C_HEAP_ARRAY(value); return true; } @@ -876,9 +876,9 @@ static bool append_to_string_flag(JVMFlag* flag, const char* new_value, JVMFlagO } (void) JVMFlagAccess::set_ccstr(flag, &value, origin); // JVMFlag always returns a pointer that needs freeing. - FREE_C_HEAP_ARRAY(char, value); + FREE_C_HEAP_ARRAY(value); // JVMFlag made its own copy, so I must delete my own temp. buffer. - FREE_C_HEAP_ARRAY(char, free_this_too); + FREE_C_HEAP_ARRAY(free_this_too); return true; } @@ -1013,7 +1013,7 @@ void Arguments::add_string(char*** bldarray, int* count, const char* arg) { if (*bldarray == nullptr) { *bldarray = NEW_C_HEAP_ARRAY(char*, new_count, mtArguments); } else { - *bldarray = REALLOC_C_HEAP_ARRAY(char*, *bldarray, new_count, mtArguments); + *bldarray = REALLOC_C_HEAP_ARRAY(*bldarray, new_count, mtArguments); } (*bldarray)[*count] = os::strdup_check_oom(arg); *count = new_count; @@ -1490,13 +1490,7 @@ jint Arguments::set_ergonomics_flags() { } size_t Arguments::limit_heap_by_allocatable_memory(size_t limit) { - // The AggressiveHeap check is a temporary workaround to avoid calling - // GCarguments::heap_virtual_to_physical_ratio() before a GC has been - // selected. This works because AggressiveHeap implies UseParallelGC - // where we know the ratio will be 1. Once the AggressiveHeap option is - // removed, this can be cleaned up. - size_t heap_virtual_to_physical_ratio = (AggressiveHeap ? 1 : GCConfig::arguments()->heap_virtual_to_physical_ratio()); - size_t fraction = MaxVirtMemFraction * heap_virtual_to_physical_ratio; + size_t fraction = MaxVirtMemFraction * GCConfig::arguments()->heap_virtual_to_physical_ratio(); size_t max_allocatable = os::commit_memory_limit(); return MIN2(limit, max_allocatable / fraction); @@ -1627,107 +1621,6 @@ void Arguments::set_heap_size() { } } -// This option inspects the machine and attempts to set various -// parameters to be optimal for long-running, memory allocation -// intensive jobs. It is intended for machines with large -// amounts of cpu and memory. -jint Arguments::set_aggressive_heap_flags() { - // initHeapSize is needed since _initial_heap_size is 4 bytes on a 32 bit - // VM, but we may not be able to represent the total physical memory - // available (like having 8gb of memory on a box but using a 32bit VM). - // Thus, we need to make sure we're using a julong for intermediate - // calculations. - julong initHeapSize; - physical_memory_size_type phys_mem = os::physical_memory(); - julong total_memory = static_cast(phys_mem); - - if (total_memory < (julong) 256 * M) { - jio_fprintf(defaultStream::error_stream(), - "You need at least 256mb of memory to use -XX:+AggressiveHeap\n"); - vm_exit(1); - } - - // The heap size is half of available memory, or (at most) - // all of possible memory less 160mb (leaving room for the OS - // when using ISM). This is the maximum; because adaptive sizing - // is turned on below, the actual space used may be smaller. - - initHeapSize = MIN2(total_memory / (julong) 2, - total_memory - (julong) 160 * M); - - initHeapSize = limit_heap_by_allocatable_memory(initHeapSize); - - if (FLAG_IS_DEFAULT(MaxHeapSize)) { - if (FLAG_SET_CMDLINE(MaxHeapSize, initHeapSize) != JVMFlag::SUCCESS) { - return JNI_EINVAL; - } - if (FLAG_SET_CMDLINE(InitialHeapSize, initHeapSize) != JVMFlag::SUCCESS) { - return JNI_EINVAL; - } - if (FLAG_SET_CMDLINE(MinHeapSize, initHeapSize) != JVMFlag::SUCCESS) { - return JNI_EINVAL; - } - } - if (FLAG_IS_DEFAULT(NewSize)) { - // Make the young generation 3/8ths of the total heap. - if (FLAG_SET_CMDLINE(NewSize, - ((julong) MaxHeapSize / (julong) 8) * (julong) 3) != JVMFlag::SUCCESS) { - return JNI_EINVAL; - } - if (FLAG_SET_CMDLINE(MaxNewSize, NewSize) != JVMFlag::SUCCESS) { - return JNI_EINVAL; - } - } - -#if !defined(_ALLBSD_SOURCE) && !defined(AIX) // UseLargePages is not yet supported on BSD and AIX. - FLAG_SET_DEFAULT(UseLargePages, true); -#endif - - // Increase some data structure sizes for efficiency - if (FLAG_SET_CMDLINE(ResizeTLAB, false) != JVMFlag::SUCCESS) { - return JNI_EINVAL; - } - if (FLAG_SET_CMDLINE(TLABSize, 256 * K) != JVMFlag::SUCCESS) { - return JNI_EINVAL; - } - - // See the OldPLABSize comment below, but replace 'after promotion' - // with 'after copying'. YoungPLABSize is the size of the survivor - // space per-gc-thread buffers. The default is 4kw. - if (FLAG_SET_CMDLINE(YoungPLABSize, 256 * K) != JVMFlag::SUCCESS) { // Note: this is in words - return JNI_EINVAL; - } - - // OldPLABSize is the size of the buffers in the old gen that - // UseParallelGC uses to promote live data that doesn't fit in the - // survivor spaces. At any given time, there's one for each gc thread. - // The default size is 1kw. These buffers are rarely used, since the - // survivor spaces are usually big enough. For specjbb, however, there - // are occasions when there's lots of live data in the young gen - // and we end up promoting some of it. We don't have a definite - // explanation for why bumping OldPLABSize helps, but the theory - // is that a bigger PLAB results in retaining something like the - // original allocation order after promotion, which improves mutator - // locality. A minor effect may be that larger PLABs reduce the - // number of PLAB allocation events during gc. The value of 8kw - // was arrived at by experimenting with specjbb. - if (FLAG_SET_CMDLINE(OldPLABSize, 8 * K) != JVMFlag::SUCCESS) { // Note: this is in words - return JNI_EINVAL; - } - - // Enable parallel GC and adaptive generation sizing - if (FLAG_SET_CMDLINE(UseParallelGC, true) != JVMFlag::SUCCESS) { - return JNI_EINVAL; - } - - // Encourage steady state memory management - if (FLAG_SET_CMDLINE(ThresholdTolerance, 100) != JVMFlag::SUCCESS) { - return JNI_EINVAL; - } - - return JNI_OK; -} - // This must be called after ergonomics. void Arguments::set_bytecode_flags() { if (!RewriteBytecodes) { @@ -1810,14 +1703,6 @@ bool Arguments::check_vm_args_consistency() { // Note: Needs platform-dependent factoring. bool status = true; - if (TLABRefillWasteFraction == 0) { - jio_fprintf(defaultStream::error_stream(), - "TLABRefillWasteFraction should be a denominator, " - "not %zu\n", - TLABRefillWasteFraction); - status = false; - } - status = CompilerConfig::check_args_consistency(status); #if INCLUDE_JVMCI if (status && EnableJVMCI) { @@ -2050,7 +1935,7 @@ int Arguments::process_patch_mod_option(const char* patch_mod_tail) { *(module_name + module_len) = '\0'; // The path piece begins one past the module_equal sign add_patch_mod_prefix(module_name, module_equal + 1); - FREE_C_HEAP_ARRAY(char, module_name); + FREE_C_HEAP_ARRAY(module_name); if (!create_numbered_module_property("jdk.module.patch", patch_mod_tail, patch_mod_count++)) { return JNI_ENOMEM; } @@ -2201,8 +2086,8 @@ jint Arguments::parse_each_vm_init_arg(const JavaVMInitArgs* args, JVMFlagOrigin } #endif // !INCLUDE_JVMTI JvmtiAgentList::add_xrun(name, options, false); - FREE_C_HEAP_ARRAY(char, name); - FREE_C_HEAP_ARRAY(char, options); + FREE_C_HEAP_ARRAY(name); + FREE_C_HEAP_ARRAY(options); } } else if (match_option(option, "--add-reads=", &tail)) { if (!create_numbered_module_property("jdk.module.addreads", tail, addreads_count++)) { @@ -2331,7 +2216,7 @@ jint Arguments::parse_each_vm_init_arg(const JavaVMInitArgs* args, JVMFlagOrigin char *options = NEW_C_HEAP_ARRAY(char, length, mtArguments); jio_snprintf(options, length, "%s", tail); JvmtiAgentList::add("instrument", options, false); - FREE_C_HEAP_ARRAY(char, options); + FREE_C_HEAP_ARRAY(options); // java agents need module java.instrument if (!create_numbered_module_property("jdk.module.addmods", "java.instrument", _addmods_count++)) { @@ -2938,16 +2823,6 @@ jint Arguments::finalize_vm_init_args() { return JNI_ERR; } - // This must be done after all arguments have been processed - // and the container support has been initialized since AggressiveHeap - // relies on the amount of total memory available. - if (AggressiveHeap) { - jint result = set_aggressive_heap_flags(); - if (result != JNI_OK) { - return result; - } - } - // CompileThresholdScaling == 0.0 is same as -Xint: Disable compilation (enable interpreter-only mode), // but like -Xint, leave compilation thresholds unaffected. // With tiered compilation disabled, setting CompileThreshold to 0 disables compilation as well. @@ -3066,7 +2941,7 @@ class ScopedVMInitArgs : public StackObj { for (int i = 0; i < _args.nOptions; i++) { os::free(_args.options[i].optionString); } - FREE_C_HEAP_ARRAY(JavaVMOption, _args.options); + FREE_C_HEAP_ARRAY(_args.options); } // Insert options into this option list, to replace option at @@ -3215,7 +3090,7 @@ jint Arguments::parse_vm_options_file(const char* file_name, ScopedVMInitArgs* v ssize_t bytes_read = ::read(fd, (void *)buf, (unsigned)bytes_alloc); ::close(fd); if (bytes_read < 0) { - FREE_C_HEAP_ARRAY(char, buf); + FREE_C_HEAP_ARRAY(buf); jio_fprintf(defaultStream::error_stream(), "Could not read options file '%s'\n", file_name); return JNI_ERR; @@ -3223,13 +3098,13 @@ jint Arguments::parse_vm_options_file(const char* file_name, ScopedVMInitArgs* v if (bytes_read == 0) { // tell caller there is no option data and that is ok - FREE_C_HEAP_ARRAY(char, buf); + FREE_C_HEAP_ARRAY(buf); return JNI_OK; } retcode = parse_options_buffer(file_name, buf, bytes_read, vm_args); - FREE_C_HEAP_ARRAY(char, buf); + FREE_C_HEAP_ARRAY(buf); return retcode; } @@ -3562,7 +3437,7 @@ jint Arguments::parse(const JavaVMInitArgs* initial_cmd_args) { char *vmoptions = ClassLoader::lookup_vm_options(); if (vmoptions != nullptr) { code = parse_options_buffer("vm options resource", vmoptions, strlen(vmoptions), &initial_vm_options_args); - FREE_C_HEAP_ARRAY(char, vmoptions); + FREE_C_HEAP_ARRAY(vmoptions); if (code != JNI_OK) { return code; } diff --git a/src/hotspot/share/runtime/arguments.hpp b/src/hotspot/share/runtime/arguments.hpp index f2bcc21e123..2c31383f7a4 100644 --- a/src/hotspot/share/runtime/arguments.hpp +++ b/src/hotspot/share/runtime/arguments.hpp @@ -303,8 +303,6 @@ class Arguments : AllStatic { // Aggressive optimization flags. static jint set_aggressive_opts_flags(); - static jint set_aggressive_heap_flags(); - // Argument parsing static bool parse_argument(const char* arg, JVMFlagOrigin origin); static bool process_argument(const char* arg, jboolean ignore_unrecognized, JVMFlagOrigin origin); diff --git a/src/hotspot/share/runtime/continuationFreezeThaw.cpp b/src/hotspot/share/runtime/continuationFreezeThaw.cpp index 9df89f1f12a..1350297ec3d 100644 --- a/src/hotspot/share/runtime/continuationFreezeThaw.cpp +++ b/src/hotspot/share/runtime/continuationFreezeThaw.cpp @@ -193,6 +193,7 @@ static void verify_continuation(oop continuation) { Continuation::debug_verify_c static void do_deopt_after_thaw(JavaThread* thread); static bool do_verify_after_thaw(JavaThread* thread, stackChunkOop chunk, outputStream* st); +static bool verify_deopt_state(const frame& f); static void log_frames(JavaThread* thread); static void log_frames_after_thaw(JavaThread* thread, ContinuationWrapper& cont, intptr_t* sp); static void print_frame_layout(const frame& f, bool callee_complete, outputStream* st = tty); @@ -2054,10 +2055,12 @@ protected: intptr_t* _fastpath; bool _barriers; bool _preempted_case; + bool _should_patch_caller_pc; bool _process_args_at_top; intptr_t* _top_unextended_sp_before_thaw; int _align_size; - DEBUG_ONLY(intptr_t* _top_stack_address); + DEBUG_ONLY(intptr_t* _top_stack_address;) + DEBUG_ONLY(address _caller_raw_pc;) // Only used for preemption on ObjectLocker ObjectMonitor* _init_lock; @@ -2479,6 +2482,7 @@ NOINLINE intptr_t* Thaw::thaw_slow(stackChunkOop chunk, Continuation::t } frame caller; // the thawed caller on the stack + _should_patch_caller_pc = false; recurse_thaw(heap_frame, caller, num_frames, _preempted_case); finish_thaw(caller); // caller is now the topmost thawed frame _cont.write(); @@ -2561,6 +2565,8 @@ void ThawBase::finalize_thaw(frame& entry, int argsize) { assert(entry.sp() == _cont.entrySP(), ""); assert(Continuation::is_continuation_enterSpecial(entry), ""); assert(_cont.is_entry_frame(entry), ""); + assert(entry.pc() == entry.raw_pc(), ""); + DEBUG_ONLY(_caller_raw_pc = entry.pc();) } inline void ThawBase::before_thaw_java_frame(const frame& hf, const frame& caller, bool bottom, int num_frame) { @@ -2590,10 +2596,12 @@ inline void ThawBase::patch(frame& f, const frame& caller, bool bottom) { if (bottom) { ContinuationHelper::Frame::patch_pc(caller, _cont.is_empty() ? caller.pc() : StubRoutines::cont_returnBarrier()); - } else { - // caller might have been deoptimized during thaw but we've overwritten the return address when copying f from the heap. - // If the caller is not deoptimized, pc is unchanged. + } else if (_should_patch_caller_pc) { + // Caller was deoptimized during thaw but we've overwritten the return address when copying f from the heap. + // Also, on some platforms, if the caller is interpreted but the callee not we also need to patch. + assert(caller.is_deoptimized_frame() PPC64_ONLY(|| caller.is_interpreted_frame()), ""); ContinuationHelper::Frame::patch_pc(caller, caller.raw_pc()); + _should_patch_caller_pc = false; } patch_pd(f, caller); @@ -2604,6 +2612,7 @@ inline void ThawBase::patch(frame& f, const frame& caller, bool bottom) { assert(!bottom || !_cont.is_empty() || Continuation::is_continuation_entry_frame(f, nullptr), ""); assert(!bottom || (_cont.is_empty() != Continuation::is_cont_barrier_frame(f)), ""); + assert(!caller.is_compiled_frame() || verify_deopt_state(caller), ""); } void ThawBase::clear_bitmap_bits(address start, address end) { @@ -2805,6 +2814,10 @@ NOINLINE void ThawBase::recurse_thaw_interpreted_frame(const frame& hf, frame& c } DEBUG_ONLY(after_thaw_java_frame(f, is_bottom_frame);) + DEBUG_ONLY(address return_pc = ContinuationHelper::InterpretedFrame::return_pc(f);) + assert(return_pc == _caller_raw_pc || (is_bottom_frame && return_pc == StubRoutines::cont_returnBarrier()), "wrong return pc"); + assert(f.pc() == f.raw_pc(), ""); + DEBUG_ONLY(_caller_raw_pc = f.pc();) caller = f; } @@ -2855,6 +2868,7 @@ void ThawBase::recurse_thaw_compiled_frame(const frame& hf, frame& caller, int n assert(!f.is_deoptimized_frame(), ""); if (hf.is_deoptimized_frame()) { maybe_set_fastpath(f.sp()); + f.set_deoptimized(); } else if (_thread->is_interp_only_mode() || (stub_caller && 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 @@ -2868,6 +2882,8 @@ void ThawBase::recurse_thaw_compiled_frame(const frame& hf, frame& caller, int n assert(f.is_deoptimized_frame(), ""); assert(ContinuationHelper::Frame::is_deopt_return(f.raw_pc(), f), ""); maybe_set_fastpath(f.sp()); + assert(!_should_patch_caller_pc, ""); + _should_patch_caller_pc = true; } if (!is_bottom_frame) { @@ -2881,6 +2897,9 @@ void ThawBase::recurse_thaw_compiled_frame(const frame& hf, frame& caller, int n } DEBUG_ONLY(after_thaw_java_frame(f, is_bottom_frame);) + DEBUG_ONLY(address return_pc = ContinuationHelper::CompiledFrame::return_pc(f);) + assert(return_pc == _caller_raw_pc || (is_bottom_frame && return_pc == StubRoutines::cont_returnBarrier()), "wrong return pc"); + DEBUG_ONLY(_caller_raw_pc = f.raw_pc();) caller = f; } @@ -2930,6 +2949,7 @@ void ThawBase::recurse_thaw_stub_frame(const frame& hf, frame& caller, int num_f _cont.tail()->fix_thawed_frame(caller, &map); DEBUG_ONLY(after_thaw_java_frame(f, false /*is_bottom_frame*/);) + assert(ContinuationHelper::StubFrame::return_pc(f) == _caller_raw_pc, "wrong return pc"); caller = f; } @@ -2979,6 +2999,7 @@ void ThawBase::recurse_thaw_native_frame(const frame& hf, frame& caller, int num _cont.tail()->fix_thawed_frame(caller, SmallRegisterMap::instance_no_args()); DEBUG_ONLY(after_thaw_java_frame(f, false /* bottom */);) + assert(ContinuationHelper::NativeFrame::return_pc(f) == _caller_raw_pc, "wrong return pc"); caller = f; } @@ -3023,8 +3044,7 @@ void ThawBase::finish_thaw(frame& f) { } void ThawBase::push_return_frame(const frame& f) { // see generate_cont_thaw - 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()), ""); + assert(!f.is_compiled_frame() || verify_deopt_state(f), ""); LogTarget(Trace, continuations) lt; if (lt.develop_is_enabled()) { @@ -3170,6 +3190,14 @@ static bool do_verify_after_thaw(JavaThread* thread, stackChunkOop chunk, output return true; } +static bool verify_deopt_state(const frame& f) { + nmethod* nm = f.cb()->as_nmethod(); + assert(f.is_deoptimized_frame() == nm->is_deopt_pc(f.raw_pc()), ""); + assert(f.is_deoptimized_frame() == (f.pc() != f.raw_pc()), ""); + assert(f.is_deoptimized_frame() == nm->is_deopt_pc(ContinuationHelper::Frame::real_pc(f)), ""); + return true; +} + static void log_frames(JavaThread* thread) { const static int show_entry_callers = 3; LogTarget(Trace, continuations) lt; diff --git a/src/hotspot/share/runtime/deoptimization.cpp b/src/hotspot/share/runtime/deoptimization.cpp index cfdcf52a5eb..9db9c676268 100644 --- a/src/hotspot/share/runtime/deoptimization.cpp +++ b/src/hotspot/share/runtime/deoptimization.cpp @@ -249,9 +249,9 @@ Deoptimization::UnrollBlock::UnrollBlock(int size_of_deoptimized_frame, } Deoptimization::UnrollBlock::~UnrollBlock() { - FREE_C_HEAP_ARRAY(intptr_t, _frame_sizes); - FREE_C_HEAP_ARRAY(intptr_t, _frame_pcs); - FREE_C_HEAP_ARRAY(intptr_t, _register_block); + FREE_C_HEAP_ARRAY(_frame_sizes); + FREE_C_HEAP_ARRAY(_frame_pcs); + FREE_C_HEAP_ARRAY(_register_block); } int Deoptimization::UnrollBlock::size_of_frames() const { diff --git a/src/hotspot/share/runtime/deoptimization.hpp b/src/hotspot/share/runtime/deoptimization.hpp index d168d9c8af6..f42976fa5de 100644 --- a/src/hotspot/share/runtime/deoptimization.hpp +++ b/src/hotspot/share/runtime/deoptimization.hpp @@ -355,7 +355,7 @@ class Deoptimization : AllStatic { } static int trap_request_debug_id(int trap_request) { if (trap_request < 0) { - return ((~(trap_request) >> _debug_id_shift) & right_n_bits(_debug_id_bits)); + return (~(trap_request) >> _debug_id_shift) & right_n_bits(_debug_id_bits); } else { // standard action for unloaded CP entry return 0; diff --git a/src/hotspot/share/runtime/fieldDescriptor.cpp b/src/hotspot/share/runtime/fieldDescriptor.cpp index 491157d5bf7..4ad916cfff7 100644 --- a/src/hotspot/share/runtime/fieldDescriptor.cpp +++ b/src/hotspot/share/runtime/fieldDescriptor.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -108,8 +108,21 @@ void fieldDescriptor::reinitialize(InstanceKlass* ik, const FieldInfo& fieldinfo guarantee(_fieldinfo.name_index() != 0 && _fieldinfo.signature_index() != 0, "bad constant pool index for fieldDescriptor"); } +void fieldDescriptor::print_access_flags(outputStream* st) const { + AccessFlags flags = access_flags(); + if (flags.is_public ()) st->print("public "); + if (flags.is_private ()) st->print("private "); + if (flags.is_protected()) st->print("protected "); + if (flags.is_static ()) st->print("static "); + if (flags.is_final ()) st->print("final "); + if (flags.is_volatile ()) st->print("volatile "); + if (flags.is_transient()) st->print("transient "); + if (flags.is_enum ()) st->print("enum "); + if (flags.is_synthetic()) st->print("synthetic "); +} + void fieldDescriptor::print_on(outputStream* st) const { - access_flags().print_on(st); + print_access_flags(st); if (field_flags().is_injected()) st->print("injected "); name()->print_value_on(st); st->print(" "); diff --git a/src/hotspot/share/runtime/fieldDescriptor.hpp b/src/hotspot/share/runtime/fieldDescriptor.hpp index fa3d1b9d23c..1b423377cc2 100644 --- a/src/hotspot/share/runtime/fieldDescriptor.hpp +++ b/src/hotspot/share/runtime/fieldDescriptor.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -111,6 +111,7 @@ class fieldDescriptor { void print() const; void print_on(outputStream* st) const; void print_on_for(outputStream* st, oop obj); + void print_access_flags(outputStream* st) const; }; #endif // SHARE_RUNTIME_FIELDDESCRIPTOR_HPP diff --git a/src/hotspot/share/runtime/flags/jvmFlag.cpp b/src/hotspot/share/runtime/flags/jvmFlag.cpp index 405b47e1813..1c965360599 100644 --- a/src/hotspot/share/runtime/flags/jvmFlag.cpp +++ b/src/hotspot/share/runtime/flags/jvmFlag.cpp @@ -648,7 +648,7 @@ void JVMFlag::printSetFlags(outputStream* out) { } } out->cr(); - FREE_C_HEAP_ARRAY(JVMFlag*, array); + FREE_C_HEAP_ARRAY(array); } #ifndef PRODUCT diff --git a/src/hotspot/share/runtime/flags/jvmFlagAccess.cpp b/src/hotspot/share/runtime/flags/jvmFlagAccess.cpp index 2db9f198ddd..8efa8f2de62 100644 --- a/src/hotspot/share/runtime/flags/jvmFlagAccess.cpp +++ b/src/hotspot/share/runtime/flags/jvmFlagAccess.cpp @@ -329,7 +329,7 @@ JVMFlag::Error JVMFlagAccess::set_ccstr(JVMFlag* flag, ccstr* value, JVMFlagOrig flag->set_ccstr(new_value); if (!flag->is_default() && old_value != nullptr) { // Old value is heap allocated so free it. - FREE_C_HEAP_ARRAY(char, old_value); + FREE_C_HEAP_ARRAY(old_value); } // Unlike the other APIs, the old value is NOT returned, so the caller won't need to free it. // The callers typically don't care what the old value is. diff --git a/src/hotspot/share/runtime/frame.cpp b/src/hotspot/share/runtime/frame.cpp index d691a3c8028..68010a17ea4 100644 --- a/src/hotspot/share/runtime/frame.cpp +++ b/src/hotspot/share/runtime/frame.cpp @@ -1133,22 +1133,6 @@ void frame::oops_upcall_do(OopClosure* f, const RegisterMap* map) const { _cb->as_upcall_stub()->oops_do(f, *this); } -bool frame::is_deoptimized_frame() const { - assert(_deopt_state != unknown, "not answerable"); - if (_deopt_state == is_deoptimized) { - return true; - } - - /* This method only checks if the frame is deoptimized - * as in return address being patched. - * It doesn't care if the OP that we return to is a - * deopt instruction */ - /*if (_cb != nullptr && _cb->is_nmethod()) { - return NativeDeoptInstruction::is_deopt_at(_pc); - }*/ - return false; -} - void frame::oops_do_internal(OopClosure* f, NMethodClosure* cf, DerivedOopClosure* df, DerivedPointerIterationMode derived_mode, const RegisterMap* map, bool use_interpreter_oop_map_cache) const { diff --git a/src/hotspot/share/runtime/frame.hpp b/src/hotspot/share/runtime/frame.hpp index f54553086f6..a80d12d7853 100644 --- a/src/hotspot/share/runtime/frame.hpp +++ b/src/hotspot/share/runtime/frame.hpp @@ -214,6 +214,9 @@ class frame { // tells whether this frame can be deoptimized bool can_be_deoptimized() const; + // used by virtual thread thaw code to fix deopt state + inline void set_deoptimized(); + // the frame size in machine words inline int frame_size() const; diff --git a/src/hotspot/share/runtime/frame.inline.hpp b/src/hotspot/share/runtime/frame.inline.hpp index cbf01dd5763..fbd51d117cf 100644 --- a/src/hotspot/share/runtime/frame.inline.hpp +++ b/src/hotspot/share/runtime/frame.inline.hpp @@ -84,6 +84,19 @@ inline address frame::get_deopt_original_pc() const { return nullptr; } +inline bool frame::is_deoptimized_frame() const { + assert(_deopt_state != unknown, "not answerable"); + return _deopt_state == is_deoptimized; +} + +inline void frame::set_deoptimized() { + assert(is_compiled_frame(), "invalid operation"); + assert(_cb == CodeCache::find_blob(_pc), "invalid _pc"); + DEBUG_ONLY(nmethod* nm = _cb->as_nmethod();) + assert(!nm->is_deopt_pc(_pc) && nm->get_original_pc(this) == _pc, "wrong _pc"); + _deopt_state = is_deoptimized; +} + 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/globals.hpp b/src/hotspot/share/runtime/globals.hpp index 9d38a44cbd5..14faef0d8e9 100644 --- a/src/hotspot/share/runtime/globals.hpp +++ b/src/hotspot/share/runtime/globals.hpp @@ -147,6 +147,11 @@ const int ObjectAlignmentInBytes = 8; #endif // _LP64 +// Default value for PrintAssemblyOptions, set via --with-print-assembly-options. +#ifndef DEFAULT_PRINT_ASSEMBLY_OPTIONS +#define DEFAULT_PRINT_ASSEMBLY_OPTIONS nullptr +#endif + #define RUNTIME_FLAGS(develop, \ develop_pd, \ product, \ @@ -611,7 +616,8 @@ const int ObjectAlignmentInBytes = 8; product(bool, PrintAssembly, false, DIAGNOSTIC, \ "Print assembly code (using external disassembler.so)") \ \ - product(ccstr, PrintAssemblyOptions, nullptr, DIAGNOSTIC, \ + product(ccstr, PrintAssemblyOptions, DEFAULT_PRINT_ASSEMBLY_OPTIONS, \ + DIAGNOSTIC, \ "Print options string passed to disassembler.so") \ \ develop(bool, PrintNMethodStatistics, false, \ diff --git a/src/hotspot/share/runtime/interfaceSupport.inline.hpp b/src/hotspot/share/runtime/interfaceSupport.inline.hpp index cd3a45a8d3c..bf9bd82b47c 100644 --- a/src/hotspot/share/runtime/interfaceSupport.inline.hpp +++ b/src/hotspot/share/runtime/interfaceSupport.inline.hpp @@ -423,6 +423,14 @@ extern "C" { \ VM_LEAF_BASE(result_type, header) +#define JVM_ENTRY_FROM_LEAF(env, result_type, header) \ + { { \ + JavaThread* thread=JavaThread::thread_from_jni_environment(env); \ + ThreadInVMfromNative __tiv(thread); \ + DEBUG_ONLY(VMNativeEntryWrapper __vew;) \ + VM_ENTRY_BASE_FROM_LEAF(result_type, header, thread) + + #define JVM_END } } #endif // SHARE_RUNTIME_INTERFACESUPPORT_INLINE_HPP diff --git a/src/hotspot/share/runtime/javaThread.cpp b/src/hotspot/share/runtime/javaThread.cpp index 77a567d4a09..5a29a668a54 100644 --- a/src/hotspot/share/runtime/javaThread.cpp +++ b/src/hotspot/share/runtime/javaThread.cpp @@ -37,6 +37,7 @@ #include "gc/shared/oopStorage.hpp" #include "gc/shared/oopStorageSet.hpp" #include "gc/shared/tlab_globals.hpp" +#include "interpreter/bytecodeTracer.hpp" #include "jfr/jfrEvents.hpp" #include "jvm.h" #include "jvmtifiles/jvmtiEnv.hpp" @@ -308,7 +309,7 @@ static jlong* resize_counters_array(jlong* old_counters, int current_size, int n if (new_size > current_size) { memset(new_counters + current_size, 0, sizeof(jlong) * (new_size - current_size)); } - FREE_C_HEAP_ARRAY(jlong, old_counters); + FREE_C_HEAP_ARRAY(old_counters); } return new_counters; } @@ -432,6 +433,8 @@ JavaThread::JavaThread(MemTag mem_tag) : _visited_for_critical_count(false), #endif + NOT_PRODUCT(_bytecode_tracer_data{} COMMA) + _terminated(_not_terminated), _in_deopt_handler(0), _doing_unsafe_access(false), @@ -700,7 +703,7 @@ JavaThread::~JavaThread() { #if INCLUDE_JVMCI if (JVMCICounterSize > 0) { - FREE_C_HEAP_ARRAY(jlong, _jvmci_counters); + FREE_C_HEAP_ARRAY(_jvmci_counters); } #endif // INCLUDE_JVMCI } @@ -1884,7 +1887,7 @@ WordSize JavaThread::popframe_preserved_args_size_in_words() { void JavaThread::popframe_free_preserved_args() { assert(_popframe_preserved_args != nullptr, "should not free PopFrame preserved arguments twice"); - FREE_C_HEAP_ARRAY(char, (char*)_popframe_preserved_args); + FREE_C_HEAP_ARRAY((char*)_popframe_preserved_args); _popframe_preserved_args = nullptr; _popframe_preserved_args_size = 0; } diff --git a/src/hotspot/share/runtime/javaThread.hpp b/src/hotspot/share/runtime/javaThread.hpp index 755a6abe0d8..bc6c0a3a4fd 100644 --- a/src/hotspot/share/runtime/javaThread.hpp +++ b/src/hotspot/share/runtime/javaThread.hpp @@ -26,6 +26,9 @@ #ifndef SHARE_RUNTIME_JAVATHREAD_HPP #define SHARE_RUNTIME_JAVATHREAD_HPP +#ifndef PRODUCT +#include "interpreter/bytecodeTracer.hpp" +#endif // PRODUCT #include "jni.h" #include "memory/allocation.hpp" #include "oops/oop.hpp" @@ -291,6 +294,16 @@ class JavaThread: public Thread { } #endif // ASSERT +#ifndef PRODUCT + private: + BytecodeTracerData _bytecode_tracer_data; + + public: + BytecodeTracerData* bytecode_tracer_data() { + return &_bytecode_tracer_data; + } +#endif // PRODUCT + // JavaThread termination support public: enum TerminatedTypes { diff --git a/src/hotspot/share/runtime/nonJavaThread.cpp b/src/hotspot/share/runtime/nonJavaThread.cpp index cb0c3f8910d..e8f01086058 100644 --- a/src/hotspot/share/runtime/nonJavaThread.cpp +++ b/src/hotspot/share/runtime/nonJavaThread.cpp @@ -133,7 +133,7 @@ NamedThread::NamedThread() : {} NamedThread::~NamedThread() { - FREE_C_HEAP_ARRAY(char, _name); + FREE_C_HEAP_ARRAY(_name); } void NamedThread::set_name(const char* format, ...) { diff --git a/src/hotspot/share/runtime/objectMonitorTable.cpp b/src/hotspot/share/runtime/objectMonitorTable.cpp index bc173992d7a..9f087ad5dee 100644 --- a/src/hotspot/share/runtime/objectMonitorTable.cpp +++ b/src/hotspot/share/runtime/objectMonitorTable.cpp @@ -192,7 +192,7 @@ public: } ~Table() { - FREE_C_HEAP_ARRAY(Atomic, _buckets); + FREE_C_HEAP_ARRAY(_buckets); } Table* prev() { diff --git a/src/hotspot/share/runtime/os.cpp b/src/hotspot/share/runtime/os.cpp index d55cf454256..f9e3a513a78 100644 --- a/src/hotspot/share/runtime/os.cpp +++ b/src/hotspot/share/runtime/os.cpp @@ -303,10 +303,10 @@ static void free_array_of_char_arrays(char** a, size_t n) { while (n > 0) { n--; if (a[n] != nullptr) { - FREE_C_HEAP_ARRAY(char, a[n]); + FREE_C_HEAP_ARRAY(a[n]); } } - FREE_C_HEAP_ARRAY(char*, a); + FREE_C_HEAP_ARRAY(a); } bool os::dll_locate_lib(char *buffer, size_t buflen, @@ -353,7 +353,7 @@ bool os::dll_locate_lib(char *buffer, size_t buflen, } } - FREE_C_HEAP_ARRAY(char*, fullfname); + FREE_C_HEAP_ARRAY(fullfname); return retval; } @@ -562,7 +562,7 @@ void* os::find_agent_function(JvmtiAgent *agent_lib, bool check_lib, const char char* agent_function_name = build_agent_function_name(sym, lib_name, agent_lib->is_absolute_path()); if (agent_function_name != nullptr) { entryName = dll_lookup(handle, agent_function_name); - FREE_C_HEAP_ARRAY(char, agent_function_name); + FREE_C_HEAP_ARRAY(agent_function_name); } return entryName; } @@ -1510,20 +1510,20 @@ bool os::set_boot_path(char fileSep, char pathSep) { bool has_jimage = (os::stat(jimage, &st) == 0); if (has_jimage) { Arguments::set_boot_class_path(jimage, true); - FREE_C_HEAP_ARRAY(char, jimage); + FREE_C_HEAP_ARRAY(jimage); return true; } - FREE_C_HEAP_ARRAY(char, jimage); + FREE_C_HEAP_ARRAY(jimage); // check if developer build with exploded modules char* base_classes = format_boot_path("%/modules/" JAVA_BASE_NAME, home, home_len, fileSep, pathSep); if (base_classes == nullptr) return false; if (os::stat(base_classes, &st) == 0) { Arguments::set_boot_class_path(base_classes, false); - FREE_C_HEAP_ARRAY(char, base_classes); + FREE_C_HEAP_ARRAY(base_classes); return true; } - FREE_C_HEAP_ARRAY(char, base_classes); + FREE_C_HEAP_ARRAY(base_classes); return false; } @@ -1653,7 +1653,7 @@ char** os::split_path(const char* path, size_t* elements, size_t file_name_lengt opath[i] = s; p += len + 1; } - FREE_C_HEAP_ARRAY(char, inpath); + FREE_C_HEAP_ARRAY(inpath); *elements = count; return opath; } diff --git a/src/hotspot/share/runtime/os_perf.hpp b/src/hotspot/share/runtime/os_perf.hpp index 8e39b75deb6..a9a82a41b7e 100644 --- a/src/hotspot/share/runtime/os_perf.hpp +++ b/src/hotspot/share/runtime/os_perf.hpp @@ -152,9 +152,9 @@ class SystemProcess : public CHeapObj { } virtual ~SystemProcess(void) { - FREE_C_HEAP_ARRAY(char, _name); - FREE_C_HEAP_ARRAY(char, _path); - FREE_C_HEAP_ARRAY(char, _command_line); + FREE_C_HEAP_ARRAY(_name); + FREE_C_HEAP_ARRAY(_path); + FREE_C_HEAP_ARRAY(_command_line); } }; diff --git a/src/hotspot/share/runtime/perfData.cpp b/src/hotspot/share/runtime/perfData.cpp index 7532ada8f5a..1502995203d 100644 --- a/src/hotspot/share/runtime/perfData.cpp +++ b/src/hotspot/share/runtime/perfData.cpp @@ -118,9 +118,9 @@ PerfData::PerfData(CounterNS ns, const char* name, Units u, Variability v) } PerfData::~PerfData() { - FREE_C_HEAP_ARRAY(char, _name); + FREE_C_HEAP_ARRAY(_name); if (is_on_c_heap()) { - FREE_C_HEAP_ARRAY(PerfDataEntry, _pdep); + FREE_C_HEAP_ARRAY(_pdep); } } diff --git a/src/hotspot/share/runtime/perfData.hpp b/src/hotspot/share/runtime/perfData.hpp index d910f8662fe..9c87f87f688 100644 --- a/src/hotspot/share/runtime/perfData.hpp +++ b/src/hotspot/share/runtime/perfData.hpp @@ -233,7 +233,7 @@ class PerfData : public CHeapObj { public: // the Variability enum must be kept in synchronization with the - // the com.sun.hotspot.perfdata.Variability class + // the sun.management.counter.Variability class enum Variability { V_Constant = 1, V_Monotonic = 2, @@ -242,7 +242,7 @@ class PerfData : public CHeapObj { }; // the Units enum must be kept in synchronization with the - // the com.sun.hotspot.perfdata.Units class + // the sun.management.counter.Units class enum Units { U_None = 1, U_Bytes = 2, diff --git a/src/hotspot/share/runtime/perfMemory.cpp b/src/hotspot/share/runtime/perfMemory.cpp index 9594149333e..134d1c47230 100644 --- a/src/hotspot/share/runtime/perfMemory.cpp +++ b/src/hotspot/share/runtime/perfMemory.cpp @@ -247,7 +247,7 @@ char* PerfMemory::get_perfdata_file_path() { dest_file = NEW_C_HEAP_ARRAY(char, JVM_MAXPATHLEN, mtInternal); if(!Arguments::copy_expand_pid(PerfDataSaveFile, strlen(PerfDataSaveFile), dest_file, JVM_MAXPATHLEN)) { - FREE_C_HEAP_ARRAY(char, dest_file); + FREE_C_HEAP_ARRAY(dest_file); log_debug(perf)("invalid performance data file path name specified, fall back to a default name"); } else { return dest_file; diff --git a/src/hotspot/share/runtime/sharedRuntime.cpp b/src/hotspot/share/runtime/sharedRuntime.cpp index 352c90f913b..3b5a6fa7ff8 100644 --- a/src/hotspot/share/runtime/sharedRuntime.cpp +++ b/src/hotspot/share/runtime/sharedRuntime.cpp @@ -3085,7 +3085,7 @@ AdapterHandlerEntry::~AdapterHandlerEntry() { _fingerprint = nullptr; } #ifdef ASSERT - FREE_C_HEAP_ARRAY(unsigned char, _saved_code); + FREE_C_HEAP_ARRAY(_saved_code); #endif FreeHeap(this); } @@ -3376,7 +3376,7 @@ JRT_LEAF(intptr_t*, SharedRuntime::OSR_migration_begin( JavaThread *current) ) JRT_END JRT_LEAF(void, SharedRuntime::OSR_migration_end( intptr_t* buf) ) - FREE_C_HEAP_ARRAY(intptr_t, buf); + FREE_C_HEAP_ARRAY(buf); JRT_END const char* AdapterHandlerLibrary::name(AdapterHandlerEntry* handler) { diff --git a/src/hotspot/share/runtime/threadSMR.cpp b/src/hotspot/share/runtime/threadSMR.cpp index 4c68648fec8..d70b7dcbd34 100644 --- a/src/hotspot/share/runtime/threadSMR.cpp +++ b/src/hotspot/share/runtime/threadSMR.cpp @@ -667,7 +667,7 @@ ThreadsList::ThreadsList(int entries) : ThreadsList::~ThreadsList() { if (_threads != empty_threads_list_data) { - FREE_C_HEAP_ARRAY(JavaThread*, _threads); + FREE_C_HEAP_ARRAY(_threads); } _magic = 0xDEADBEEF; } diff --git a/src/hotspot/share/runtime/threads.cpp b/src/hotspot/share/runtime/threads.cpp index b83389a1929..27c4c588429 100644 --- a/src/hotspot/share/runtime/threads.cpp +++ b/src/hotspot/share/runtime/threads.cpp @@ -1062,7 +1062,7 @@ void Threads::destroy_vm() { #if INCLUDE_JVMCI if (JVMCICounterSize > 0) { - FREE_C_HEAP_ARRAY(jlong, JavaThread::_jvmci_old_thread_counters); + FREE_C_HEAP_ARRAY(JavaThread::_jvmci_old_thread_counters); } #endif diff --git a/src/hotspot/share/runtime/vmStructs.cpp b/src/hotspot/share/runtime/vmStructs.cpp index ad9463443b2..6ae9de05518 100644 --- a/src/hotspot/share/runtime/vmStructs.cpp +++ b/src/hotspot/share/runtime/vmStructs.cpp @@ -2086,10 +2086,10 @@ static int recursiveFindType(VMTypeEntry* origtypes, const char* typeName, bool s[len-1] = '\0'; // tty->print_cr("checking \"%s\" for \"%s\"", s, typeName); if (recursiveFindType(origtypes, s, true) == 1) { - FREE_C_HEAP_ARRAY(char, s); + FREE_C_HEAP_ARRAY(s); return 1; } - FREE_C_HEAP_ARRAY(char, s); + FREE_C_HEAP_ARRAY(s); } const char* start = nullptr; if (strstr(typeName, "GrowableArray<") == typeName) { @@ -2105,10 +2105,10 @@ static int recursiveFindType(VMTypeEntry* origtypes, const char* typeName, bool s[len-1] = '\0'; // tty->print_cr("checking \"%s\" for \"%s\"", s, typeName); if (recursiveFindType(origtypes, s, true) == 1) { - FREE_C_HEAP_ARRAY(char, s); + FREE_C_HEAP_ARRAY(s); return 1; } - FREE_C_HEAP_ARRAY(char, s); + FREE_C_HEAP_ARRAY(s); } if (strstr(typeName, "const ") == typeName) { const char * s = typeName + strlen("const "); diff --git a/src/hotspot/share/services/diagnosticArgument.cpp b/src/hotspot/share/services/diagnosticArgument.cpp index 247ab50bde7..0ba7bda2719 100644 --- a/src/hotspot/share/services/diagnosticArgument.cpp +++ b/src/hotspot/share/services/diagnosticArgument.cpp @@ -36,7 +36,7 @@ StringArrayArgument::StringArrayArgument() { StringArrayArgument::~StringArrayArgument() { for (int i=0; i<_array->length(); i++) { - FREE_C_HEAP_ARRAY(char, _array->at(i)); + FREE_C_HEAP_ARRAY(_array->at(i)); } delete _array; } @@ -183,7 +183,7 @@ template <> void DCmdArgument::init_value(TRAPS) { template <> void DCmdArgument::destroy_value() { } template <> void DCmdArgument::destroy_value() { - FREE_C_HEAP_ARRAY(char, _value); + FREE_C_HEAP_ARRAY(_value); set_value(nullptr); } @@ -194,14 +194,14 @@ template <> void DCmdArgument::parse_value(const char* str, } else { // Use realloc as we may have a default set. if (strcmp(type(), "FILE") == 0) { - _value = REALLOC_C_HEAP_ARRAY(char, _value, JVM_MAXPATHLEN, mtInternal); + _value = REALLOC_C_HEAP_ARRAY(_value, JVM_MAXPATHLEN, mtInternal); if (!Arguments::copy_expand_pid(str, len, _value, JVM_MAXPATHLEN)) { stringStream error_msg; error_msg.print("File path invalid or too long: %s", str); THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(), error_msg.base()); } } else { - _value = REALLOC_C_HEAP_ARRAY(char, _value, len + 1, mtInternal); + _value = REALLOC_C_HEAP_ARRAY(_value, len + 1, mtInternal); int n = os::snprintf(_value, len + 1, "%.*s", (int)len, str); assert((size_t)n <= len, "Unexpected number of characters in string"); } diff --git a/src/hotspot/share/services/finalizerService.cpp b/src/hotspot/share/services/finalizerService.cpp index 9acf17b8cfd..d57d0fb5b50 100644 --- a/src/hotspot/share/services/finalizerService.cpp +++ b/src/hotspot/share/services/finalizerService.cpp @@ -93,7 +93,7 @@ FinalizerEntry::FinalizerEntry(const InstanceKlass* ik) : _total_finalizers_run(0) {} FinalizerEntry::~FinalizerEntry() { - FREE_C_HEAP_ARRAY(char, _codesource); + FREE_C_HEAP_ARRAY(_codesource); } const InstanceKlass* FinalizerEntry::klass() const { diff --git a/src/hotspot/share/services/heapDumper.cpp b/src/hotspot/share/services/heapDumper.cpp index bfb4546a8a1..c850a3a711f 100644 --- a/src/hotspot/share/services/heapDumper.cpp +++ b/src/hotspot/share/services/heapDumper.cpp @@ -2308,7 +2308,7 @@ class VM_HeapDumper : public VM_GC_Operation, public WorkerTask, public Unmounte for (int i = 0; i < _thread_dumpers_count; i++) { delete _thread_dumpers[i]; } - FREE_C_HEAP_ARRAY(ThreadDumper*, _thread_dumpers); + FREE_C_HEAP_ARRAY(_thread_dumpers); } if (_dumper_controller != nullptr) { diff --git a/src/hotspot/share/services/management.cpp b/src/hotspot/share/services/management.cpp index 664fb5a8ef3..36db3df056f 100644 --- a/src/hotspot/share/services/management.cpp +++ b/src/hotspot/share/services/management.cpp @@ -1715,7 +1715,7 @@ ThreadTimesClosure::~ThreadTimesClosure() { for (int i = 0; i < _count; i++) { os::free(_names_chars[i]); } - FREE_C_HEAP_ARRAY(char *, _names_chars); + FREE_C_HEAP_ARRAY(_names_chars); } // Fills names with VM internal thread names and times with the corresponding diff --git a/src/hotspot/share/services/memoryManager.cpp b/src/hotspot/share/services/memoryManager.cpp index ef9babbb20d..2d725db85b5 100644 --- a/src/hotspot/share/services/memoryManager.cpp +++ b/src/hotspot/share/services/memoryManager.cpp @@ -163,8 +163,8 @@ GCStatInfo::GCStatInfo(int num_pools) { } GCStatInfo::~GCStatInfo() { - FREE_C_HEAP_ARRAY(MemoryUsage*, _before_gc_usage_array); - FREE_C_HEAP_ARRAY(MemoryUsage*, _after_gc_usage_array); + FREE_C_HEAP_ARRAY(_before_gc_usage_array); + FREE_C_HEAP_ARRAY(_after_gc_usage_array); } void GCStatInfo::set_gc_usage(int pool_index, MemoryUsage usage, bool before_gc) { diff --git a/src/hotspot/share/utilities/accessFlags.cpp b/src/hotspot/share/utilities/accessFlags.cpp index ab4c7cde709..0988da18c51 100644 --- a/src/hotspot/share/utilities/accessFlags.cpp +++ b/src/hotspot/share/utilities/accessFlags.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -22,29 +22,8 @@ * */ -#include "oops/oop.inline.hpp" -#include "runtime/atomicAccess.hpp" #include "utilities/accessFlags.hpp" -#if !defined(PRODUCT) || INCLUDE_JVMTI - -void AccessFlags::print_on(outputStream* st) const { - if (is_public ()) st->print("public " ); - if (is_private ()) st->print("private " ); - if (is_protected ()) st->print("protected " ); - if (is_static ()) st->print("static " ); - if (is_final ()) st->print("final " ); - if (is_synchronized()) st->print("synchronized "); - if (is_volatile ()) st->print("volatile " ); - if (is_transient ()) st->print("transient " ); - if (is_native ()) st->print("native " ); - if (is_interface ()) st->print("interface " ); - if (is_abstract ()) st->print("abstract " ); - if (is_synthetic ()) st->print("synthetic " ); -} - -#endif // !PRODUCT || INCLUDE_JVMTI - void accessFlags_init() { assert(sizeof(AccessFlags) == sizeof(u2), "just checking size of flags"); } diff --git a/src/hotspot/share/utilities/accessFlags.hpp b/src/hotspot/share/utilities/accessFlags.hpp index 54bbaeb2c13..a0aef9daa0c 100644 --- a/src/hotspot/share/utilities/accessFlags.hpp +++ b/src/hotspot/share/utilities/accessFlags.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -53,10 +53,15 @@ class AccessFlags { bool is_synchronized() const { return (_flags & JVM_ACC_SYNCHRONIZED) != 0; } bool is_super () const { return (_flags & JVM_ACC_SUPER ) != 0; } bool is_volatile () const { return (_flags & JVM_ACC_VOLATILE ) != 0; } + bool is_bridge () const { return (_flags & JVM_ACC_BRIDGE ) != 0; } bool is_transient () const { return (_flags & JVM_ACC_TRANSIENT ) != 0; } + bool is_varargs () const { return (_flags & JVM_ACC_VARARGS ) != 0; } bool is_native () const { return (_flags & JVM_ACC_NATIVE ) != 0; } + bool is_enum () const { return (_flags & JVM_ACC_ENUM ) != 0; } + bool is_annotation () const { return (_flags & JVM_ACC_ANNOTATION ) != 0; } bool is_interface () const { return (_flags & JVM_ACC_INTERFACE ) != 0; } bool is_abstract () const { return (_flags & JVM_ACC_ABSTRACT ) != 0; } + bool is_strictfp () const { return (_flags & JVM_ACC_STRICT ) != 0; } // Attribute flags bool is_synthetic () const { return (_flags & JVM_ACC_SYNTHETIC ) != 0; } @@ -92,13 +97,6 @@ class AccessFlags { assert((_flags & JVM_RECOGNIZED_CLASS_MODIFIERS) == _flags, "only recognized flags"); return _flags; } - - // Printing/debugging -#if INCLUDE_JVMTI - void print_on(outputStream* st) const; -#else - void print_on(outputStream* st) const PRODUCT_RETURN; -#endif }; inline AccessFlags accessFlags_from(u2 flags) { diff --git a/src/hotspot/share/utilities/concurrentHashTable.inline.hpp b/src/hotspot/share/utilities/concurrentHashTable.inline.hpp index 62d2dd29dab..d5f6dee336b 100644 --- a/src/hotspot/share/utilities/concurrentHashTable.inline.hpp +++ b/src/hotspot/share/utilities/concurrentHashTable.inline.hpp @@ -217,7 +217,7 @@ template inline ConcurrentHashTable:: InternalTable::~InternalTable() { - FREE_C_HEAP_ARRAY(Bucket, _buckets); + FREE_C_HEAP_ARRAY(_buckets); } // ScopedCS diff --git a/src/hotspot/share/utilities/elfFile.cpp b/src/hotspot/share/utilities/elfFile.cpp index 0b7713e9ca9..e81f9128292 100644 --- a/src/hotspot/share/utilities/elfFile.cpp +++ b/src/hotspot/share/utilities/elfFile.cpp @@ -942,7 +942,7 @@ bool DwarfFile::ArangesCache::add_entry(const AddressDescriptor& descriptor, uin bool DwarfFile::ArangesCache::grow() { size_t new_capacity = _capacity == 0 ? 128 : _capacity * 1.5; - ArangesEntry* new_entries = REALLOC_C_HEAP_ARRAY_RETURN_NULL(ArangesEntry, _entries, new_capacity, mtInternal); + ArangesEntry* new_entries = REALLOC_C_HEAP_ARRAY_RETURN_NULL(_entries, new_capacity, mtInternal); if (new_entries == nullptr) { return false; } diff --git a/src/hotspot/share/utilities/elfFile.hpp b/src/hotspot/share/utilities/elfFile.hpp index 8abd846364c..0bfa821e256 100644 --- a/src/hotspot/share/utilities/elfFile.hpp +++ b/src/hotspot/share/utilities/elfFile.hpp @@ -487,7 +487,7 @@ class DwarfFile : public ElfFile { bool grow(); void free() { if (_entries != nullptr) { - FREE_C_HEAP_ARRAY(ArangesEntry, _entries); + FREE_C_HEAP_ARRAY(_entries); _entries = nullptr; } } diff --git a/src/hotspot/share/utilities/growableArray.cpp b/src/hotspot/share/utilities/growableArray.cpp index 9cc0813a1f6..dc6c24ea7e0 100644 --- a/src/hotspot/share/utilities/growableArray.cpp +++ b/src/hotspot/share/utilities/growableArray.cpp @@ -57,7 +57,7 @@ void* GrowableArrayCHeapAllocator::allocate(int max, int element_size, MemTag me } void GrowableArrayCHeapAllocator::deallocate(void* elements) { - if (!AOTMetaspace::in_aot_cache(elements)) { + if (!MetaspaceObj::is_pointer_in_aot_cache(elements)) { FreeHeap(elements); } } diff --git a/src/hotspot/share/utilities/istream.cpp b/src/hotspot/share/utilities/istream.cpp index ce622c2c282..c78fa5d1efa 100644 --- a/src/hotspot/share/utilities/istream.cpp +++ b/src/hotspot/share/utilities/istream.cpp @@ -265,7 +265,7 @@ bool inputStream::expand_buffer(size_t new_length) { } else { // realloc COV(EXB_R); - new_buf = REALLOC_C_HEAP_ARRAY(char, _buffer, new_length, mtInternal); + new_buf = REALLOC_C_HEAP_ARRAY(_buffer, new_length, mtInternal); assert(new_buf != nullptr, "would have exited VM if OOM"); } diff --git a/src/hotspot/share/utilities/numberSeq.cpp b/src/hotspot/share/utilities/numberSeq.cpp index 536f6563866..9d4ece105ed 100644 --- a/src/hotspot/share/utilities/numberSeq.cpp +++ b/src/hotspot/share/utilities/numberSeq.cpp @@ -144,7 +144,7 @@ TruncatedSeq::TruncatedSeq(int length, double alpha): } TruncatedSeq::~TruncatedSeq() { - FREE_C_HEAP_ARRAY(double, _sequence); + FREE_C_HEAP_ARRAY(_sequence); } void TruncatedSeq::add(double val) { diff --git a/src/hotspot/share/utilities/ostream.cpp b/src/hotspot/share/utilities/ostream.cpp index ded233d48bf..f052431d55e 100644 --- a/src/hotspot/share/utilities/ostream.cpp +++ b/src/hotspot/share/utilities/ostream.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -369,7 +369,7 @@ void stringStream::grow(size_t new_capacity) { } zero_terminate(); } else { - _buffer = REALLOC_C_HEAP_ARRAY(char, _buffer, new_capacity, mtInternal); + _buffer = REALLOC_C_HEAP_ARRAY(_buffer, new_capacity, mtInternal); _capacity = new_capacity; } } @@ -425,11 +425,6 @@ char* stringStream::as_string(bool c_heap) const { NEW_C_HEAP_ARRAY(char, _written + 1, mtInternal) : NEW_RESOURCE_ARRAY(char, _written + 1); ::memcpy(copy, _buffer, _written); copy[_written] = '\0'; // terminating null - if (c_heap) { - // Need to ensure our content is written to memory before we return - // the pointer to it. - OrderAccess::storestore(); - } return copy; } @@ -442,7 +437,7 @@ char* stringStream::as_string(Arena* arena) const { stringStream::~stringStream() { if (!_is_fixed && _buffer != _small_buffer) { - FREE_C_HEAP_ARRAY(char, _buffer); + FREE_C_HEAP_ARRAY(_buffer); } } @@ -681,7 +676,7 @@ fileStream* defaultStream::open_file(const char* log_name) { } fileStream* file = new (mtInternal) fileStream(try_name); - FREE_C_HEAP_ARRAY(char, try_name); + FREE_C_HEAP_ARRAY(try_name); if (file->is_open()) { return file; } @@ -699,7 +694,7 @@ fileStream* defaultStream::open_file(const char* log_name) { jio_printf("Warning: Forcing option -XX:LogFile=%s\n", try_name); file = new (mtInternal) fileStream(try_name); - FREE_C_HEAP_ARRAY(char, try_name); + FREE_C_HEAP_ARRAY(try_name); if (file->is_open()) { return file; } @@ -1056,7 +1051,7 @@ void bufferedStream::write(const char* s, size_t len) { } } if (buffer_length < end) { - buffer = REALLOC_C_HEAP_ARRAY(char, buffer, end, mtInternal); + buffer = REALLOC_C_HEAP_ARRAY(buffer, end, mtInternal); buffer_length = end; } } @@ -1075,7 +1070,7 @@ char* bufferedStream::as_string() { } bufferedStream::~bufferedStream() { - FREE_C_HEAP_ARRAY(char, buffer); + FREE_C_HEAP_ARRAY(buffer); } #ifndef PRODUCT diff --git a/src/hotspot/share/utilities/rbTree.hpp b/src/hotspot/share/utilities/rbTree.hpp index 9c04ccbe9ab..fb505ebe9ca 100644 --- a/src/hotspot/share/utilities/rbTree.hpp +++ b/src/hotspot/share/utilities/rbTree.hpp @@ -385,6 +385,15 @@ public: void free_node(RBNode* node); + // Updates the key in the given node or node cursor. + // This will never trigger a tree rebalancing. + // The user must ensure that no tree properties are broken: + // There must not exist any node with the new key + // For all nodes with key < old_key, must also have key < new_key + // For all nodes with key > old_key, must also have key > new_key + void update_key(const Cursor& node_cursor, const K& new_key); + void update_key(RBNode* node, const K& new_key); + // Inserts a node with the given key/value into the tree, // if the key already exist, the value is updated instead. // Returns false if and only if allocation of a new node failed. diff --git a/src/hotspot/share/utilities/rbTree.inline.hpp b/src/hotspot/share/utilities/rbTree.inline.hpp index 381cb916405..1bd8ba8faf8 100644 --- a/src/hotspot/share/utilities/rbTree.inline.hpp +++ b/src/hotspot/share/utilities/rbTree.inline.hpp @@ -1147,6 +1147,29 @@ inline void RBTree::free_node(RBNode* node) { _allocator.free(node); } +template +inline void RBTree::update_key(const Cursor& node_cursor, const K& new_key) { + precond(node_cursor.valid()); + precond(node_cursor.found()); + + RBNode* node = node_cursor.node(); + update_key(node, new_key); +} + +template +inline void RBTree::update_key(RBNode* node, const K& new_key) { + precond(node != nullptr); + #ifdef ASSERT + const RBNode* prev = node->prev(); + const RBNode* next = node->next(); + + if (prev != nullptr) assert(COMPARATOR::cmp(new_key, prev->key()) == RBTreeOrdering::GT, "updated key not GT previous node's key."); + if (next != nullptr) assert(COMPARATOR::cmp(new_key, next->key()) == RBTreeOrdering::LT, "updated key not LT next node's key."); + #endif // ASSERT + + node->_key = new_key; +} + template inline bool RBTree::upsert(const K& key, const V& val, const RBNode* hint_node) { Cursor node_cursor = cursor(key, hint_node); diff --git a/src/hotspot/share/utilities/resizableHashTable.hpp b/src/hotspot/share/utilities/resizableHashTable.hpp index a5b53698b11..8e6528f6a3c 100644 --- a/src/hotspot/share/utilities/resizableHashTable.hpp +++ b/src/hotspot/share/utilities/resizableHashTable.hpp @@ -45,7 +45,7 @@ protected: ~ResizeableHashTableStorage() { if (ALLOC_TYPE == C_HEAP) { - FREE_C_HEAP_ARRAY(Node*, _table); + FREE_C_HEAP_ARRAY(_table); } } @@ -151,7 +151,7 @@ public: } if (ALLOC_TYPE == AnyObj::C_HEAP) { - FREE_C_HEAP_ARRAY(Node*, old_table); + FREE_C_HEAP_ARRAY(old_table); } BASE::_table = new_table; BASE::_table_size = new_size; diff --git a/src/hotspot/share/utilities/stack.inline.hpp b/src/hotspot/share/utilities/stack.inline.hpp index 49ccf416629..78e575a0eaf 100644 --- a/src/hotspot/share/utilities/stack.inline.hpp +++ b/src/hotspot/share/utilities/stack.inline.hpp @@ -145,7 +145,7 @@ E* Stack::alloc(size_t bytes) template void Stack::free(E* addr, size_t bytes) { - FREE_C_HEAP_ARRAY(char, (char*) addr); + FREE_C_HEAP_ARRAY((char*) addr); } // Stack is used by the GC code and in some hot paths a lot of the Stack diff --git a/src/hotspot/share/utilities/stringUtils.cpp b/src/hotspot/share/utilities/stringUtils.cpp index 0872ce43d4b..d133d21e52f 100644 --- a/src/hotspot/share/utilities/stringUtils.cpp +++ b/src/hotspot/share/utilities/stringUtils.cpp @@ -125,7 +125,7 @@ bool StringUtils::is_star_match(const char* star_pattern, const char* str) { } StringUtils::CommaSeparatedStringIterator::~CommaSeparatedStringIterator() { - FREE_C_HEAP_ARRAY(char, _list); + FREE_C_HEAP_ARRAY(_list); } ccstrlist StringUtils::CommaSeparatedStringIterator::canonicalize(ccstrlist option_value) { diff --git a/src/hotspot/share/utilities/xmlstream.cpp b/src/hotspot/share/utilities/xmlstream.cpp index 6dacab1dc25..3ebc1b4b4ac 100644 --- a/src/hotspot/share/utilities/xmlstream.cpp +++ b/src/hotspot/share/utilities/xmlstream.cpp @@ -65,7 +65,7 @@ void xmlStream::initialize(outputStream* out) { #ifdef ASSERT xmlStream::~xmlStream() { - FREE_C_HEAP_ARRAY(char, _element_close_stack_low); + FREE_C_HEAP_ARRAY(_element_close_stack_low); } #endif @@ -169,7 +169,7 @@ void xmlStream::see_tag(const char* tag, bool push) { _element_close_stack_high = new_high; _element_close_stack_low = new_low; _element_close_stack_ptr = new_ptr; - FREE_C_HEAP_ARRAY(char, old_low); + FREE_C_HEAP_ARRAY(old_low); push_ptr = new_ptr - (tag_len+1); } assert(push_ptr >= _element_close_stack_low, "in range"); diff --git a/src/java.base/macosx/native/libosxsecurity/KeystoreImpl.m b/src/java.base/macosx/native/libosxsecurity/KeystoreImpl.m index 6d8eb832370..d59cb6c5abb 100644 --- a/src/java.base/macosx/native/libosxsecurity/KeystoreImpl.m +++ b/src/java.base/macosx/native/libosxsecurity/KeystoreImpl.m @@ -292,7 +292,10 @@ static void addIdentitiesToKeystore(JNIEnv *env, jobject keyStore, jmethodID jm_ if (searchResult == noErr) { // Get the cert from the identity, then generate a chain. SecCertificateRef certificate; - SecIdentityCopyCertificate(theIdentity, &certificate); + OSStatus res = SecIdentityCopyCertificate(theIdentity, &certificate); + if (res != errSecSuccess) { + goto errOut; + } // *** Should do something with this error... err = completeCertChain(theIdentity, NULL, TRUE, &certChain); @@ -302,18 +305,21 @@ static void addIdentitiesToKeystore(JNIEnv *env, jobject keyStore, jmethodID jm_ // Make a java array of certificate data from the chain. jclass byteArrayClass = (*env)->FindClass(env, "[B"); if (byteArrayClass == NULL) { + CFRelease(certificate); goto errOut; } jobjectArray javaCertArray = (*env)->NewObjectArray(env, certCount, byteArrayClass, NULL); // Cleanup first then check for a NULL return code (*env)->DeleteLocalRef(env, byteArrayClass); if (javaCertArray == NULL) { + CFRelease(certificate); goto errOut; } // And, make an array of the certificate refs. jlongArray certRefArray = (*env)->NewLongArray(env, certCount); if (certRefArray == NULL) { + CFRelease(certificate); goto errOut; } @@ -322,10 +328,12 @@ static void addIdentitiesToKeystore(JNIEnv *env, jobject keyStore, jmethodID jm_ for (i = 0; i < certCount; i++) { CSSM_DATA currCertData; - if (i == 0) + if (i == 0) { currCertRef = certificate; - else + } else { currCertRef = (SecCertificateRef)CFArrayGetValueAtIndex(certChain, i); + CFRetain(currCertRef); + } bzero(&currCertData, sizeof(CSSM_DATA)); err = SecCertificateGetData(currCertRef, &currCertData); @@ -342,10 +350,14 @@ static void addIdentitiesToKeystore(JNIEnv *env, jobject keyStore, jmethodID jm_ // Get the private key. When needed we'll export the data from it later. SecKeyRef privateKeyRef; err = SecIdentityCopyPrivateKey(theIdentity, &privateKeyRef); + if (err != errSecSuccess) { + goto errOut; + } // Find the label. It's a 'blob', but we interpret as characters. jstring alias = getLabelFromItem(env, (SecKeychainItemRef)certificate); if (alias == NULL) { + CFRelease(privateKeyRef); goto errOut; } diff --git a/src/java.base/share/classes/com/sun/crypto/provider/PBES1Core.java b/src/java.base/share/classes/com/sun/crypto/provider/PBES1Core.java index e10b0b1a7cf..d614412b13b 100644 --- a/src/java.base/share/classes/com/sun/crypto/provider/PBES1Core.java +++ b/src/java.base/share/classes/com/sun/crypto/provider/PBES1Core.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -47,7 +47,38 @@ final class PBES1Core { private final MessageDigest md; private final String algo; private byte[] salt = null; - private int iCount = 10; + // RFC 8018 and NIST SP 800-132 sec 5.2 recommend 1000 as the minimum + private int iCount = PKCS12PBECipherCore.DEFAULT_COUNT; + + // utility method for checking weak salts of PBEWithMD5AndTripleDES cipher + private static boolean isWeak(byte[] s) { + // consider salts weak if it met both of the following conditions: + // 1) s[0...3] == s[4...7] + // 2) s[0] == s[3] && s[1] == s[2] + if (Arrays.equals(s, 0, 4, s, 4, 8)) { + return (s[0] == s[3]) && (s[1] == s[2]); + } + return false; + } + + // utility method for generating 8-byte salts + private static byte[] generateSalt(String algo, SecureRandom sr) { + byte[] salt = new byte[8]; + sr.nextBytes(salt); + // check and re-generate for DESede if necessary + if (algo.equals("DESede")) { + // prevent an infinite-loop in case of a rigged SecureRandom + int numAttempts = 50; + while (isWeak(salt)) { + sr.nextBytes(salt); + if (numAttempts-- < 0) { + throw new ProviderException( + "Unable to find salts after 50 attempts"); + } + } + } + return salt; + } /** * Creates an instance of PBE Cipher using the specified CipherSpi @@ -163,8 +194,7 @@ final class PBES1Core { AlgorithmParameters getParameters() { AlgorithmParameters params; if (salt == null) { - salt = new byte[8]; - SunJCE.getRandom().nextBytes(salt); + salt = generateSalt(algo, SunJCE.getRandom()); } PBEParameterSpec pbeSpec = new PBEParameterSpec(salt, iCount); try { @@ -227,8 +257,7 @@ final class PBES1Core { if (params == null) { // create random salt and use default iteration count - salt = new byte[8]; - random.nextBytes(salt); + salt = generateSalt(algo, random); } else { if (!(params instanceof PBEParameterSpec)) { throw new InvalidAlgorithmParameterException @@ -240,6 +269,15 @@ final class PBES1Core { throw new InvalidAlgorithmParameterException ("Salt must be 8 bytes long"); } + // for DESede, reject weak salts for encryption + if (algo.equals("DESede") && + (opmode == Cipher.ENCRYPT_MODE || + opmode == Cipher.WRAP_MODE) && + isWeak(salt)) { + throw new InvalidAlgorithmParameterException( + "Weak salts cannot be used for encryption"); + } + iCount = ((PBEParameterSpec) params).getIterationCount(); if (iCount <= 0) { throw new InvalidAlgorithmParameterException diff --git a/src/java.base/share/classes/com/sun/crypto/provider/PKCS12PBECipherCore.java b/src/java.base/share/classes/com/sun/crypto/provider/PKCS12PBECipherCore.java index 7d2ba7f9831..517d7777287 100644 --- a/src/java.base/share/classes/com/sun/crypto/provider/PKCS12PBECipherCore.java +++ b/src/java.base/share/classes/com/sun/crypto/provider/PKCS12PBECipherCore.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -53,7 +53,7 @@ final class PKCS12PBECipherCore { private int iCount = 0; private static final int DEFAULT_SALT_LENGTH = 20; - private static final int DEFAULT_COUNT = 1024; + static final int DEFAULT_COUNT = 1024; static final int CIPHER_KEY = 1; static final int CIPHER_IV = 2; diff --git a/src/java.base/share/classes/java/lang/Class.java b/src/java.base/share/classes/java/lang/Class.java index f15291827d5..b08b9fe4d2c 100644 --- a/src/java.base/share/classes/java/lang/Class.java +++ b/src/java.base/share/classes/java/lang/Class.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1994, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1994, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -323,18 +323,19 @@ public final class Class implements java.io.Serializable, } while (component.isArray()); sb.append(component.getName()); } else { - // Class modifiers are a superset of interface modifiers - int modifiers = getModifiers() & Modifier.classModifiers(); - if (modifiers != 0) { - sb.append(Modifier.toString(modifiers)); - sb.append(' '); - } + int modifiers = getModifiers(); + Reflection.appendAccessControlModifiers(sb, modifiers); + if (Modifier.isAbstract(modifiers)) + sb.append("abstract "); // Intentionally printed for interfaces + if (Modifier.isStatic(modifiers)) + sb.append("static "); + if (Modifier.isFinal(modifiers)) + sb.append("final "); - // A class cannot be strictfp and sealed/non-sealed so - // it is sufficient to check for sealed-ness after all - // modifiers are printed. addSealingInfo(modifiers, sb); + // Note: class strictfp modifier is not recoverable from a class file + if (isAnnotation()) { sb.append('@'); } diff --git a/src/java.base/share/classes/java/lang/foreign/MemorySegment.java b/src/java.base/share/classes/java/lang/foreign/MemorySegment.java index 78098e39a17..70b15bb0cd7 100644 --- a/src/java.base/share/classes/java/lang/foreign/MemorySegment.java +++ b/src/java.base/share/classes/java/lang/foreign/MemorySegment.java @@ -1552,6 +1552,11 @@ public sealed interface MemorySegment permits AbstractMemorySegmentImpl { *

* The {@linkplain MemorySegment#maxByteAlignment() maximum byte alignment} for * the {@code NULL} segment is of 262. + * + * @apiNote Clients should avoid using {@code ==} to compare a segment with + * {@code MemorySegment.NULL}. A segment with address {@code 0L} may be + * {@linkplain #ofAddress(long) created independently} and may therefore + * have a different identity. */ MemorySegment NULL = MemorySegment.ofAddress(0L); diff --git a/src/java.base/share/classes/java/lang/reflect/AccessFlag.java b/src/java.base/share/classes/java/lang/reflect/AccessFlag.java index 4314c8c410d..46b9ce77fd7 100644 --- a/src/java.base/share/classes/java/lang/reflect/AccessFlag.java +++ b/src/java.base/share/classes/java/lang/reflect/AccessFlag.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -429,8 +429,6 @@ public enum AccessFlag { * * @see Class#accessFlags() * @see ClassModel#flags() - * @see Modifier#classModifiers() - * @see Modifier#interfaceModifiers() * @jvms 4.1 The {@code ClassFile} Structure */ CLASS(ACC_PUBLIC | ACC_FINAL | ACC_SUPER | @@ -450,7 +448,6 @@ public enum AccessFlag { * * @see Field#accessFlags() * @see FieldModel#flags() - * @see Modifier#fieldModifiers() * @jvms 4.5 Fields */ FIELD(ACC_PUBLIC | ACC_PRIVATE | ACC_PROTECTED | @@ -466,8 +463,6 @@ public enum AccessFlag { * * @see Executable#accessFlags() * @see MethodModel#flags() - * @see Modifier#methodModifiers() - * @see Modifier#constructorModifiers() * @jvms 4.6 Methods */ METHOD(ACC_PUBLIC | ACC_PRIVATE | ACC_PROTECTED | @@ -493,8 +488,6 @@ public enum AccessFlag { * * @see Class#accessFlags() * @see InnerClassInfo#flags() - * @see Modifier#classModifiers() - * @see Modifier#interfaceModifiers() * @jvms 4.7.6 The {@code InnerClasses} Attribute */ INNER_CLASS(ACC_PUBLIC | ACC_PRIVATE | ACC_PROTECTED | @@ -511,7 +504,6 @@ public enum AccessFlag { * * @see Parameter#accessFlags() * @see MethodParameterInfo#flags() - * @see Modifier#parameterModifiers() * @jvms 4.7.24 The {@code MethodParameters} Attribute */ METHOD_PARAMETER(ACC_FINAL | ACC_SYNTHETIC | ACC_MANDATED, diff --git a/src/java.base/share/classes/java/lang/reflect/Constructor.java b/src/java.base/share/classes/java/lang/reflect/Constructor.java index d072971307c..b81ef99ecff 100644 --- a/src/java.base/share/classes/java/lang/reflect/Constructor.java +++ b/src/java.base/share/classes/java/lang/reflect/Constructor.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -354,12 +354,15 @@ public final class Constructor extends Executable { * @jls 8.9.2 Enum Body Declarations */ public String toString() { - return sharedToString(Modifier.constructorModifiers(), - false, - parameterTypes, + return sharedToString(parameterTypes, exceptionTypes); } + @Override + void appendModifiers(StringBuilder sb) { + Reflection.appendAccessControlModifiers(sb, getModifiers()); + } + @Override void specificToStringHeader(StringBuilder sb) { sb.append(getDeclaringClass().getTypeName()); @@ -417,7 +420,7 @@ public final class Constructor extends Executable { */ @Override public String toGenericString() { - return sharedToGenericString(Modifier.constructorModifiers(), false); + return super.toGenericString(); } @Override diff --git a/src/java.base/share/classes/java/lang/reflect/Executable.java b/src/java.base/share/classes/java/lang/reflect/Executable.java index 4f32d33048d..b20658d5dd0 100644 --- a/src/java.base/share/classes/java/lang/reflect/Executable.java +++ b/src/java.base/share/classes/java/lang/reflect/Executable.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -93,31 +93,15 @@ public abstract sealed class Executable extends AccessibleObject getDeclaringClass()); } - void printModifiersIfNonzero(StringBuilder sb, int mask, boolean isDefault) { - int mod = getModifiers() & mask; + // Appends source modifiers of this declaration to a display string builder. + abstract void appendModifiers(StringBuilder sb); - if (mod != 0 && !isDefault) { - sb.append(Modifier.toString(mod)).append(' '); - } else { - int access_mod = mod & Modifier.ACCESS_MODIFIERS; - if (access_mod != 0) - sb.append(Modifier.toString(access_mod)).append(' '); - if (isDefault) - sb.append("default "); - mod = (mod & ~Modifier.ACCESS_MODIFIERS); - if (mod != 0) - sb.append(Modifier.toString(mod)).append(' '); - } - } - - String sharedToString(int modifierMask, - boolean isDefault, - Class[] parameterTypes, + String sharedToString(Class[] parameterTypes, Class[] exceptionTypes) { try { StringBuilder sb = new StringBuilder(); - printModifiersIfNonzero(sb, modifierMask, isDefault); + appendModifiers(sb); specificToStringHeader(sb); sb.append(Arrays.stream(parameterTypes) .map(Type::getTypeName) @@ -151,11 +135,11 @@ public abstract sealed class Executable extends AccessibleObject } } - String sharedToGenericString(int modifierMask, boolean isDefault) { + String sharedToGenericString() { try { StringBuilder sb = new StringBuilder(); - printModifiersIfNonzero(sb, modifierMask, isDefault); + appendModifiers(sb); TypeVariable[] typeparms = getTypeParameters(); if (typeparms.length > 0) { @@ -548,7 +532,9 @@ public abstract sealed class Executable extends AccessibleObject * {@return a string describing this {@code Executable}, including * any type parameters} */ - public abstract String toGenericString(); + public String toGenericString() { + return sharedToGenericString(); + } /** * {@return {@code true} if this executable was declared to take a diff --git a/src/java.base/share/classes/java/lang/reflect/Field.java b/src/java.base/share/classes/java/lang/reflect/Field.java index a4f0afa0199..d9bafaa0082 100644 --- a/src/java.base/share/classes/java/lang/reflect/Field.java +++ b/src/java.base/share/classes/java/lang/reflect/Field.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -367,11 +367,24 @@ class Field extends AccessibleObject implements Member { * @jls 8.3.1 Field Modifiers */ public String toString() { - int mod = getModifiers() & Modifier.fieldModifiers(); - return (((mod == 0) ? "" : (Modifier.toString(mod) + " ")) + return modifierPrefix() + getType().getTypeName() + " " + getDeclaringClass().getTypeName() + "." - + getName()); + + getName(); + } + + private String modifierPrefix() { + StringBuilder sb = new StringBuilder(); + Reflection.appendAccessControlModifiers(sb, modifiers); + if (Modifier.isStatic(modifiers)) + sb.append("static "); + if (Modifier.isFinal(modifiers)) + sb.append("final "); + if (Modifier.isTransient(modifiers)) + sb.append("transient "); + if (Modifier.isVolatile(modifiers)) + sb.append("volatile "); + return sb.toString(); } @Override @@ -400,12 +413,11 @@ class Field extends AccessibleObject implements Member { * @jls 8.3.1 Field Modifiers */ public String toGenericString() { - int mod = getModifiers() & Modifier.fieldModifiers(); Type fieldType = getGenericType(); - return (((mod == 0) ? "" : (Modifier.toString(mod) + " ")) + return modifierPrefix() + fieldType.getTypeName() + " " + getDeclaringClass().getTypeName() + "." - + getName()); + + getName(); } /** diff --git a/src/java.base/share/classes/java/lang/reflect/Method.java b/src/java.base/share/classes/java/lang/reflect/Method.java index 07616206075..b48e70e1717 100644 --- a/src/java.base/share/classes/java/lang/reflect/Method.java +++ b/src/java.base/share/classes/java/lang/reflect/Method.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -398,12 +398,30 @@ public final class Method extends Executable { * @jls 9.6.1 Annotation Interface Elements */ public String toString() { - return sharedToString(Modifier.methodModifiers(), - isDefault(), - parameterTypes, + return sharedToString(parameterTypes, exceptionTypes); } + @Override + void appendModifiers(StringBuilder sb) { + int mods = getModifiers(); + Reflection.appendAccessControlModifiers(sb, mods); + if (Modifier.isAbstract(mods)) + sb.append("abstract "); + if (isDefault()) + sb.append("default "); + if (Modifier.isStatic(mods)) + sb.append("static "); + if (Modifier.isFinal(mods)) + sb.append("final "); + if (Modifier.isSynchronized(mods)) + sb.append("synchronized "); + if (Modifier.isNative(mods)) + sb.append("native "); + if (Modifier.isStrict(mods)) + sb.append("strictfp "); + } + @Override void specificToStringHeader(StringBuilder sb) { sb.append(getReturnType().getTypeName()).append(' '); @@ -469,7 +487,7 @@ public final class Method extends Executable { */ @Override public String toGenericString() { - return sharedToGenericString(Modifier.methodModifiers(), isDefault()); + return super.toGenericString(); } @Override diff --git a/src/java.base/share/classes/java/lang/reflect/Modifier.java b/src/java.base/share/classes/java/lang/reflect/Modifier.java index 624f32b4e04..450e549d4b9 100644 --- a/src/java.base/share/classes/java/lang/reflect/Modifier.java +++ b/src/java.base/share/classes/java/lang/reflect/Modifier.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -28,30 +28,38 @@ package java.lang.reflect; import java.util.StringJoiner; /** - * The Modifier class provides {@code static} methods and - * constants to decode class and member access modifiers. The sets of - * modifiers are represented as integers with distinct bit positions - * representing different modifiers. The values for the constants - * representing the modifiers are taken from the tables in sections - * {@jvms 4.1}, {@jvms 4.4}, {@jvms 4.5}, and {@jvms 4.7} of - * The Java Virtual Machine Specification. + * Provides {@code static} methods and constants to decode {@linkplain + * AccessFlag classfile access and property flags} with corresponding + * {@linkplain java.compiler/javax.lang.model.element.Modifier Java + * language modifiers}. + *

+ * Modifier interpretation is context-sensitive: for example, the {@link + * #isSynchronized(int) isSynchronized} check is only meaningful for method + * access flags, representing the {@code synchronized} modifier on methods. + * A {@code true} return on a field access flags does not indicate that field + * has the {@code synchronized} modifier. * * @apiNote - * Not all modifiers that are syntactic Java language modifiers are - * represented in this class, only those modifiers that also - * have a corresponding JVM {@linkplain AccessFlag access flag} are - * included. In particular the {@code default} method modifier (JLS - * {@jls 9.4.3}) and the {@code sealed} and {@code non-sealed} class - * (JLS {@jls 8.1.1.2}) and interface (JLS {@jls 9.1.1.4}) modifiers - * are not represented in this class. + * The mappings from classfile access flags to Java language modifiers have + * {@linkplain java.lang.reflect##LanguageJvmModel diverged} during the + * evolution of the Java SE Platform. Many access flags and Java language + * modifiers are not represented in this class; the mappings represented in this + * class are not sufficient to reconstruct Java langugage modifiers from access + * flags, and vice versa. * + * @see AccessFlag + * @see java.compiler/javax.lang.model.element.Modifier + * @see java.lang.reflect##LanguageJvmModel + * Java programming language and JVM modeling in core reflection * @see Class#getModifiers() * @see Member#getModifiers() + * @see Parameter#getModifiers() * * @author Nakul Saraiya * @author Kenneth Russell * @since 1.1 */ +@SuppressWarnings("doclint:reference") // cross-module link public final class Modifier { /** * Do not call. @@ -224,33 +232,24 @@ public final class Modifier { * return a string of modifiers that are not valid modifiers of a * Java entity; in other words, no checking is done on the * possible validity of the combination of modifiers represented - * by the input. + * by the input. This method also omits all access flags without + * a corresponding source modifier. * - * Note that to perform such checking for a known kind of entity, - * such as a constructor or method, first AND the argument of - * {@code toString} with the appropriate mask from a method like - * {@link #constructorModifiers} or {@link #methodModifiers}. - * - * @apiNote - * To make a high-fidelity representation of the Java source - * modifiers of a class or member, source-level modifiers that do - * not have a constant in this class should be included - * and appear in an order consistent with the full recommended - * ordering for that kind of declaration as given in The - * Java Language Specification. For example, for a - * {@linkplain Method#toGenericString() method} the "{@link - * Method#isDefault() default}" modifier is ordered immediately - * before "{@code static}" (JLS {@jls 9.4}). For a {@linkplain - * Class#toGenericString() class object}, the "{@link - * Class#isSealed() sealed}" or {@code "non-sealed"} modifier is - * ordered immediately after "{@code final}" for a class (JLS - * {@jls 8.1.1}) and immediately after "{@code static}" for an - * interface (JLS {@jls 9.1.1}). + * @deprecated + * Modifier interpretation is context-sensitive; this API may report an + * incomplete or incorrect list of Java language modifiers. The mappings + * from {@code class} file access flags to Java language modifiers have + * {@linkplain java.lang.reflect##LanguageJvmModel diverged} during the + * evolution of the Java SE Platform. + *

+ * Use {@link AccessFlag} to examine access flags; {@code toGenericString} + * methods on reflective objects print Java language modifiers. * * @param mod a set of modifiers * @return a string representation of the set of modifiers * represented by {@code mod} */ + @Deprecated(since = "27") public static String toString(int mod) { StringJoiner sj = new StringJoiner(" "); @@ -439,20 +438,24 @@ public final class Modifier { private static final int PARAMETER_MODIFIERS = Modifier.FINAL; - static final int ACCESS_MODIFIERS = - Modifier.PUBLIC | Modifier.PROTECTED | Modifier.PRIVATE; - /** * Return an {@code int} value OR-ing together the source language * modifiers that can be applied to a class. * @return an {@code int} value OR-ing together the source language * modifiers that can be applied to a class. * + * @deprecated + * This method was originally created to support the now-deprecated + * {@link #toString(int) Modifier::toString(int)} method. + * Use {@link AccessFlag.Location} to inspect structure-specific + * access modifier properties. + * * @see AccessFlag.Location#CLASS * @see AccessFlag.Location#INNER_CLASS * @jls 8.1.1 Class Modifiers * @since 1.7 */ + @Deprecated(since = "27") public static int classModifiers() { return CLASS_MODIFIERS; } @@ -463,11 +466,18 @@ public final class Modifier { * @return an {@code int} value OR-ing together the source language * modifiers that can be applied to an interface. * + * @deprecated + * This method was originally created to support the now-deprecated + * {@link #toString(int) Modifier::toString(int)} method. + * Use {@link AccessFlag.Location} to inspect structure-specific + * access modifier properties. + * * @see AccessFlag.Location#CLASS * @see AccessFlag.Location#INNER_CLASS * @jls 9.1.1 Interface Modifiers * @since 1.7 */ + @Deprecated(since = "27") public static int interfaceModifiers() { return INTERFACE_MODIFIERS; } @@ -478,10 +488,17 @@ public final class Modifier { * @return an {@code int} value OR-ing together the source language * modifiers that can be applied to a constructor. * + * @deprecated + * This method was originally created to support the now-deprecated + * {@link #toString(int) Modifier::toString(int)} method. + * Use {@link AccessFlag.Location} to inspect structure-specific + * access modifier properties. + * * @see AccessFlag.Location#METHOD * @jls 8.8.3 Constructor Modifiers * @since 1.7 */ + @Deprecated(since = "27") public static int constructorModifiers() { return CONSTRUCTOR_MODIFIERS; } @@ -492,10 +509,17 @@ public final class Modifier { * @return an {@code int} value OR-ing together the source language * modifiers that can be applied to a method. * + * @deprecated + * This method was originally created to support the now-deprecated + * {@link #toString(int) Modifier::toString(int)} method. + * Use {@link AccessFlag.Location} to inspect structure-specific + * access modifier properties. + * * @see AccessFlag.Location#METHOD * @jls 8.4.3 Method Modifiers * @since 1.7 */ + @Deprecated(since = "27") public static int methodModifiers() { return METHOD_MODIFIERS; } @@ -506,10 +530,17 @@ public final class Modifier { * @return an {@code int} value OR-ing together the source language * modifiers that can be applied to a field. * + * @deprecated + * This method was originally created to support the now-deprecated + * {@link #toString(int) Modifier::toString(int)} method. + * Use {@link AccessFlag.Location} to inspect structure-specific + * access modifier properties. + * * @see AccessFlag.Location#FIELD * @jls 8.3.1 Field Modifiers * @since 1.7 */ + @Deprecated(since = "27") public static int fieldModifiers() { return FIELD_MODIFIERS; } @@ -520,10 +551,17 @@ public final class Modifier { * @return an {@code int} value OR-ing together the source language * modifiers that can be applied to a parameter. * + * @deprecated + * This method was originally created to support the now-deprecated + * {@link #toString(int) Modifier::toString(int)} method. + * Use {@link AccessFlag.Location} to inspect structure-specific + * access modifier properties. + * * @see AccessFlag.Location#METHOD_PARAMETER * @jls 8.4.1 Formal Parameters * @since 1.8 */ + @Deprecated(since = "27") public static int parameterModifiers() { return PARAMETER_MODIFIERS; } diff --git a/src/java.base/share/classes/java/lang/reflect/Parameter.java b/src/java.base/share/classes/java/lang/reflect/Parameter.java index 8ecf8060615..cc06ae02f84 100644 --- a/src/java.base/share/classes/java/lang/reflect/Parameter.java +++ b/src/java.base/share/classes/java/lang/reflect/Parameter.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -126,10 +126,9 @@ public final class Parameter implements AnnotatedElement { final Type type = getParameterizedType(); final String typename = type.getTypeName(); - sb.append(Modifier.toString(getModifiers() & Modifier.parameterModifiers() )); - - if(0 != modifiers) - sb.append(' '); + if (Modifier.isFinal(modifiers)) { + sb.append("final "); + } if(isVarArgs()) sb.append(typename.replaceFirst("\\[\\]$", "...")); diff --git a/src/java.base/share/classes/java/net/URL.java b/src/java.base/share/classes/java/net/URL.java index 1e86f41fd3f..2f2c80423ce 100644 --- a/src/java.base/share/classes/java/net/URL.java +++ b/src/java.base/share/classes/java/net/URL.java @@ -53,16 +53,12 @@ import static jdk.internal.util.Exceptions.formatMsg; * Wide Web. A resource can be something as simple as a file or a * directory, or it can be a reference to a more complicated object, * such as a query to a database or to a search engine. More - * information on the types of URLs and their formats can be found at: - * - * Types of URL *

* In general, a URL can be broken into several parts. Consider the * following example: - *

- *     http://www.example.com/docs/resource1.html
- * 
+ * {@snippet lang="text" : + * http://www.example.com/docs/resource1.html + * } *

* The URL above indicates that the protocol to use is * {@code http} (HyperText Transfer Protocol) and that the @@ -80,9 +76,9 @@ import static jdk.internal.util.Exceptions.formatMsg; * the protocol is used instead. For example, the default port for * {@code http} is {@code 80}. An alternative port could be * specified as: - *

- *     http://www.example.com:1080/docs/resource1.html
- * 
+ * {@snippet lang="text" : + * http://www.example.com:1080/docs/resource1.html + * } *

* The syntax of {@code URL} is defined by RFC 2396: Uniform @@ -95,9 +91,9 @@ import static jdk.internal.util.Exceptions.formatMsg; * A URL may have appended to it a "fragment", also known * as a "ref" or a "reference". The fragment is indicated by the sharp * sign character "#" followed by more characters. For example, - *

- *     http://www.example.com/index.html#chapter1
- * 
+ * {@snippet lang="text" : + * http://www.example.com/index.html#chapter1 + * } *

* This fragment is not technically part of the URL. Rather, it * indicates that after the specified resource is retrieved, the @@ -109,17 +105,17 @@ import static jdk.internal.util.Exceptions.formatMsg; * which contains only enough information to reach the resource * relative to another URL. Relative URLs are frequently used within * HTML pages. For example, if the contents of the URL: - *

- *     http://www.example.com/index.html
- * 
+ * {@snippet lang="text" : + * http://www.example.com/index.html + * } * contained within it the relative URL: - *
- *     FAQ.html
- * 
+ * {@snippet lang="text" : + * FAQ.html + * } * it would be a shorthand for: - *
- *     http://www.example.com/FAQ.html
- * 
+ * {@snippet lang="text" : + * http://www.example.com/FAQ.html + * } *

* The relative URL need not specify all the components of a URL. If * the protocol, host name, or port number is missing, the value is @@ -147,13 +143,13 @@ import static jdk.internal.util.Exceptions.formatMsg; * syntax specification. *

* The URL class does not itself encode or decode any URL components - * according to the escaping mechanism defined in RFC2396. It is the + * according to the escaping mechanism defined in RFC 2396. It is the * responsibility of the caller to encode any fields, which need to be * escaped prior to calling URL, and also to decode any escaped fields, * that are returned from URL. Furthermore, because URL has no knowledge * of URL escaping, it does not recognise equivalence between the encoded - * or decoded form of the same URL. For example, the two URLs:
- *

    http://foo.com/hello world/ and http://foo.com/hello%20world
+ * or decoded form of the same URL. For example, the two URLs: + * {@code http://foo.com/hello%20world} and {@code http://foo.com/hello world/} * would be considered not equal to each other. *

* Note, the {@link java.net.URI} class does perform escaping of its @@ -164,7 +160,7 @@ import static jdk.internal.util.Exceptions.formatMsg; *

* The {@link URLEncoder} and {@link URLDecoder} classes can also be * used, but only for HTML form encoding, which is not the same - * as the encoding scheme defined in RFC2396. + * as the encoding scheme defined in RFC 2396. * * @apiNote * @@ -190,7 +186,7 @@ import static jdk.internal.util.Exceptions.formatMsg; * be abused to construct misleading URLs or URIs. Applications * that deal with URLs or URIs should take into account * the recommendations advised in RFC3986, + * href="https://tools.ietf.org/html/rfc3986#section-7">RFC 3986, * Section 7, Security Considerations. *

* All {@code URL} constructors may throw {@link MalformedURLException}. @@ -572,10 +568,10 @@ public final class URL implements java.io.Serializable { * * The new URL is created from the given context URL and the spec * argument as described in - * RFC2396 "Uniform Resource Identifiers : Generic Syntax" : - *

-     *          <scheme>://<authority><path>?<query>#<fragment>
-     * 
+ * RFC 2396 "Uniform Resource Identifiers : Generic Syntax" : + * {@snippet lang="text" : + * ://?# + * } * The reference is parsed into the scheme, authority, path, query and * fragment parts. If the path component is empty and the scheme, * authority, and query components are undefined, then the new URL is a @@ -598,11 +594,11 @@ public final class URL implements java.io.Serializable { * path is treated as absolute and the spec path replaces the context path. *

* Otherwise, the path is treated as a relative path and is appended to the - * context path, as described in RFC2396. Also, in this case, + * context path, as described in RFC 2396. Also, in this case, * the path is canonicalized through the removal of directory * changes made by occurrences of ".." and ".". *

- * For a more detailed description of URL parsing, refer to RFC2396. + * For a more detailed description of URL parsing, refer to RFC 2396. * * @implSpec Parsing the URL includes calling the {@link * URLStreamHandler#parseURL(URL, String, int, int) parseURL} method on the @@ -1027,7 +1023,7 @@ public final class URL implements java.io.Serializable { /** * Gets the host name of this {@code URL}, if applicable. - * The format of the host conforms to RFC 2732, i.e. for a + * The format of the host conforms to RFC 2732, i.e. for a * literal IPv6 address, this method will return the IPv6 address * enclosed in square brackets ({@code '['} and {@code ']'}). * @@ -1157,12 +1153,12 @@ public final class URL implements java.io.Serializable { /** * Returns a {@link java.net.URI} equivalent to this URL. * This method functions in the same way as {@code new URI (this.toString())}. - *

Note, any URL instance that complies with RFC 2396 can be converted + *

Note, any URL instance that complies with RFC 2396 can be converted * to a URI. However, some URLs that are not strictly in compliance * can not be converted to a URI. * * @throws URISyntaxException if this URL is not formatted strictly according to - * RFC2396 and cannot be converted to a URI. + * RFC 2396 and cannot be converted to a URI. * * @return a URI instance equivalent to this URL. * @since 1.5 @@ -1251,9 +1247,9 @@ public final class URL implements java.io.Serializable { * Opens a connection to this {@code URL} and returns an * {@code InputStream} for reading from that connection. This * method is a shorthand for: - *

-     *     openConnection().getInputStream()
-     * 
+ * {@snippet lang="java" : + * openConnection().getInputStream() + * } * * @return an input stream for reading from the URL connection. * @throws IOException if an I/O exception occurs. @@ -1266,9 +1262,9 @@ public final class URL implements java.io.Serializable { /** * Gets the contents of this URL. This method is a shorthand for: - *
-     *     openConnection().getContent()
-     * 
+ * {@snippet lang="java" : + * openConnection().getContent() + * } * * @return the contents of this URL. * @throws IOException if an I/O exception occurs. @@ -1280,9 +1276,9 @@ public final class URL implements java.io.Serializable { /** * Gets the contents of this URL. This method is a shorthand for: - *
-     *     openConnection().getContent(classes)
-     * 
+ * {@snippet lang="java" : + * openConnection().getContent(classes) + * } * * @param classes an array of Java types * @return the content object of this URL that is the first match of diff --git a/src/java.base/share/classes/jdk/internal/foreign/SegmentFactories.java b/src/java.base/share/classes/jdk/internal/foreign/SegmentFactories.java index 728ee235547..a94800711cf 100644 --- a/src/java.base/share/classes/jdk/internal/foreign/SegmentFactories.java +++ b/src/java.base/share/classes/jdk/internal/foreign/SegmentFactories.java @@ -190,15 +190,16 @@ public class SegmentFactories { if (VM.isDirectMemoryPageAligned()) { byteAlignment = Math.max(byteAlignment, AbstractMemorySegmentImpl.NIO_ACCESS.pageSize()); } + // Always allocate at least some memory so that zero-length segments have distinct + // non-zero addresses. + byteSize = Math.max(1, byteSize); + // Align the allocation size up to a multiple of 8 so we can init the memory with longs long alignedSize = init ? Utils.alignUp(byteSize, Long.BYTES) : byteSize; // Check for wrap around if (alignedSize < 0) { throw new OutOfMemoryError(); } - // Always allocate at least some memory so that zero-length segments have distinct - // non-zero addresses. - alignedSize = Math.max(1, alignedSize); long allocationSize; long allocationBase; @@ -226,12 +227,13 @@ public class SegmentFactories { if (init) { initNativeMemory(result, alignedSize); } + final long cleanupByteSize = byteSize; sessionImpl.addOrCleanupIfFail(new MemorySessionImpl.ResourceList.ResourceCleanup() { @Override public void cleanup() { UNSAFE.freeMemory(allocationBase); if (shouldReserve) { - AbstractMemorySegmentImpl.NIO_ACCESS.unreserveMemory(allocationSize, byteSize); + AbstractMemorySegmentImpl.NIO_ACCESS.unreserveMemory(allocationSize, cleanupByteSize); } } }); diff --git a/src/java.base/share/classes/jdk/internal/foreign/abi/ppc64/CallArranger.java b/src/java.base/share/classes/jdk/internal/foreign/abi/ppc64/CallArranger.java index 0fd90ef6f73..c9994ec2930 100644 --- a/src/java.base/share/classes/jdk/internal/foreign/abi/ppc64/CallArranger.java +++ b/src/java.base/share/classes/jdk/internal/foreign/abi/ppc64/CallArranger.java @@ -245,7 +245,12 @@ public abstract class CallArranger { // Regular struct, no HFA. VMStorage[] structAlloc(MemoryLayout layout) { // Allocate enough gp slots (regs and stack) such that the struct fits in them. - int numChunks = (int) Utils.alignUp(layout.byteSize(), MAX_COPY_SIZE) / MAX_COPY_SIZE; + final int numChunks; + try { + numChunks = Math.toIntExact(Utils.alignUp(layout.byteSize(), MAX_COPY_SIZE) / MAX_COPY_SIZE); + } catch (ArithmeticException ae) { + throw new IllegalArgumentException("Layout too large: " + layout, ae); + } VMStorage[] result = new VMStorage[numChunks]; for (int i = 0; i < numChunks; i++) { result[i] = nextStorage(StorageType.INTEGER, false); diff --git a/src/java.base/share/classes/jdk/internal/reflect/Reflection.java b/src/java.base/share/classes/jdk/internal/reflect/Reflection.java index d39fd9231da..d674c8e13c1 100644 --- a/src/java.base/share/classes/jdk/internal/reflect/Reflection.java +++ b/src/java.base/share/classes/jdk/internal/reflect/Reflection.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -34,7 +34,6 @@ import java.util.Set; import jdk.internal.access.JavaLangAccess; import jdk.internal.access.SharedSecrets; import jdk.internal.misc.VM; -import jdk.internal.module.ModuleBootstrap; import jdk.internal.vm.annotation.ForceInline; import jdk.internal.vm.annotation.IntrinsicCandidate; @@ -429,13 +428,41 @@ public class Reflection { } private static String msgSuffix(int modifiers) { - boolean packageAccess = - ((Modifier.PRIVATE | - Modifier.PROTECTED | - Modifier.PUBLIC) & modifiers) == 0; - return packageAccess ? - " with package access" : - " with modifiers \"" + Modifier.toString(modifiers) + "\""; + return " with " + accessControlStatus(modifiers) + " access"; + } + + /** + * Returns a display string for the access control modifier status. + * In particular, this prints "package-private" status. + * Reports upon an illegal modifier input. + * + * @param modifiers modifier input + * @return the display string + */ + public static String accessControlStatus(int modifiers) { + modifiers &= (Modifier.PRIVATE | Modifier.PROTECTED | Modifier.PUBLIC); + return switch (modifiers) { + case 0 -> "package-private"; + case Modifier.PUBLIC -> "public"; + case Modifier.PRIVATE -> "private"; + case Modifier.PROTECTED -> "protected"; + default -> "(illegal modifiers 0x%x)".formatted(modifiers); + }; + } + + /** + * Adds the public/protected/private access control modifiers to a display buffer. + * + * @param sb the buffer + * @param modifiers the modifiers + */ + public static void appendAccessControlModifiers(StringBuilder sb, int modifiers) { + if (Modifier.isPublic(modifiers)) + sb.append("public "); + if (Modifier.isProtected(modifiers)) + sb.append("protected "); + if (Modifier.isPrivate(modifiers)) + sb.append("private "); } /** diff --git a/src/java.base/share/classes/sun/invoke/util/VerifyAccess.java b/src/java.base/share/classes/sun/invoke/util/VerifyAccess.java index ec768704f95..d9b27735bd5 100644 --- a/src/java.base/share/classes/sun/invoke/util/VerifyAccess.java +++ b/src/java.base/share/classes/sun/invoke/util/VerifyAccess.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -143,7 +143,7 @@ public class VerifyAccess { assert (canAccess && refc == defc) || !canAccess; return canAccess; default: - throw new IllegalArgumentException("bad modifiers: "+Modifier.toString(mods)); + throw new IllegalArgumentException("bad modifiers: %04x".formatted(mods)); } } diff --git a/src/java.base/share/classes/sun/net/www/http/HttpClient.java b/src/java.base/share/classes/sun/net/www/http/HttpClient.java index 82ab4c199a5..ffab60e714e 100644 --- a/src/java.base/share/classes/sun/net/www/http/HttpClient.java +++ b/src/java.base/share/classes/sun/net/www/http/HttpClient.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1994, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1994, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -438,8 +438,17 @@ public class HttpClient extends NetworkClient { } } + /** + * {@return {@code true}, if the connection to the server is still + * established and there is no stale data to be read; {@code false}, + * otherwise} + *

+ * A {@code true} return value indicates that the connection is reusable for + * an HTTP request. A {@code false} return value indicates that the + * connection is either lost or dirty, and it should be closed. + */ protected boolean available() { - boolean available = true; + boolean available = false; int old = -1; lock(); @@ -447,24 +456,24 @@ public class HttpClient extends NetworkClient { try { old = serverSocket.getSoTimeout(); serverSocket.setSoTimeout(1); - BufferedInputStream tmpbuf = - new BufferedInputStream(serverSocket.getInputStream()); - int r = tmpbuf.read(); + int r = serverSocket.getInputStream().read(); if (r == -1) { logFinest("HttpClient.available(): " + "read returned -1: not available"); - available = false; } } catch (SocketTimeoutException e) { logFinest("HttpClient.available(): " + "SocketTimeout: its available"); + available = true; } finally { if (old != -1) serverSocket.setSoTimeout(old); } } catch (IOException e) { - logFinest("HttpClient.available(): " + - "SocketException: not available"); + logFinest("HttpClient.available(): IOException: not available"); + // `SocketTimeoutException` might have set the return value to + // `true`, but consequently `serverSocket::setSoTimeout` might have + // failed. Hence, reset the return value, always. available = false; } finally { unlock(); diff --git a/src/java.base/share/classes/sun/net/www/protocol/https/HttpsClient.java b/src/java.base/share/classes/sun/net/www/protocol/https/HttpsClient.java index f5804cd83bd..8b63d52a989 100644 --- a/src/java.base/share/classes/sun/net/www/protocol/https/HttpsClient.java +++ b/src/java.base/share/classes/sun/net/www/protocol/https/HttpsClient.java @@ -23,7 +23,6 @@ * questions. */ - package sun.net.www.protocol.https; import java.io.IOException; @@ -36,7 +35,6 @@ import java.net.URL; import java.net.UnknownHostException; import java.net.InetSocketAddress; import java.net.Proxy; -import java.security.Principal; import java.security.cert.*; import java.util.ArrayList; import java.util.List; @@ -242,8 +240,11 @@ final class HttpsClient extends HttpClient if (ret != null && httpuc != null && httpuc.streaming() && "POST".equals(httpuc.getRequestMethod())) { - if (!ret.available()) + if (!ret.available()) { + ret.inCache = false; + ret.closeServer(); ret = null; + } } if (ret != null) { diff --git a/src/java.base/share/classes/sun/security/provider/X509Factory.java b/src/java.base/share/classes/sun/security/provider/X509Factory.java index 4be83d629bb..154d1428414 100644 --- a/src/java.base/share/classes/sun/security/provider/X509Factory.java +++ b/src/java.base/share/classes/sun/security/provider/X509Factory.java @@ -66,6 +66,7 @@ public class X509Factory extends CertificateFactorySpi { public static final String END_CERT = "-----END CERTIFICATE-----"; private static final int ENC_MAX_LENGTH = 4096 * 1024; // 4 MB MAX + public static final int BER_ITERATION_COUNT = 128; // Limit nested depth private static final Cache certCache = Cache.newSoftMemoryCache(750); @@ -570,7 +571,7 @@ public class X509Factory extends CertificateFactorySpi { if (c == DerValue.tag_Sequence) { ByteArrayOutputStream bout = new ByteArrayOutputStream(2048); bout.write(c); - readBERInternal(is, bout, c); + readBERInternal(is, bout, c, BER_ITERATION_COUNT); return bout.toByteArray(); } else { try { @@ -594,12 +595,16 @@ public class X509Factory extends CertificateFactorySpi { * @param is Read from this InputStream * @param bout Write into this OutputStream * @param tag Tag already read (-1 mean not read) + * @param depth nesting depth limit * @return The current tag, used to check EOC in indefinite-length BER * @throws IOException Any parsing error */ private static int readBERInternal(InputStream is, - ByteArrayOutputStream bout, int tag) throws IOException { + ByteArrayOutputStream bout, int tag, int depth) throws IOException { + if (depth-- == 0) { + throw new IOException("Nesting sequence depth limit reached."); + } if (tag == -1) { // Not read before the call, read now tag = is.read(); if (tag == -1) { @@ -625,7 +630,7 @@ public class X509Factory extends CertificateFactorySpi { "Non constructed encoding must have definite length"); } while (true) { - int subTag = readBERInternal(is, bout, -1); + int subTag = readBERInternal(is, bout, -1, depth); if (subTag == 0) { // EOC, end of indefinite-length section break; } 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 31c0f4ecb9c..ed0fd0f5576 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, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -43,9 +43,7 @@ import static sun.security.x509.PKIXExtensions.IssuingDistributionPoint_Id; /** * Class to obtain CRLs via the CRLDistributionPoints extension. - * Note that the functionality of this class must be explicitly enabled - * via a system property, see the USE_CRLDP variable below. - * + *

* This class uses the URICertStore class to fetch CRLs. The URICertStore * class also implements CRL caching: see the class description for more * information. diff --git a/src/java.base/share/classes/sun/security/provider/certpath/RevocationChecker.java b/src/java.base/share/classes/sun/security/provider/certpath/RevocationChecker.java index 297727310d4..7751f6a32bf 100644 --- a/src/java.base/share/classes/sun/security/provider/certpath/RevocationChecker.java +++ b/src/java.base/share/classes/sun/security/provider/certpath/RevocationChecker.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -1007,13 +1007,17 @@ class RevocationChecker extends PKIXRevocationChecker { // any way to convey them back to the application. // That's the default, so no need to write code. builderParams.setDate(params.date()); - builderParams.setCertPathCheckers(params.certPathCheckers()); builderParams.setSigProvider(params.sigProvider()); // Skip revocation during this build to detect circular // references. But check revocation afterwards, using the // key (or any other that works). builderParams.setRevocationEnabled(false); + // Remove itself from params to avoid circular reference. + builderParams.setCertPathCheckers(params.certPathCheckers() + .stream() + .filter(checker -> checker != this) + .toList()); // check for AuthorityInformationAccess extension if (Builder.USE_AIA) { diff --git a/src/java.base/share/classes/sun/security/x509/DNSName.java b/src/java.base/share/classes/sun/security/x509/DNSName.java index 597652022ce..ce903a3d16c 100644 --- a/src/java.base/share/classes/sun/security/x509/DNSName.java +++ b/src/java.base/share/classes/sun/security/x509/DNSName.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -52,8 +52,8 @@ import sun.security.util.*; public class DNSName implements GeneralNameInterface { private final String name; - private static final String alphaDigits = - "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"; + private static final String DNS_ALLOWED = + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-"; /** * Create the DNSName object from the passed encoded Der value. @@ -73,52 +73,64 @@ public class DNSName implements GeneralNameInterface { * @throws IOException if the name is not a valid DNSName */ public DNSName(String name, boolean allowWildcard) throws IOException { - if (name == null || name.isEmpty()) + + // Check the full name. + if (name == null || name.isEmpty()) { throw new IOException("DNSName must not be null or empty"); - if (name.contains(" ")) - throw new IOException("DNSName with blank components is not permitted"); - if (name.startsWith(".") || name.endsWith(".")) + } + + if (name.contains(" ")) { + throw new IOException( + "DNSName with blank labels is not permitted"); + } + + if (name.startsWith(".") || name.endsWith(".")) { throw new IOException("DNSName may not begin or end with a ."); - /* - * Name will consist of label components separated by "." - * startIndex is the index of the first character of a component - * endIndex is the index of the last character of a component plus 1 - */ - for (int endIndex,startIndex = 0; startIndex < name.length(); startIndex = endIndex+1) { - endIndex = name.indexOf('.', startIndex); - if (endIndex < 0) { - endIndex = name.length(); - } - if (endIndex - startIndex < 1) - throw new IOException("DNSName with empty components are not permitted"); + } - if (allowWildcard) { - // RFC 1123: DNSName components must begin with a letter or digit - // or RFC 4592: the first component of a DNSName can have only a wildcard - // character * (asterisk), i.e. *.example.com. Asterisks at other components - // will not be allowed as a wildcard. - if (alphaDigits.indexOf(name.charAt(startIndex)) < 0) { - // Checking to make sure the wildcard only appears in the first component, - // and it has to be at least 3-char long with the form of *.[alphaDigit] - if ((name.length() < 3) || (name.indexOf('*') != 0) || - (name.charAt(startIndex+1) != '.') || - (alphaDigits.indexOf(name.charAt(startIndex+2)) < 0)) - throw new IOException("DNSName components must begin with a letter, digit, " - + "or the first component can have only a wildcard character *"); + // RFC 1123 Section 2.1 and RFC 2181 Section 11 + if (name.length() > 253) { + throw new IOException( + "DNSName can't be longer than 253 characters"); + } + + // Check the labels. + String[] labels = name.split("\\."); + + for (int i = 0; i < labels.length; i++) { + String label = labels[i]; + + if (label.isEmpty()) { + throw new IOException( + "DNSName with empty labels is not permitted"); + } + + // RFC 1123 Section 2.1 + if (label.length() > 63) { + throw new IOException( + "DNSName label can't be longer than 63 characters"); + } + + // RFC 1035 Section 2.3.1 + if (label.startsWith("-") || label.endsWith("-")) { + throw new IOException( + "DNSName label may not begin or end with a hyphen"); + } + + // RFC 9525 Section 6.3 + if (allowWildcard && label.equals("*") && i == 0 + && labels.length > 1) { + continue; + } + + for (char c : label.toCharArray()) { + if (DNS_ALLOWED.indexOf(c) < 0) { + throw new IOException("DNSName labels must consist of " + + "letters, digits, and hyphens"); } - } else { - // RFC 1123: DNSName components must begin with a letter or digit - if (alphaDigits.indexOf(name.charAt(startIndex)) < 0) - throw new IOException("DNSName components must begin with a letter or digit"); - } - - //nonStartIndex: index for characters in the component beyond the first one - for (int nonStartIndex=startIndex+1; nonStartIndex < endIndex; nonStartIndex++) { - char x = name.charAt(nonStartIndex); - if ((alphaDigits).indexOf(x) < 0 && x != '-') - throw new IOException("DNSName components must consist of letters, digits, and hyphens"); } } + this.name = name; } diff --git a/src/java.base/share/man/java.md b/src/java.base/share/man/java.md index 18d64b3a4c2..6c079c268b1 100644 --- a/src/java.base/share/man/java.md +++ b/src/java.base/share/man/java.md @@ -2938,12 +2938,6 @@ they're used. (`-XX:+UseParallelGC` or `-XX:+UseG1GC`). Other collectors employing multiple threads always perform reference processing in parallel. -[`-XX:+AggressiveHeap`]{#-XX__AggressiveHeap} -: Enables Java heap optimization. This sets various parameters to be - optimal for long-running jobs with intensive memory allocation, based on - the configuration of the computer (RAM and CPU). By default, the option - is disabled and the heap sizes are configured less aggressively. - ## Obsolete Java Options These `java` options are still accepted but ignored, and a warning is issued @@ -2976,6 +2970,12 @@ when they're used. -XX:{+|-}UseJVMCICompiler ``` +[`-XX:+AggressiveHeap`]{#-XX__AggressiveHeap} +: Enabled Java heap optimization. This set various parameters to be + optimal for long-running jobs with intensive memory allocation, based on + the configuration of the computer (RAM and CPU). By default, the option + was disabled and the heap sizes configured less aggressively. + ## Removed Java Options No documented java options have been removed in JDK @@VERSION_SPECIFICATION@@. diff --git a/src/java.base/share/native/libjli/java.c b/src/java.base/share/native/libjli/java.c index 4621ab588d1..e19ba280fa7 100644 --- a/src/java.base/share/native/libjli/java.c +++ b/src/java.base/share/native/libjli/java.c @@ -1058,7 +1058,7 @@ static void SetMainModule(const char *s) { static const char format[] = "-Djdk.module.main=%s"; - char* slash = JLI_StrChr(s, '/'); + const char* slash = JLI_StrChr(s, '/'); size_t s_len, def_len; char *def; diff --git a/src/java.base/share/native/libjli/jli_util.c b/src/java.base/share/native/libjli/jli_util.c index 3b24a784491..51c2d8b8573 100644 --- a/src/java.base/share/native/libjli/jli_util.c +++ b/src/java.base/share/native/libjli/jli_util.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -87,7 +87,7 @@ JLI_MemFree(void *ptr) jboolean JLI_HasSuffix(const char *s1, const char *s2) { - char *p = JLI_StrRChr(s1, '.'); + const char* p = JLI_StrRChr(s1, '.'); if (p == NULL || *p == '\0') { return JNI_FALSE; } diff --git a/src/java.base/share/native/libverify/check_code.c b/src/java.base/share/native/libverify/check_code.c index 4830fedb97b..e6aebead212 100644 --- a/src/java.base/share/native/libverify/check_code.c +++ b/src/java.base/share/native/libverify/check_code.c @@ -3831,7 +3831,7 @@ signature_to_fieldtype(context_type *context, case JVM_SIGNATURE_CLASS: { char buffer_space[256]; char *buffer = buffer_space; - char *finish = strchr(p, JVM_SIGNATURE_ENDCLASS); + const char* finish = strchr(p, JVM_SIGNATURE_ENDCLASS); int length; if (finish == NULL) { /* Signature must have ';' after the class name. diff --git a/src/java.base/share/native/libzip/zip_util.c b/src/java.base/share/native/libzip/zip_util.c index 3ad148b0be5..96d3050f527 100644 --- a/src/java.base/share/native/libzip/zip_util.c +++ b/src/java.base/share/native/libzip/zip_util.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1995, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1995, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -568,7 +568,7 @@ static jlong readCEN(jzfile *zip, jint knownTotal) { /* Following are unsigned 32-bit */ - jlong endpos, end64pos, cenpos, cenlen, cenoff; + jlong endpos, end64pos, cenpos, cenlen, cenoff, total64; /* Following are unsigned 16-bit */ jint total, tablelen, i, j; unsigned char *cenbuf = NULL; @@ -604,7 +604,16 @@ readCEN(jzfile *zip, jint knownTotal) if ((end64pos = findEND64(zip, end64buf, endpos)) != -1) { cenlen = ZIP64_ENDSIZ(end64buf); cenoff = ZIP64_ENDOFF(end64buf); - total = (jint)ZIP64_ENDTOT(end64buf); + total64 = ZIP64_ENDTOT(end64buf); + /* ZIP64 size, offset and total-count fields are unsigned 64-bit + * values. Sizes and offsets that do not fit in signed jlong + * (i.e., >= 2^63), or total values that do not fit in jint, are + * not supported and indicate a corrupt or invalid zip file. + */ + if (cenlen < 0 || cenoff < 0 || total64 < 0 || total64 > INT_MAX) { + ZIP_FORMAT_ERROR("Zip64 END values exceed supported size"); + } + total = (jint)total64; endpos = end64pos; #ifdef USE_MMAP endhdrlen = ZIP64_ENDHDR; @@ -1137,20 +1146,8 @@ ZIP_FreeEntry(jzfile *jz, jzentry *ze) } } -/* - * Returns the zip entry corresponding to the specified name, or - * NULL if not found. - */ -jzentry * -ZIP_GetEntry(jzfile *zip, char *name, jint ulen) -{ - if (ulen == 0) { - return ZIP_GetEntry2(zip, name, (jint)strlen(name), JNI_FALSE); - } - return ZIP_GetEntry2(zip, name, ulen, JNI_TRUE); -} - -jboolean equals(char* name1, int len1, char* name2, int len2) { +static jboolean +equals(const char* name1, int len1, const char* name2, int len2) { if (len1 != len2) { return JNI_FALSE; } @@ -1162,16 +1159,12 @@ jboolean equals(char* name1, int len1, char* name2, int len2) { return JNI_TRUE; } -/* - * Returns the zip entry corresponding to the specified name, or - * NULL if not found. - * This method supports embedded null character in "name", use ulen - * for the length of "name". - */ jzentry * -ZIP_GetEntry2(jzfile *zip, char *name, jint ulen, jboolean addSlash) +ZIP_GetEntry(jzfile *zip, const char *name) { - unsigned int hsh = hashN(name, ulen); + // length of the entry name being searched for + const jint name_len = (jint) strlen(name); + const unsigned int hsh = hashN(name, name_len); jint idx; jzentry *ze = 0; @@ -1182,79 +1175,47 @@ ZIP_GetEntry2(jzfile *zip, char *name, jint ulen, jboolean addSlash) idx = zip->table[hsh % zip->tablelen]; - /* - * This while loop is an optimization where a double lookup - * for name and name+/ is being performed. The name char - * array has enough room at the end to try again with a - * slash appended if the first table lookup does not succeed. - */ - while(1) { - - /* Check the cached entry first */ - ze = zip->cache; - if (ze && equals(ze->name, ze->nlen, name, ulen)) { - /* Cache hit! Remove and return the cached entry. */ - zip->cache = 0; - ZIP_Unlock(zip); - return ze; - } - ze = 0; - - /* - * Search down the target hash chain for a cell whose - * 32 bit hash matches the hashed name. - */ - while (idx != ZIP_ENDCHAIN) { - jzcell *zc = &zip->entries[idx]; - - if (zc->hash == hsh) { - /* - * OK, we've found a ZIP entry whose 32 bit hashcode - * matches the name we're looking for. Try to read - * its entry information from the CEN. If the CEN - * name matches the name we're looking for, we're - * done. - * If the names don't match (which should be very rare) - * we keep searching. - */ - ze = newEntry(zip, zc, ACCESS_RANDOM); - if (ze && equals(ze->name, ze->nlen, name, ulen)) { - break; - } - if (ze != 0) { - /* We need to release the lock across the free call */ - ZIP_Unlock(zip); - ZIP_FreeEntry(zip, ze); - ZIP_Lock(zip); - } - ze = 0; - } - idx = zc->next; - } - - /* Entry found, return it */ - if (ze != 0) { - break; - } - - /* If no need to try appending slash, we are done */ - if (!addSlash) { - break; - } - - /* Slash is already there? */ - if (ulen > 0 && name[ulen - 1] == '/') { - break; - } - - /* Add slash and try once more */ - name[ulen++] = '/'; - name[ulen] = '\0'; - hsh = hash_append(hsh, '/'); - idx = zip->table[hsh % zip->tablelen]; - addSlash = JNI_FALSE; + /* Check the cached entry first */ + ze = zip->cache; + if (ze && equals(ze->name, ze->nlen, name, name_len)) { + /* Cache hit! Remove and return the cached entry. */ + zip->cache = 0; + ZIP_Unlock(zip); + return ze; } + ze = 0; + /* + * Search down the target hash chain for a cell whose + * 32 bit hash matches the hashed name. + */ + while (idx != ZIP_ENDCHAIN) { + jzcell *zc = &zip->entries[idx]; + + if (zc->hash == hsh) { + /* + * OK, we've found a ZIP entry whose 32 bit hashcode + * matches the name we're looking for. Try to read + * its entry information from the CEN. If the CEN + * name matches the name we're looking for, we're + * done. + * If the names don't match (which should be very rare) + * we keep searching. + */ + ze = newEntry(zip, zc, ACCESS_RANDOM); + if (ze && equals(ze->name, ze->nlen, name, name_len)) { + break; + } + if (ze != 0) { + /* We need to release the lock across the free call */ + ZIP_Unlock(zip); + ZIP_FreeEntry(zip, ze); + ZIP_Lock(zip); + } + ze = 0; + } + idx = zc->next; + } Finally: ZIP_Unlock(zip); return ze; @@ -1466,9 +1427,9 @@ InflateFully(jzfile *zip, jzentry *entry, void *buf, char **msg) * has the size bigger than 2**32 bytes in ONE invocation. */ JNIEXPORT jzentry * -ZIP_FindEntry(jzfile *zip, char *name, jint *sizeP, jint *nameLenP) +ZIP_FindEntry(jzfile *zip, const char *name, jint *sizeP, jint *nameLenP) { - jzentry *entry = ZIP_GetEntry(zip, name, 0); + jzentry *entry = ZIP_GetEntry(zip, name); if (entry) { *sizeP = (jint)entry->size; *nameLenP = (jint)strlen(entry->name); diff --git a/src/java.base/share/native/libzip/zip_util.h b/src/java.base/share/native/libzip/zip_util.h index 9825202fc7b..8cfe0b261f5 100644 --- a/src/java.base/share/native/libzip/zip_util.h +++ b/src/java.base/share/native/libzip/zip_util.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 1995, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1995, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -241,8 +241,15 @@ typedef struct jzfile { /* Zip file */ */ #define ZIP_ENDCHAIN ((jint)-1) +/* + * Returns the ZIP entry corresponding to the given (NULL terminated) + * entry name. Returns NULL if no entry is found by that name. + * If the entry is found, then the value of the given sizeP will be + * updated to the ZIP entry's size and the value of nameLenP will be + * updated to the ZIP entry name's length. + */ JNIEXPORT jzentry * -ZIP_FindEntry(jzfile *zip, char *name, jint *sizeP, jint *nameLenP); +ZIP_FindEntry(jzfile *zip, const char *name, jint *sizeP, jint *nameLenP); JNIEXPORT jboolean ZIP_ReadEntry(jzfile *zip, jzentry *entry, unsigned char *buf, char *entrynm); @@ -268,8 +275,12 @@ ZIP_Put_In_Cache0(const char *name, ZFILE zfd, char **pmsg, jlong lastModified, JNIEXPORT void ZIP_Close(jzfile *zip); +/* + * Returns the ZIP entry corresponding to the given (NULL terminated) + * entry name. Returns NULL if no entry is found by that name. + */ jzentry * -ZIP_GetEntry(jzfile *zip, char *name, jint ulen); +ZIP_GetEntry(jzfile *zip, const char *name); void ZIP_Lock(jzfile *zip); void @@ -279,7 +290,6 @@ ZIP_Read(jzfile *zip, jzentry *entry, jlong pos, void *buf, jint len); JNIEXPORT void ZIP_FreeEntry(jzfile *zip, jzentry *ze); jlong ZIP_GetEntryDataOffset(jzfile *zip, jzentry *entry); -jzentry * ZIP_GetEntry2(jzfile *zip, char *name, jint ulen, jboolean addSlash); JNIEXPORT jboolean ZIP_InflateFully(void *inBuf, jlong inLen, void *outBuf, jlong outLen, char **pmsg); diff --git a/src/java.base/unix/native/libjava/TimeZone_md.c b/src/java.base/unix/native/libjava/TimeZone_md.c index cd253edde60..2f163cf27f1 100644 --- a/src/java.base/unix/native/libjava/TimeZone_md.c +++ b/src/java.base/unix/native/libjava/TimeZone_md.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -95,7 +95,7 @@ getZoneName(char *str) { static const char *zidir = "zoneinfo/"; - char *pos = strstr((const char *)str, zidir); + char* pos = strstr(str, zidir); if (pos == NULL) { return NULL; } diff --git a/src/java.base/unix/native/libnet/NetworkInterface.c b/src/java.base/unix/native/libnet/NetworkInterface.c index f5025b9f488..5ed99f256d8 100644 --- a/src/java.base/unix/native/libnet/NetworkInterface.c +++ b/src/java.base/unix/native/libnet/NetworkInterface.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -205,7 +205,7 @@ JNIEXPORT jobject JNICALL Java_java_net_NetworkInterface_getByName0 netif *ifs, *curr; jboolean isCopy; const char* name_utf; - char *colonP; + const char* colonP; jobject obj = NULL; if (name != NULL) { diff --git a/src/java.base/windows/native/libnet/NTLMAuthSequence.c b/src/java.base/windows/native/libnet/NTLMAuthSequence.c index 0da2675b886..214df84ccb8 100644 --- a/src/java.base/windows/native/libnet/NTLMAuthSequence.c +++ b/src/java.base/windows/native/libnet/NTLMAuthSequence.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -231,7 +231,7 @@ JNIEXPORT jbyteArray JNICALL Java_sun_net_www_protocol_http_ntlm_NTLMAuthSequenc if (ss < 0) { SetLastError(ss); - JNU_ThrowIOExceptionWithLastError(env, "InitializeSecurityContext"); + JNU_ThrowIOExceptionWithMessageAndLastError(env, "InitializeSecurityContext"); endSequence (pCred, pCtx, env, status); return 0; } @@ -241,7 +241,7 @@ JNIEXPORT jbyteArray JNICALL Java_sun_net_www_protocol_http_ntlm_NTLMAuthSequenc if (ss < 0) { SetLastError(ss); - JNU_ThrowIOExceptionWithLastError(env, "CompleteAuthToken"); + JNU_ThrowIOExceptionWithMessageAndLastError(env, "CompleteAuthToken"); endSequence (pCred, pCtx, env, status); return 0; } diff --git a/src/java.desktop/macosx/classes/sun/lwawt/LWListPeer.java b/src/java.desktop/macosx/classes/sun/lwawt/LWListPeer.java index e2f26201919..001a44ebf8a 100644 --- a/src/java.desktop/macosx/classes/sun/lwawt/LWListPeer.java +++ b/src/java.desktop/macosx/classes/sun/lwawt/LWListPeer.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -45,7 +45,7 @@ import javax.swing.JScrollBar; import javax.swing.JScrollPane; import javax.swing.JViewport; import javax.swing.ListCellRenderer; -import javax.swing.ListSelectionModel; +import javax.swing.ListModel; import javax.swing.event.ListSelectionEvent; import javax.swing.event.ListSelectionListener; @@ -53,6 +53,9 @@ import static java.awt.event.ItemEvent.DESELECTED; import static java.awt.event.ItemEvent.ITEM_STATE_CHANGED; import static java.awt.event.ItemEvent.SELECTED; +import static javax.swing.ListSelectionModel.MULTIPLE_INTERVAL_SELECTION; +import static javax.swing.ListSelectionModel.SINGLE_SELECTION; + /** * Lightweight implementation of {@link ListPeer}. Delegates most of the work to * the {@link JList}, which is placed inside {@link JScrollPane}. @@ -157,11 +160,14 @@ final class LWListPeer extends LWComponentPeer @Override public void select(final int index) { synchronized (getDelegateLock()) { - getDelegate().setSkipStateChangedEvent(true); - try { - getDelegate().getView().setSelectedIndex(index); - } finally { - getDelegate().setSkipStateChangedEvent(false); + ListModel model = getDelegate().getModel(); + if (index >= 0 && index < model.getSize()) { + getDelegate().setSkipStateChangedEvent(true); + try { + getDelegate().getView().addSelectionInterval(index, index); + } finally { + getDelegate().setSkipStateChangedEvent(false); + } } } } @@ -188,9 +194,23 @@ final class LWListPeer extends LWComponentPeer @Override public void setMultipleMode(final boolean m) { synchronized (getDelegateLock()) { - getDelegate().getView().setSelectionMode(m ? - ListSelectionModel.MULTIPLE_INTERVAL_SELECTION - : ListSelectionModel.SINGLE_SELECTION); + JList view = getDelegate().getView(); + int newMode = m ? MULTIPLE_INTERVAL_SELECTION : SINGLE_SELECTION; + if (view.getSelectionMode() == newMode) { + return; + } + int lead = view.getLeadSelectionIndex(); + boolean wasSelected = lead != -1 && view.isSelectedIndex(lead); + getDelegate().setSkipStateChangedEvent(true); + try { + view.clearSelection(); + view.setSelectionMode(newMode); + if (wasSelected) { + view.setSelectedIndex(lead); + } + } finally { + getDelegate().setSkipStateChangedEvent(false); + } } } diff --git a/src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/CommonComponentAccessibility.m b/src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/CommonComponentAccessibility.m index 45e8f981f50..40f9f50a7d7 100644 --- a/src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/CommonComponentAccessibility.m +++ b/src/java.desktop/macosx/native/libawt_lwawt/awt/a11y/CommonComponentAccessibility.m @@ -1190,13 +1190,24 @@ static jobject sAccessibilityClass = NULL; JNIEnv* env = [ThreadUtilities getJNIEnv]; GET_CACCESSIBILITY_CLASS_RETURN(FALSE); - DECLARE_STATIC_METHOD_RETURN(jm_doAccessibleAction, sjc_CAccessibility, "doAccessibleAction", - "(Ljavax/accessibility/AccessibleAction;ILjava/awt/Component;)V", FALSE); - (*env)->CallStaticVoidMethod(env, sjc_CAccessibility, jm_doAccessibleAction, - [self axContextWithEnv:(env)], index, fComponent); + DECLARE_STATIC_METHOD_RETURN(jm_getAccessibleAction, sjc_CAccessibility, "getAccessibleAction", + "(Ljavax/accessibility/Accessible;Ljava/awt/Component;)Ljavax/accessibility/AccessibleAction;", FALSE); + + jobject axAction = (*env)->CallStaticObjectMethod(env, sjc_CAccessibility, jm_getAccessibleAction, fAccessible, fComponent); CHECK_EXCEPTION(); - return TRUE; + if (axAction != NULL) { + DECLARE_STATIC_METHOD_RETURN(jm_doAccessibleAction, sjc_CAccessibility, "doAccessibleAction", + "(Ljavax/accessibility/AccessibleAction;ILjava/awt/Component;)V", FALSE); + (*env)->CallStaticVoidMethod(env, sjc_CAccessibility, jm_doAccessibleAction, + axAction, index, fComponent); + CHECK_EXCEPTION(); + + (*env)->DeleteLocalRef(env, axAction); + return TRUE; + } else { + return FALSE; + } } // NSAccessibilityActions methods diff --git a/src/java.desktop/macosx/native/libawt_lwawt/java2d/metal/MTLRenderQueue.m b/src/java.desktop/macosx/native/libawt_lwawt/java2d/metal/MTLRenderQueue.m index 3ffa887388e..d6edd56a5ab 100644 --- a/src/java.desktop/macosx/native/libawt_lwawt/java2d/metal/MTLRenderQueue.m +++ b/src/java.desktop/macosx/native/libawt_lwawt/java2d/metal/MTLRenderQueue.m @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -48,6 +48,19 @@ jint mtlPreviousOp = MTL_OP_INIT; extern void MTLGC_DestroyMTLGraphicsConfig(jlong pConfigInfo); +/** + * Triggers the display link for the current destination surface. + */ +static void MTLSD_Flush() { + if (dstOps != NULL) { + MTLSDOps *dstMTLOps = (MTLSDOps *)dstOps->privOps; + MTLLayer *layer = (MTLLayer*)dstMTLOps->layer; + if (layer != NULL) { + [layer startDisplayLink]; + } + } +} + void MTLRenderQueue_CheckPreviousOp(jint op) { if (mtlPreviousOp == op) { @@ -589,6 +602,7 @@ Java_sun_java2d_metal_MTLRenderQueue_flushBuffer [cbwrapper release]; }]; [commandbuf commit]; + MTLSD_Flush(); } mtlc = [MTLContext setSurfacesEnv:env src:pSrc dst:pDst]; dstOps = (BMTLSDOps *)jlong_to_ptr(pDst); @@ -616,6 +630,7 @@ Java_sun_java2d_metal_MTLRenderQueue_flushBuffer [cbwrapper release]; }]; [commandbuf commit]; + MTLSD_Flush(); } mtlc = newMtlc; dstOps = NULL; @@ -886,14 +901,7 @@ Java_sun_java2d_metal_MTLRenderQueue_flushBuffer [cbwrapper release]; }]; [commandbuf commit]; - BMTLSDOps *dstOps = MTLRenderQueue_GetCurrentDestination(); - if (dstOps != NULL) { - MTLSDOps *dstMTLOps = (MTLSDOps *)dstOps->privOps; - MTLLayer *layer = (MTLLayer*)dstMTLOps->layer; - if (layer != NULL) { - [layer startDisplayLink]; - } - } + MTLSD_Flush(); } RESET_PREVIOUS_OP(); } diff --git a/src/java.desktop/share/classes/com/sun/imageio/stream/StreamCloser.java b/src/java.desktop/share/classes/com/sun/imageio/stream/StreamCloser.java index 7de400ad199..29aaed7d9e3 100644 --- a/src/java.desktop/share/classes/com/sun/imageio/stream/StreamCloser.java +++ b/src/java.desktop/share/classes/com/sun/imageio/stream/StreamCloser.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -48,7 +48,6 @@ public class StreamCloser { private static WeakHashMap toCloseQueue; private static Thread streamCloser; - @SuppressWarnings("removal") public static void addToQueue(CloseAction ca) { synchronized (StreamCloser.class) { if (toCloseQueue == null) { diff --git a/src/java.desktop/share/classes/java/awt/Component.java b/src/java.desktop/share/classes/java/awt/Component.java index 7f021dcdb85..21358efa3f3 100644 --- a/src/java.desktop/share/classes/java/awt/Component.java +++ b/src/java.desktop/share/classes/java/awt/Component.java @@ -4000,7 +4000,6 @@ public abstract class Component implements ImageObserver, MenuContainer, * {@code true}. * @see #createBuffers(int, BufferCapabilities) */ - @SuppressWarnings("removal") protected FlipBufferStrategy(int numBuffers, BufferCapabilities caps) throws AWTException { @@ -8129,7 +8128,6 @@ public abstract class Component implements ImageObserver, MenuContainer, return res; } - @SuppressWarnings("removal") final Component getNextFocusCandidate() { Container rootAncestor = getTraversalRoot(); Component comp = this; diff --git a/src/java.desktop/share/classes/java/awt/SequencedEvent.java b/src/java.desktop/share/classes/java/awt/SequencedEvent.java index 25fe72e1787..c919374a85c 100644 --- a/src/java.desktop/share/classes/java/awt/SequencedEvent.java +++ b/src/java.desktop/share/classes/java/awt/SequencedEvent.java @@ -55,7 +55,6 @@ class SequencedEvent extends AWTEvent implements ActiveEvent { private static final LinkedList list = new LinkedList<>(); private final AWTEvent nested; - @SuppressWarnings("serial") // Not statically typed as Serializable private boolean disposed; private final LinkedList pendingEvents = new LinkedList<>(); diff --git a/src/java.desktop/share/classes/javax/imageio/spi/ServiceRegistry.java b/src/java.desktop/share/classes/javax/imageio/spi/ServiceRegistry.java index 7eaa14133c5..2d6edaca544 100644 --- a/src/java.desktop/share/classes/javax/imageio/spi/ServiceRegistry.java +++ b/src/java.desktop/share/classes/javax/imageio/spi/ServiceRegistry.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -718,7 +718,6 @@ class SubRegistry { this.category = category; } - @SuppressWarnings("removal") public synchronized boolean registerServiceProvider(Object provider) { Object oprovider = map.get(provider.getClass()); boolean present = oprovider != null; diff --git a/src/java.desktop/share/classes/javax/print/attribute/AttributeSet.java b/src/java.desktop/share/classes/javax/print/attribute/AttributeSet.java index 58b23569a92..0fd2da05d60 100644 --- a/src/java.desktop/share/classes/javax/print/attribute/AttributeSet.java +++ b/src/java.desktop/share/classes/javax/print/attribute/AttributeSet.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -249,6 +249,7 @@ public interface AttributeSet { * @return {@code true} if the specified object is equal to this attribute * set */ + @Override public boolean equals(Object object); /** @@ -261,5 +262,6 @@ public interface AttributeSet { * * @return the hash code value for this attribute set */ + @Override public int hashCode(); } diff --git a/src/java.desktop/share/classes/javax/print/attribute/AttributeSetUtilities.java b/src/java.desktop/share/classes/javax/print/attribute/AttributeSetUtilities.java index f762eb89925..ea4dcf54f32 100644 --- a/src/java.desktop/share/classes/javax/print/attribute/AttributeSetUtilities.java +++ b/src/java.desktop/share/classes/javax/print/attribute/AttributeSetUtilities.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -101,54 +101,67 @@ public final class AttributeSetUtilities { attrset = attributeSet; } + @Override public Attribute get(Class key) { return attrset.get(key); } + @Override public boolean add(Attribute attribute) { throw new UnmodifiableSetException(); } + @Override public synchronized boolean remove(Class category) { throw new UnmodifiableSetException(); } + @Override public boolean remove(Attribute attribute) { throw new UnmodifiableSetException(); } + @Override public boolean containsKey(Class category) { return attrset.containsKey(category); } + @Override public boolean containsValue(Attribute attribute) { return attrset.containsValue(attribute); } + @Override public boolean addAll(AttributeSet attributes) { throw new UnmodifiableSetException(); } + @Override public int size() { return attrset.size(); } + @Override public Attribute[] toArray() { return attrset.toArray(); } + @Override public void clear() { throw new UnmodifiableSetException(); } + @Override public boolean isEmpty() { return attrset.isEmpty(); } + @Override public boolean equals(Object o) { return attrset.equals (o); } + @Override public int hashCode() { return attrset.hashCode(); } @@ -366,54 +379,67 @@ public final class AttributeSetUtilities { attrset = attributeSet; } + @Override public synchronized Attribute get(Class category) { return attrset.get(category); } + @Override public synchronized boolean add(Attribute attribute) { return attrset.add(attribute); } + @Override public synchronized boolean remove(Class category) { return attrset.remove(category); } + @Override public synchronized boolean remove(Attribute attribute) { return attrset.remove(attribute); } + @Override public synchronized boolean containsKey(Class category) { return attrset.containsKey(category); } + @Override public synchronized boolean containsValue(Attribute attribute) { return attrset.containsValue(attribute); } + @Override public synchronized boolean addAll(AttributeSet attributes) { return attrset.addAll(attributes); } + @Override public synchronized int size() { return attrset.size(); } + @Override public synchronized Attribute[] toArray() { return attrset.toArray(); } + @Override public synchronized void clear() { attrset.clear(); } + @Override public synchronized boolean isEmpty() { return attrset.isEmpty(); } + @Override public synchronized boolean equals(Object o) { return attrset.equals (o); } + @Override public synchronized int hashCode() { return attrset.hashCode(); } diff --git a/src/java.desktop/share/classes/javax/print/attribute/DateTimeSyntax.java b/src/java.desktop/share/classes/javax/print/attribute/DateTimeSyntax.java index 2f0eafb9f79..154b492de84 100644 --- a/src/java.desktop/share/classes/javax/print/attribute/DateTimeSyntax.java +++ b/src/java.desktop/share/classes/javax/print/attribute/DateTimeSyntax.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -114,6 +114,7 @@ public abstract class DateTimeSyntax implements Serializable, Cloneable { * @return {@code true} if {@code object} is equivalent to this date-time * attribute, {@code false} otherwise */ + @Override public boolean equals(Object object) { return object instanceof DateTimeSyntax other && value.equals(other.value); @@ -123,6 +124,7 @@ public abstract class DateTimeSyntax implements Serializable, Cloneable { * Returns a hash code value for this date-time attribute. The hashcode is * that of this attribute's {@code java.util.Date} value. */ + @Override public int hashCode() { return value.hashCode(); } @@ -132,6 +134,7 @@ public abstract class DateTimeSyntax implements Serializable, Cloneable { * string value is just this attribute's {@code java.util.Date} value * converted to a string. */ + @Override public String toString() { return "" + value; } diff --git a/src/java.desktop/share/classes/javax/print/attribute/DocAttributeSet.java b/src/java.desktop/share/classes/javax/print/attribute/DocAttributeSet.java index 102786da27b..2abd6e6322a 100644 --- a/src/java.desktop/share/classes/javax/print/attribute/DocAttributeSet.java +++ b/src/java.desktop/share/classes/javax/print/attribute/DocAttributeSet.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -59,6 +59,7 @@ public interface DocAttributeSet extends AttributeSet { * interface {@link DocAttribute DocAttribute} * @throws NullPointerException if the {@code attribute} is {@code null} */ + @Override public boolean add(Attribute attribute); /** @@ -88,5 +89,6 @@ public interface DocAttributeSet extends AttributeSet { * @throws NullPointerException if the specified set is {@code null} * @see #add(Attribute) */ + @Override public boolean addAll(AttributeSet attributes); } diff --git a/src/java.desktop/share/classes/javax/print/attribute/EnumSyntax.java b/src/java.desktop/share/classes/javax/print/attribute/EnumSyntax.java index fd48a600ee3..4c291999e02 100644 --- a/src/java.desktop/share/classes/javax/print/attribute/EnumSyntax.java +++ b/src/java.desktop/share/classes/javax/print/attribute/EnumSyntax.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -145,6 +145,7 @@ public abstract class EnumSyntax implements Serializable, Cloneable { * semantics of enumeration values is the same object as this enumeration * value. */ + @Override public Object clone() { return this; } @@ -153,6 +154,7 @@ public abstract class EnumSyntax implements Serializable, Cloneable { * Returns a hash code value for this enumeration value. The hash code is * just this enumeration value's integer value. */ + @Override public int hashCode() { return value; } @@ -160,6 +162,7 @@ public abstract class EnumSyntax implements Serializable, Cloneable { /** * Returns a string value corresponding to this enumeration value. */ + @Override public String toString() { String[] theTable = getStringTable(); diff --git a/src/java.desktop/share/classes/javax/print/attribute/HashAttributeSet.java b/src/java.desktop/share/classes/javax/print/attribute/HashAttributeSet.java index 4ad4c8634aa..6800b45a349 100644 --- a/src/java.desktop/share/classes/javax/print/attribute/HashAttributeSet.java +++ b/src/java.desktop/share/classes/javax/print/attribute/HashAttributeSet.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -255,6 +255,7 @@ public class HashAttributeSet implements AttributeSet, Serializable { * {@link Class Class} that implements interface * {@link Attribute Attribute} */ + @Override public Attribute get(Class category) { return attrMap.get(AttributeSetUtilities. verifyAttributeCategory(category, @@ -274,6 +275,7 @@ public class HashAttributeSet implements AttributeSet, Serializable { * @throws UnmodifiableSetException if this attribute set does not support * the {@code add()} operation */ + @Override public boolean add(Attribute attribute) { Object oldAttribute = attrMap.put(attribute.getCategory(), @@ -294,6 +296,7 @@ public class HashAttributeSet implements AttributeSet, Serializable { * @throws UnmodifiableSetException if this attribute set does not support * the {@code remove()} operation */ + @Override public boolean remove(Class category) { return category != null && @@ -314,6 +317,7 @@ public class HashAttributeSet implements AttributeSet, Serializable { * @throws UnmodifiableSetException if this attribute set does not support * the {@code remove()} operation */ + @Override public boolean remove(Attribute attribute) { return attribute != null && @@ -328,6 +332,7 @@ public class HashAttributeSet implements AttributeSet, Serializable { * @return {@code true} if this attribute set contains an attribute value * for the specified category */ + @Override public boolean containsKey(Class category) { return category != null && @@ -344,6 +349,7 @@ public class HashAttributeSet implements AttributeSet, Serializable { * @return {@code true} if this attribute set contains the given attribute * value */ + @Override public boolean containsValue(Attribute attribute) { return attribute != null && attribute.equals(attrMap.get(attribute.getCategory())); @@ -371,6 +377,7 @@ public class HashAttributeSet implements AttributeSet, Serializable { * {@code null}, or the set is {@code null} * @see #add(Attribute) */ + @Override public boolean addAll(AttributeSet attributes) { Attribute []attrs = attributes.toArray(); @@ -392,6 +399,7 @@ public class HashAttributeSet implements AttributeSet, Serializable { * * @return the number of attributes in this attribute set */ + @Override public int size() { return attrMap.size(); } @@ -402,6 +410,7 @@ public class HashAttributeSet implements AttributeSet, Serializable { * @return the attributes contained in this set as an array, zero length if * the {@code AttributeSet} is empty */ + @Override public Attribute[] toArray() { Attribute []attrs = new Attribute[size()]; attrMap.values().toArray(attrs); @@ -414,6 +423,7 @@ public class HashAttributeSet implements AttributeSet, Serializable { * @throws UnmodifiableSetException if this attribute set does not support * the {@code clear()} operation */ + @Override public void clear() { attrMap.clear(); } @@ -423,6 +433,7 @@ public class HashAttributeSet implements AttributeSet, Serializable { * * @return {@code true} if this attribute set contains no attributes */ + @Override public boolean isEmpty() { return attrMap.isEmpty(); } @@ -438,6 +449,7 @@ public class HashAttributeSet implements AttributeSet, Serializable { * @return {@code true} if the specified object is equal to this attribute * set */ + @Override public boolean equals(Object object) { if (!(object instanceof AttributeSet aset)) { return false; @@ -466,6 +478,7 @@ public class HashAttributeSet implements AttributeSet, Serializable { * * @return the hash code value for this attribute set */ + @Override public int hashCode() { int hcode = 0; Attribute[] attrs = toArray(); diff --git a/src/java.desktop/share/classes/javax/print/attribute/IntegerSyntax.java b/src/java.desktop/share/classes/javax/print/attribute/IntegerSyntax.java index f6dbee3aa5a..b6846ff7271 100644 --- a/src/java.desktop/share/classes/javax/print/attribute/IntegerSyntax.java +++ b/src/java.desktop/share/classes/javax/print/attribute/IntegerSyntax.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -107,6 +107,7 @@ public abstract class IntegerSyntax implements Serializable, Cloneable { * @return {@code true} if {@code object} is equivalent to this integer * attribute, {@code false} otherwise */ + @Override public boolean equals(Object object) { return object instanceof IntegerSyntax other && value == other.value; @@ -116,6 +117,7 @@ public abstract class IntegerSyntax implements Serializable, Cloneable { * Returns a hash code value for this integer attribute. The hash code is * just this integer attribute's integer value. */ + @Override public int hashCode() { return value; } @@ -125,6 +127,7 @@ public abstract class IntegerSyntax implements Serializable, Cloneable { * string value is just this integer attribute's integer value converted to * a string. */ + @Override public String toString() { return "" + value; } diff --git a/src/java.desktop/share/classes/javax/print/attribute/PrintJobAttributeSet.java b/src/java.desktop/share/classes/javax/print/attribute/PrintJobAttributeSet.java index 63535fba93e..ce22602f4d5 100644 --- a/src/java.desktop/share/classes/javax/print/attribute/PrintJobAttributeSet.java +++ b/src/java.desktop/share/classes/javax/print/attribute/PrintJobAttributeSet.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -59,6 +59,7 @@ public interface PrintJobAttributeSet extends AttributeSet { * interface {@link PrintJobAttribute PrintJobAttribute} * @throws NullPointerException if the {@code attribute} is {@code null} */ + @Override public boolean add(Attribute attribute); /** @@ -88,5 +89,6 @@ public interface PrintJobAttributeSet extends AttributeSet { * @throws NullPointerException if the specified set is {@code null} * @see #add(Attribute) */ + @Override public boolean addAll(AttributeSet attributes); } diff --git a/src/java.desktop/share/classes/javax/print/attribute/PrintRequestAttributeSet.java b/src/java.desktop/share/classes/javax/print/attribute/PrintRequestAttributeSet.java index 95a07655f03..958d255b296 100644 --- a/src/java.desktop/share/classes/javax/print/attribute/PrintRequestAttributeSet.java +++ b/src/java.desktop/share/classes/javax/print/attribute/PrintRequestAttributeSet.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -60,6 +60,7 @@ public interface PrintRequestAttributeSet extends AttributeSet { * interface {@link PrintRequestAttribute PrintRequestAttribute} * @throws NullPointerException if the {@code attribute} is {@code null} */ + @Override public boolean add(Attribute attribute); /** @@ -90,5 +91,6 @@ public interface PrintRequestAttributeSet extends AttributeSet { * @throws NullPointerException if the specified set is {@code null} * @see #add(Attribute) */ + @Override public boolean addAll(AttributeSet attributes); } diff --git a/src/java.desktop/share/classes/javax/print/attribute/PrintServiceAttributeSet.java b/src/java.desktop/share/classes/javax/print/attribute/PrintServiceAttributeSet.java index fd2d4dc4694..a456eac07b6 100644 --- a/src/java.desktop/share/classes/javax/print/attribute/PrintServiceAttributeSet.java +++ b/src/java.desktop/share/classes/javax/print/attribute/PrintServiceAttributeSet.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -60,6 +60,7 @@ public interface PrintServiceAttributeSet extends AttributeSet { * interface {@link PrintServiceAttribute PrintServiceAttribute} * @throws NullPointerException if the {@code attribute} is {@code null} */ + @Override public boolean add(Attribute attribute); /** @@ -90,5 +91,6 @@ public interface PrintServiceAttributeSet extends AttributeSet { * @throws NullPointerException if the specified set is {@code null} * @see #add(Attribute) */ + @Override public boolean addAll(AttributeSet attributes); } diff --git a/src/java.desktop/share/classes/javax/print/attribute/ResolutionSyntax.java b/src/java.desktop/share/classes/javax/print/attribute/ResolutionSyntax.java index 8ffae65a0d2..ffb1fab3619 100644 --- a/src/java.desktop/share/classes/javax/print/attribute/ResolutionSyntax.java +++ b/src/java.desktop/share/classes/javax/print/attribute/ResolutionSyntax.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -266,6 +266,7 @@ public abstract class ResolutionSyntax implements Serializable, Cloneable { * @return {@code true} if {@code object} is equivalent to this resolution * attribute, {@code false} otherwise */ + @Override public boolean equals(Object object) { return object instanceof ResolutionSyntax other && this.crossFeedResolution == other.crossFeedResolution && @@ -275,6 +276,7 @@ public abstract class ResolutionSyntax implements Serializable, Cloneable { /** * Returns a hash code value for this resolution attribute. */ + @Override public int hashCode() { return(((crossFeedResolution & 0x0000FFFF)) | ((feedResolution & 0x0000FFFF) << 16)); @@ -286,6 +288,7 @@ public abstract class ResolutionSyntax implements Serializable, Cloneable { * cross feed direction resolution and F is the feed direction * resolution. The values are reported in the internal units of dphi. */ + @Override public String toString() { StringBuilder result = new StringBuilder(); result.append(crossFeedResolution); diff --git a/src/java.desktop/share/classes/javax/print/attribute/SetOfIntegerSyntax.java b/src/java.desktop/share/classes/javax/print/attribute/SetOfIntegerSyntax.java index 6df67ef90ca..8088cfcd743 100644 --- a/src/java.desktop/share/classes/javax/print/attribute/SetOfIntegerSyntax.java +++ b/src/java.desktop/share/classes/javax/print/attribute/SetOfIntegerSyntax.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -482,6 +482,7 @@ public abstract class SetOfIntegerSyntax implements Serializable, Cloneable { * @return {@code true} if {@code object} is equivalent to this * set-of-integer attribute, {@code false} otherwise */ + @Override public boolean equals(Object object) { if (object instanceof SetOfIntegerSyntax other) { int[][] myMembers = this.members; @@ -509,6 +510,7 @@ public abstract class SetOfIntegerSyntax implements Serializable, Cloneable { * code is the sum of the lower and upper bounds of the ranges in the * canonical array form, or 0 for an empty set. */ + @Override public int hashCode() { int result = 0; int n = members.length; @@ -526,6 +528,7 @@ public abstract class SetOfIntegerSyntax implements Serializable, Cloneable { * the lower bound equals the upper bound or * "i-j" otherwise. */ + @Override public String toString() { StringBuilder result = new StringBuilder(); int n = members.length; diff --git a/src/java.desktop/share/classes/javax/print/attribute/Size2DSyntax.java b/src/java.desktop/share/classes/javax/print/attribute/Size2DSyntax.java index 9ff772bc30d..056031b52f2 100644 --- a/src/java.desktop/share/classes/javax/print/attribute/Size2DSyntax.java +++ b/src/java.desktop/share/classes/javax/print/attribute/Size2DSyntax.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -263,6 +263,7 @@ public abstract class Size2DSyntax implements Serializable, Cloneable { * @return {@code true} if {@code object} is equivalent to this * two-dimensional size attribute, {@code false} otherwise */ + @Override public boolean equals(Object object) { return object instanceof Size2DSyntax size2DSyntax && this.x == size2DSyntax.x && @@ -272,6 +273,7 @@ public abstract class Size2DSyntax implements Serializable, Cloneable { /** * Returns a hash code value for this two-dimensional size attribute. */ + @Override public int hashCode() { return (((x & 0x0000FFFF) ) | ((y & 0x0000FFFF) << 16)); @@ -283,6 +285,7 @@ public abstract class Size2DSyntax implements Serializable, Cloneable { * is the {@code X} dimension and Y is the {@code Y} dimension. The * values are reported in the internal units of micrometers. */ + @Override public String toString() { StringBuilder result = new StringBuilder(); result.append(x); diff --git a/src/java.desktop/share/classes/javax/print/attribute/TextSyntax.java b/src/java.desktop/share/classes/javax/print/attribute/TextSyntax.java index 9a343bc8af2..2c49a11b250 100644 --- a/src/java.desktop/share/classes/javax/print/attribute/TextSyntax.java +++ b/src/java.desktop/share/classes/javax/print/attribute/TextSyntax.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -112,6 +112,7 @@ public abstract class TextSyntax implements Serializable, Cloneable { * * @return a hashcode value for this object */ + @Override public int hashCode() { return value.hashCode() ^ locale.hashCode(); } @@ -131,6 +132,7 @@ public abstract class TextSyntax implements Serializable, Cloneable { * @return {@code true} if {@code object} is equivalent to this text * attribute, {@code false} otherwise */ + @Override public boolean equals(Object object) { return object instanceof TextSyntax other && this.value.equals(other.value) && @@ -143,6 +145,7 @@ public abstract class TextSyntax implements Serializable, Cloneable { * * @return a {@code String} identifying this object */ + @Override public String toString(){ return value; } diff --git a/src/java.desktop/share/classes/javax/print/attribute/URISyntax.java b/src/java.desktop/share/classes/javax/print/attribute/URISyntax.java index 10545df71fd..b3e604283f7 100644 --- a/src/java.desktop/share/classes/javax/print/attribute/URISyntax.java +++ b/src/java.desktop/share/classes/javax/print/attribute/URISyntax.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -82,6 +82,7 @@ public abstract class URISyntax implements Serializable, Cloneable { * * @return a hashcode value for this object */ + @Override public int hashCode() { return uri.hashCode(); } @@ -100,6 +101,7 @@ public abstract class URISyntax implements Serializable, Cloneable { * @return {@code true} if {@code object} is equivalent to this {@code URI} * attribute, {@code false} otherwise */ + @Override public boolean equals(Object object) { return object instanceof URISyntax other && this.uri.equals(other.uri); @@ -112,6 +114,7 @@ public abstract class URISyntax implements Serializable, Cloneable { * * @return a {@code String} identifying this object */ + @Override public String toString() { return uri.toString(); } diff --git a/src/java.desktop/share/classes/javax/swing/JComponent.java b/src/java.desktop/share/classes/javax/swing/JComponent.java index 87d6a41c2b0..9a7e67913ff 100644 --- a/src/java.desktop/share/classes/javax/swing/JComponent.java +++ b/src/java.desktop/share/classes/javax/swing/JComponent.java @@ -5070,7 +5070,6 @@ public abstract class JComponent extends Container implements Serializable, this.paintingChild = paintingChild; } - @SuppressWarnings("removal") void _paintImmediately(int x, int y, int w, int h) { Graphics g; Container c; diff --git a/src/java.desktop/share/classes/javax/swing/PopupFactory.java b/src/java.desktop/share/classes/javax/swing/PopupFactory.java index 7245820c289..58a74def3b6 100644 --- a/src/java.desktop/share/classes/javax/swing/PopupFactory.java +++ b/src/java.desktop/share/classes/javax/swing/PopupFactory.java @@ -865,7 +865,6 @@ public class PopupFactory { /** * Returns the cache to use for medium weight popups. */ - @SuppressWarnings("unchecked") private static List getMediumWeightPopupCache() { synchronized (MediumWeightPopup.class) { if (cache == null) { diff --git a/src/java.desktop/share/classes/javax/swing/RepaintManager.java b/src/java.desktop/share/classes/javax/swing/RepaintManager.java index ab21e555919..9901ef04a47 100644 --- a/src/java.desktop/share/classes/javax/swing/RepaintManager.java +++ b/src/java.desktop/share/classes/javax/swing/RepaintManager.java @@ -1026,7 +1026,7 @@ public class RepaintManager // If the window is non-opaque, it's double-buffered at peer's level Window w = (c instanceof Window) ? (Window)c : SwingUtilities.getWindowAncestor(c); - if (!w.isOpaque()) { + if (w != null && !w.isOpaque()) { Toolkit tk = Toolkit.getDefaultToolkit(); if ((tk instanceof SunToolkit) && (((SunToolkit)tk).needUpdateWindow())) { return null; diff --git a/src/java.desktop/share/classes/javax/swing/ToolTipManager.java b/src/java.desktop/share/classes/javax/swing/ToolTipManager.java index 4c3d0209823..58a4b384ccf 100644 --- a/src/java.desktop/share/classes/javax/swing/ToolTipManager.java +++ b/src/java.desktop/share/classes/javax/swing/ToolTipManager.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -818,7 +818,6 @@ public final class ToolTipManager extends MouseAdapter implements MouseMotionLis // Returns: 0 no adjust // >0 adjust by value return - @SuppressWarnings("removal") private int getPopupFitHeight(Rectangle popupRectInScreen, Component invoker){ if (invoker != null){ Container parent; diff --git a/src/java.desktop/share/classes/javax/swing/text/DefaultCaret.java b/src/java.desktop/share/classes/javax/swing/text/DefaultCaret.java index ed502e8da9b..f76e0405124 100644 --- a/src/java.desktop/share/classes/javax/swing/text/DefaultCaret.java +++ b/src/java.desktop/share/classes/javax/swing/text/DefaultCaret.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,6 +25,7 @@ package javax.swing.text; +import java.awt.Color; import java.awt.Graphics; import java.awt.HeadlessException; import java.awt.Point; @@ -690,7 +691,25 @@ public class DefaultCaret extends Rectangle implements Caret, FocusListener, Mou // semantics of damage we can't really get around this. damage(r); } - g.setColor(component.getCaretColor()); + if (component.isEditable()) { + g.setColor(component.getCaretColor()); + } else { + Color caretColor = component.getCaretColor(); + if (caretColor == null) { + caretColor = g.getColor(); + } + Color bg = component.getBackground(); + if (bg == null) { + g.setColor(caretColor); + } else { + int red = (caretColor.getRed() + bg.getRed()) / 2; + int green = (caretColor.getGreen() + bg.getGreen()) / 2; + int blue = (caretColor.getBlue() + bg.getBlue()) / 2; + int alpha = 127; + Color newCaretColor = new Color(red, green, blue, alpha); + g.setColor(newCaretColor); + } + } int paintWidth = getCaretWidth(r.height); r.x -= paintWidth >> 1; g.fillRect(r.x, r.y, paintWidth, r.height); diff --git a/src/java.desktop/share/classes/sun/awt/geom/AreaOp.java b/src/java.desktop/share/classes/sun/awt/geom/AreaOp.java index 1d0e6df3734..65f7dbf11eb 100644 --- a/src/java.desktop/share/classes/sun/awt/geom/AreaOp.java +++ b/src/java.desktop/share/classes/sun/awt/geom/AreaOp.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -146,6 +146,8 @@ public abstract class AreaOp { public static final int RSTAG_INSIDE = 1; public static final int RSTAG_OUTSIDE = -1; + public static final int MAX_LINK_COUNT = 1024; + public abstract void newRow(); public abstract int classify(Edge e); @@ -195,6 +197,25 @@ public abstract class AreaOp { } }; + private void consumeSubCurves(Vector subcurves, + Vector chains, + Vector curve) { + finalizeSubCurves(subcurves, chains); + Enumeration enum_ = subcurves.elements(); + while (enum_.hasMoreElements()) { + CurveLink link = enum_.nextElement(); + curve.add(link.getMoveto()); + CurveLink nextlink = link; + while ((nextlink = nextlink.getNext()) != null) { + if (!link.absorb(nextlink)) { + curve.add(link.getSubCurve()); + link = nextlink; + } + } + curve.add(link.getSubCurve()); + } + } + private Vector pruneEdges(Vector edges) { int numedges = edges.size(); if (numedges < 2) { @@ -218,6 +239,8 @@ public abstract class AreaOp { Vector subcurves = new Vector<>(); Vector chains = new Vector<>(); Vector links = new Vector<>(); + Vector ret = new Vector<>(); + int linkCount = 0; // Active edges are between left (inclusive) and right (exclusive) while (left < numedges) { double y = yrange[0]; @@ -390,27 +413,22 @@ public abstract class AreaOp { System.out.println(" "+link.getSubCurve()); } } + // If we have complex area calculation, we should consume the + // intermediate subcurves to optimize memory footprint + if (linkCount >= MAX_LINK_COUNT) { + consumeSubCurves(subcurves, chains, ret); + linkCount = 0; + chains.clear(); + subcurves.clear(); + } + linkCount += links.size(); resolveLinks(subcurves, chains, links); links.clear(); // Finally capture the bottom of the valid Y range as the top // of the next Y range. yrange[0] = yend; } - finalizeSubCurves(subcurves, chains); - Vector ret = new Vector<>(); - Enumeration enum_ = subcurves.elements(); - while (enum_.hasMoreElements()) { - CurveLink link = enum_.nextElement(); - ret.add(link.getMoveto()); - CurveLink nextlink = link; - while ((nextlink = nextlink.getNext()) != null) { - if (!link.absorb(nextlink)) { - ret.add(link.getSubCurve()); - link = nextlink; - } - } - ret.add(link.getSubCurve()); - } + consumeSubCurves(subcurves, chains, ret); return ret; } diff --git a/src/java.desktop/share/classes/sun/awt/geom/Curve.java b/src/java.desktop/share/classes/sun/awt/geom/Curve.java index 83986b88777..7cdb45e5a22 100644 --- a/src/java.desktop/share/classes/sun/awt/geom/Curve.java +++ b/src/java.desktop/share/classes/sun/awt/geom/Curve.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -1046,6 +1046,9 @@ public abstract class Curve { double bump = ymin; double maxbump = Math.min(ymin * 1E13, (y1 - y0) * .1); double y = y0 + bump; + if (!Double.isFinite(y1)) { + return 0; + } while (y <= y1) { if (fairlyClose(this.XforY(y), that.XforY(y))) { if ((bump *= 2) > maxbump) { @@ -1319,7 +1322,7 @@ public abstract class Curve { public boolean fairlyClose(double v1, double v2) { return (Math.abs(v1 - v2) < - Math.max(Math.abs(v1), Math.abs(v2)) * 1E-10); + Math.max(Math.abs(v1), Math.abs(v2)) * 1E-8); } public abstract int getSegment(double[] coords); diff --git a/src/java.desktop/share/native/common/java2d/opengl/OGLRenderQueue.c b/src/java.desktop/share/native/common/java2d/opengl/OGLRenderQueue.c index 2bafc33f588..ddd9b1c6eb2 100644 --- a/src/java.desktop/share/native/common/java2d/opengl/OGLRenderQueue.c +++ b/src/java.desktop/share/native/common/java2d/opengl/OGLRenderQueue.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -433,6 +433,7 @@ Java_sun_java2d_opengl_OGLRenderQueue_flushBuffer jlong pDst = NEXT_LONG(b); if (oglc != NULL) { RESET_PREVIOUS_OP(); + OGLSD_Flush(env); } oglc = OGLContext_SetSurfaces(env, pSrc, pDst); dstOps = (OGLSDOps *)jlong_to_ptr(pDst); @@ -443,6 +444,7 @@ Java_sun_java2d_opengl_OGLRenderQueue_flushBuffer jlong pConfigInfo = NEXT_LONG(b); if (oglc != NULL) { RESET_PREVIOUS_OP(); + OGLSD_Flush(env); } oglc = OGLSD_SetScratchSurface(env, pConfigInfo); dstOps = NULL; diff --git a/src/java.desktop/windows/classes/sun/awt/windows/WWindowPeer.java b/src/java.desktop/windows/classes/sun/awt/windows/WWindowPeer.java index f028e0fbec5..9c1c7665f4b 100644 --- a/src/java.desktop/windows/classes/sun/awt/windows/WWindowPeer.java +++ b/src/java.desktop/windows/classes/sun/awt/windows/WWindowPeer.java @@ -108,7 +108,6 @@ public class WWindowPeer extends WPanelPeer implements WindowPeer, static List activeWindows = new LinkedList(); // WComponentPeer overrides @Override - @SuppressWarnings("unchecked") protected void disposeImpl() { synchronized (activeWindows) { activeWindows.remove(this); diff --git a/src/java.instrument/share/native/libinstrument/JPLISAgent.c b/src/java.instrument/share/native/libinstrument/JPLISAgent.c index c65bfb9f2f9..a48defd471d 100644 --- a/src/java.instrument/share/native/libinstrument/JPLISAgent.c +++ b/src/java.instrument/share/native/libinstrument/JPLISAgent.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -780,7 +780,7 @@ getModuleObject(jvmtiEnv* jvmti, jobject moduleObject = NULL; /* find last slash in the class name */ - char* last_slash = (cname == NULL) ? NULL : strrchr(cname, '/'); + const char* last_slash = (cname == NULL) ? NULL : strrchr(cname, '/'); int len = (last_slash == NULL) ? 0 : (int)(last_slash - cname); char* pkg_name_buf = (char*)malloc(len + 1); diff --git a/src/java.instrument/unix/native/libinstrument/FileSystemSupport_md.c b/src/java.instrument/unix/native/libinstrument/FileSystemSupport_md.c index f7ea013412d..b9771e55b44 100644 --- a/src/java.instrument/unix/native/libinstrument/FileSystemSupport_md.c +++ b/src/java.instrument/unix/native/libinstrument/FileSystemSupport_md.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2004, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -36,7 +36,7 @@ #define slash '/' char* basePath(const char* path) { - char* last = strrchr(path, slash); + const char* last = strrchr(path, slash); if (last == NULL) { return (char*)path; } else { diff --git a/src/java.naming/share/classes/com/sun/jndi/ldap/ext/StartTlsResponseImpl.java b/src/java.naming/share/classes/com/sun/jndi/ldap/ext/StartTlsResponseImpl.java index fdff5d84189..77bb54fa5ba 100644 --- a/src/java.naming/share/classes/com/sun/jndi/ldap/ext/StartTlsResponseImpl.java +++ b/src/java.naming/share/classes/com/sun/jndi/ldap/ext/StartTlsResponseImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -29,7 +29,6 @@ import java.io.InputStream; import java.io.OutputStream; import java.io.IOException; -import java.security.Principal; import java.security.cert.X509Certificate; import java.security.cert.CertificateException; @@ -64,11 +63,6 @@ public final class StartTlsResponseImpl extends StartTlsResponse { private static final boolean debug = false; - /* - * The dNSName type in a subjectAltName extension of an X.509 certificate - */ - private static final int DNSNAME_TYPE = 2; - /* * The server's hostname. */ @@ -111,9 +105,9 @@ public final class StartTlsResponseImpl extends StartTlsResponse { private transient HostnameVerifier verifier = null; /* - * The flag to indicate that the TLS connection is closed. + * The flag to indicate that close() was invoked */ - private transient boolean isClosed = true; + private transient boolean closed; private static final long serialVersionUID = -1126624615143411328L; @@ -133,6 +127,7 @@ public final class StartTlsResponseImpl extends StartTlsResponse { * enable. * @see #negotiate */ + @Override public void setEnabledCipherSuites(String[] suites) { // The impl does accept null suites, although the spec requires // a non-null list. @@ -150,6 +145,7 @@ public final class StartTlsResponseImpl extends StartTlsResponse { * @param verifier The non-null hostname verifier callback. * @see #negotiate */ + @Override public void setHostnameVerifier(HostnameVerifier verifier) { this.verifier = verifier; } @@ -165,6 +161,7 @@ public final class StartTlsResponseImpl extends StartTlsResponse { * @see #setEnabledCipherSuites * @see #setHostnameVerifier */ + @Override public SSLSession negotiate() throws IOException { return negotiate(null); @@ -200,9 +197,10 @@ public final class StartTlsResponseImpl extends StartTlsResponse { * @see #setEnabledCipherSuites * @see #setHostnameVerifier */ + @Override public SSLSession negotiate(SSLSocketFactory factory) throws IOException { - if (isClosed && sslSocket != null) { + if (closed) { throw new IOException("TLS connection is closed."); } @@ -223,7 +221,6 @@ public final class StartTlsResponseImpl extends StartTlsResponse { SSLPeerUnverifiedException verifExcep = null; try { if (verify(hostname, sslSession)) { - isClosed = false; return sslSession; } } catch (SSLPeerUnverifiedException e) { @@ -232,18 +229,18 @@ public final class StartTlsResponseImpl extends StartTlsResponse { } if ((verifier != null) && verifier.verify(hostname, sslSession)) { - isClosed = false; return sslSession; } - // Verification failed - close(); - sslSession.invalidate(); if (verifExcep == null) { - verifExcep = new SSLPeerUnverifiedException( - "hostname of the server '" + hostname + - "' does not match the hostname in the " + - "server's certificate."); + verifExcep = new SSLPeerUnverifiedException("hostname of the server '" + + hostname + "' does not match the hostname in the server's certificate."); + } + sslSession.invalidate(); + try { + close(); + } catch (IOException ioe) { + verifExcep.addSuppressed(ioe); } throw verifExcep; } @@ -255,15 +252,13 @@ public final class StartTlsResponseImpl extends StartTlsResponse { * @throws IOException If an IO error was encountered while closing the * TLS connection */ + @Override public void close() throws IOException { - - if (isClosed) { + if (closed) { return; } - if (debug) { - System.out.println("StartTLS: replacing SSL " + - "streams with originals"); + System.out.println("StartTLS: closing"); } // Replace SSL streams with the original streams @@ -273,9 +268,13 @@ public final class StartTlsResponseImpl extends StartTlsResponse { if (debug) { System.out.println("StartTLS: closing SSL Socket"); } - sslSocket.close(); - - isClosed = true; + try { + if (sslSocket != null) { + sslSocket.close(); + } + } finally { + closed = true; + } } /** @@ -298,9 +297,8 @@ public final class StartTlsResponseImpl extends StartTlsResponse { * Returns the default SSL socket factory. * * @return The default SSL socket factory. - * @throws IOException If TLS is not supported. */ - private SSLSocketFactory getDefaultFactory() throws IOException { + private SSLSocketFactory getDefaultFactory() { if (defaultFactory != null) { return defaultFactory; @@ -370,9 +368,13 @@ public final class StartTlsResponseImpl extends StartTlsResponse { System.out.println("StartTLS: Got IO error during handshake"); e.printStackTrace(); } - - sslSocket.close(); - isClosed = true; + try { + close(); + } catch (IOException ioe) { + if (e != ioe) { + e.addSuppressed(ioe); + } + } throw e; // pass up exception } @@ -441,20 +443,4 @@ public final class StartTlsResponseImpl extends StartTlsResponse { "server's certificate.", e); } } - - /* - * Get the peer principal from the session - */ - private static Principal getPeerPrincipal(SSLSession session) - throws SSLPeerUnverifiedException { - Principal principal; - try { - principal = session.getPeerPrincipal(); - } catch (AbstractMethodError e) { - // if the JSSE provider does not support it, return null, since - // we need it only for Kerberos. - principal = null; - } - return principal; - } } diff --git a/src/java.net.http/share/classes/jdk/internal/net/http/common/SSLFlowDelegate.java b/src/java.net.http/share/classes/jdk/internal/net/http/common/SSLFlowDelegate.java index c662983d0af..e7dec5a6963 100644 --- a/src/java.net.http/share/classes/jdk/internal/net/http/common/SSLFlowDelegate.java +++ b/src/java.net.http/share/classes/jdk/internal/net/http/common/SSLFlowDelegate.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -273,7 +273,7 @@ public class SSLFlowDelegate { final SequentialScheduler scheduler; volatile ByteBuffer readBuf; - volatile boolean completing; + boolean completing; final ReentrantLock readBufferLock = new ReentrantLock(); final Logger debugr = Utils.getDebugLogger(this::dbgString, Utils.DEBUG); @@ -301,6 +301,11 @@ public class SSLFlowDelegate { return enterReadScheduling(); } + @Override + public boolean closing() { + return closeNotifyReceived(); + } + public final String dbgString() { return "SSL Reader(" + tubeName + ")"; } @@ -505,7 +510,7 @@ public class SSLFlowDelegate { if (result.handshaking()) { handshaking = true; if (debugr.on()) debugr.log("handshaking"); - if (doHandshake(result, READER)) continue; // need unwrap + if (doHandshake(result.handshakeStatus(), READER)) continue; // need unwrap else break; // doHandshake will have triggered the write scheduler if necessary } else { if (trySetALPN()) { @@ -550,6 +555,7 @@ public class SSLFlowDelegate { private volatile Status lastUnwrapStatus; EngineResult unwrapBuffer(ByteBuffer src) throws IOException { + assert readBufferLock.isHeldByCurrentThread(); ByteBuffer dst = getAppBuffer(); int len = src.remaining(); while (true) { @@ -573,6 +579,8 @@ public class SSLFlowDelegate { break; case CLOSED: assert dst.position() == 0; + src.position(src.limit()); + completing = true; return doClosure(new EngineResult(sslResult)); case BUFFER_UNDERFLOW: // handled implicitly by compaction/reallocation of readBuf @@ -834,7 +842,7 @@ public class SSLFlowDelegate { boolean handshaking = false; if (result.handshaking()) { if (debugw.on()) debugw.log("handshaking"); - doHandshake(result, WRITER); // ok to ignore return + doHandshake(result.handshakeStatus(), WRITER); // ok to ignore return handshaking = true; } else { if (trySetALPN()) { @@ -1090,14 +1098,14 @@ public class SSLFlowDelegate { return (current & HANDSHAKING); }; - private boolean doHandshake(EngineResult r, int caller) { + private boolean doHandshake(HandshakeStatus handshakeStatus, int caller) { // unconditionally sets the HANDSHAKING bit, while preserving task bits handshakeState.getAndAccumulate(0, (current, unused) -> HANDSHAKING | (current & TASK_BITS)); if (stateList != null && debug.on()) { - stateList.add(r.handshakeStatus().toString()); + stateList.add(handshakeStatus.toString()); stateList.add(Integer.toString(caller)); } - switch (r.handshakeStatus()) { + switch (handshakeStatus) { case NEED_TASK: int s = handshakeState.accumulateAndGet(0, REQUEST_OR_DO_TASKS); if ((s & REQUESTING_TASKS) > 0) { // someone else is or will do tasks @@ -1125,7 +1133,7 @@ public class SSLFlowDelegate { break; default: throw new InternalError("Unexpected handshake status:" - + r.handshakeStatus()); + + handshakeStatus); } return true; } @@ -1182,34 +1190,20 @@ public class SSLFlowDelegate { return false; } - // FIXME: acknowledge a received CLOSE request from peer EngineResult doClosure(EngineResult r) throws IOException { if (debug.on()) debug.log("doClosure(%s): %s [isOutboundDone: %s, isInboundDone: %s]", r.result, engine.getHandshakeStatus(), engine.isOutboundDone(), engine.isInboundDone()); + if (debug.on()) debug.log("doClosure: close_notify received"); + close_notify_received = true; + engine.closeOutbound(); if (engine.getHandshakeStatus() == HandshakeStatus.NEED_WRAP) { // we have received TLS close_notify and need to send // an acknowledgement back. We're calling doHandshake // to finish the close handshake. - if (engine.isInboundDone() && !engine.isOutboundDone()) { - if (debug.on()) debug.log("doClosure: close_notify received"); - close_notify_received = true; - if (!writer.scheduler.isStopped()) { - doHandshake(r, READER); - } else { - // We have received closed notify, but we - // won't be able to send the acknowledgement. - // Nothing more will come from the socket either, - // so mark the reader as completed. - var readerLock = reader.readBufferLock; - readerLock.lock(); - try { - reader.completing = true; - } finally { - readerLock.unlock(); - } - } + if (!writer.scheduler.isStopped()) { + doHandshake(HandshakeStatus.NEED_WRAP, READER); } } return r; diff --git a/src/java.net.http/share/classes/jdk/internal/net/http/common/SubscriberWrapper.java b/src/java.net.http/share/classes/jdk/internal/net/http/common/SubscriberWrapper.java index b9e1def58e0..013ed31c8c1 100644 --- a/src/java.net.http/share/classes/jdk/internal/net/http/common/SubscriberWrapper.java +++ b/src/java.net.http/share/classes/jdk/internal/net/http/common/SubscriberWrapper.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -459,7 +459,7 @@ public abstract class SubscriberWrapper } void checkCompletion() { - if (downstreamCompleted || !upstreamCompleted) { + if (downstreamCompleted || (!upstreamCompleted && !completionAcknowledged)) { return; } if (!outputQ.isEmpty()) { diff --git a/src/java.security.jgss/share/classes/sun/security/krb5/internal/crypto/dk/AesDkCrypto.java b/src/java.security.jgss/share/classes/sun/security/krb5/internal/crypto/dk/AesDkCrypto.java index 1f6e98e50e8..f04f28ae134 100644 --- a/src/java.security.jgss/share/classes/sun/security/krb5/internal/crypto/dk/AesDkCrypto.java +++ b/src/java.security.jgss/share/classes/sun/security/krb5/internal/crypto/dk/AesDkCrypto.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2004, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -118,14 +118,7 @@ public class AesDkCrypto extends DkCrypto { private byte[] stringToKey(char[] secret, byte[] salt, byte[] params) throws GeneralSecurityException { - int iter_count = DEFAULT_ITERATION_COUNT; - if (params != null) { - if (params.length != 4) { - throw new RuntimeException("Invalid parameter to stringToKey"); - } - iter_count = readBigEndian(params, 0, 4); - } - + int iter_count = DkCrypto.iterationCount(params, DEFAULT_ITERATION_COUNT); byte[] tmpKey = randomToKey(PBKDF2(secret, salt, iter_count, getKeySeedLength())); byte[] result = dk(tmpKey, KERBEROS_CONSTANT); @@ -485,17 +478,4 @@ public class AesDkCrypto extends DkCrypto { return result; } - - public static final int readBigEndian(byte[] data, int pos, int size) { - int retVal = 0; - int shifter = (size-1)*8; - while (size > 0) { - retVal += (data[pos] & 0xff) << shifter; - shifter -= 8; - pos++; - size--; - } - return retVal; - } - } diff --git a/src/java.security.jgss/share/classes/sun/security/krb5/internal/crypto/dk/AesSha2DkCrypto.java b/src/java.security.jgss/share/classes/sun/security/krb5/internal/crypto/dk/AesSha2DkCrypto.java index cb9e42b2dee..5af0517f883 100644 --- a/src/java.security.jgss/share/classes/sun/security/krb5/internal/crypto/dk/AesSha2DkCrypto.java +++ b/src/java.security.jgss/share/classes/sun/security/krb5/internal/crypto/dk/AesSha2DkCrypto.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -122,14 +122,7 @@ public class AesSha2DkCrypto extends DkCrypto { private byte[] stringToKey(char[] secret, byte[] salt, byte[] params) throws GeneralSecurityException { - int iter_count = DEFAULT_ITERATION_COUNT; - if (params != null) { - if (params.length != 4) { - throw new RuntimeException("Invalid parameter to stringToKey"); - } - iter_count = readBigEndian(params, 0, 4); - } - + int iter_count = DkCrypto.iterationCount(params, DEFAULT_ITERATION_COUNT); byte[] saltp = new byte[26 + 1 + salt.length]; if (keyLength == 128) { System.arraycopy(ETYPE_NAME_128, 0, saltp, 0, 26); @@ -525,17 +518,4 @@ public class AesSha2DkCrypto extends DkCrypto { return result; } - - public static final int readBigEndian(byte[] data, int pos, int size) { - int retVal = 0; - int shifter = (size-1)*8; - while (size > 0) { - retVal += (data[pos] & 0xff) << shifter; - shifter -= 8; - pos++; - size--; - } - return retVal; - } - } diff --git a/src/java.security.jgss/share/classes/sun/security/krb5/internal/crypto/dk/DkCrypto.java b/src/java.security.jgss/share/classes/sun/security/krb5/internal/crypto/dk/DkCrypto.java index da327814592..260f30bd000 100644 --- a/src/java.security.jgss/share/classes/sun/security/krb5/internal/crypto/dk/DkCrypto.java +++ b/src/java.security.jgss/share/classes/sun/security/krb5/internal/crypto/dk/DkCrypto.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2004, 2025, Oracle and/or its affiliates. All rights reserved. */ /* @@ -31,8 +31,8 @@ package sun.security.krb5.internal.crypto.dk; import javax.crypto.Cipher; -import javax.crypto.Mac; import java.security.GeneralSecurityException; +import java.security.InvalidAlgorithmParameterException; import java.util.Arrays; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; @@ -692,4 +692,41 @@ public abstract class DkCrypto { bb.get(answer, 0, len); return answer; } + + static int iterationCount(byte[] params, int defaultValue) + throws InvalidAlgorithmParameterException { + if (params == null) { + return defaultValue; + } + if (params.length != 4) { + throw new InvalidAlgorithmParameterException("Invalid params"); + } + if (params[0] != 0 || ((params[1] & 0xff) >= 80)) { + // IC should be less than 80 * 2^16. This is roughly + // the same as PKCS12KeyStore's 5_000_000 limit. + throw new InvalidAlgorithmParameterException( + "Incoming iteration count is too big"); + } + int iter_count = readBigEndian(params, 0, 4); + if (!ALLOW_WEAK_PBKDF2_ITERATION_COUNT && iter_count < defaultValue) { + throw new InvalidAlgorithmParameterException( + "Incoming iteration count is too small"); + } + return iter_count; + } + + public static final int readBigEndian(byte[] data, int pos, int size) { + int retVal = 0; + int shifter = (size-1)*8; + while (size > 0) { + retVal += (data[pos] & 0xff) << shifter; + shifter -= 8; + pos++; + size--; + } + return retVal; + } + + // Only used by test + public static boolean ALLOW_WEAK_PBKDF2_ITERATION_COUNT = false; } diff --git a/src/java.xml/share/classes/com/sun/org/apache/xpath/internal/jaxp/XPathExpressionImpl.java b/src/java.xml/share/classes/com/sun/org/apache/xpath/internal/jaxp/XPathExpressionImpl.java index e3f25731e6d..d6ac228b982 100644 --- a/src/java.xml/share/classes/com/sun/org/apache/xpath/internal/jaxp/XPathExpressionImpl.java +++ b/src/java.xml/share/classes/com/sun/org/apache/xpath/internal/jaxp/XPathExpressionImpl.java @@ -34,6 +34,8 @@ import javax.xml.xpath.XPathVariableResolver; import jdk.xml.internal.JdkXmlConfig; import jdk.xml.internal.JdkXmlFeatures; +import jdk.xml.internal.XMLSecurityManager; +import jdk.xml.internal.XMLSecurityPropertyManager; import org.w3c.dom.Document; import org.xml.sax.InputSource; @@ -41,7 +43,7 @@ import org.xml.sax.InputSource; * The XPathExpression interface encapsulates a (compiled) XPath expression. * * @author Ramesh Mandava - * @LastModified: May 2025 + * @LastModified: Nov 2025 */ public class XPathExpressionImpl extends XPathImplUtil implements XPathExpression { @@ -51,7 +53,9 @@ public class XPathExpressionImpl extends XPathImplUtil implements XPathExpressio * from the context. */ protected XPathExpressionImpl() { - this(null, null, null, null, false, JdkXmlConfig.getInstance(false).getXMLFeatures(true)); + this(null, null, null, null, false, JdkXmlConfig.getInstance(false).getXMLFeatures(true), + JdkXmlConfig.getInstance(false).getXMLSecurityManager(false), + JdkXmlConfig.getInstance(false).getXMLSecurityPropertyManager(false)); }; protected XPathExpressionImpl(com.sun.org.apache.xpath.internal.XPath xpath, @@ -59,13 +63,16 @@ public class XPathExpressionImpl extends XPathImplUtil implements XPathExpressio XPathFunctionResolver functionResolver, XPathVariableResolver variableResolver) { this(xpath, prefixResolver, functionResolver, variableResolver, - false, JdkXmlConfig.getInstance(false).getXMLFeatures(true)); + false, JdkXmlConfig.getInstance(false).getXMLFeatures(true), + JdkXmlConfig.getInstance(false).getXMLSecurityManager(false), + JdkXmlConfig.getInstance(false).getXMLSecurityPropertyManager(false)); }; protected XPathExpressionImpl(com.sun.org.apache.xpath.internal.XPath xpath, JAXPPrefixResolver prefixResolver,XPathFunctionResolver functionResolver, XPathVariableResolver variableResolver, boolean featureSecureProcessing, - JdkXmlFeatures featureManager) { + JdkXmlFeatures featureManager, XMLSecurityManager xmlSecMgr, + XMLSecurityPropertyManager xmlSecPropMgr) { this.xpath = xpath; this.prefixResolver = prefixResolver; this.functionResolver = functionResolver; @@ -74,6 +81,8 @@ public class XPathExpressionImpl extends XPathImplUtil implements XPathExpressio this.overrideDefaultParser = featureManager.getFeature( JdkXmlFeatures.XmlFeature.JDK_OVERRIDE_PARSER); this.featureManager = featureManager; + this.xmlSecMgr = xmlSecMgr; + this.xmlSecPropMgr = xmlSecPropMgr; }; public void setXPath (com.sun.org.apache.xpath.internal.XPath xpath) { diff --git a/src/java.xml/share/classes/com/sun/org/apache/xpath/internal/jaxp/XPathImpl.java b/src/java.xml/share/classes/com/sun/org/apache/xpath/internal/jaxp/XPathImpl.java index c2faf90ce2e..f62a290557d 100644 --- a/src/java.xml/share/classes/com/sun/org/apache/xpath/internal/jaxp/XPathImpl.java +++ b/src/java.xml/share/classes/com/sun/org/apache/xpath/internal/jaxp/XPathImpl.java @@ -51,7 +51,7 @@ import org.xml.sax.InputSource; * New methods: evaluateExpression * Refactored to share code with XPathExpressionImpl. * - * @LastModified: June 2025 + * @LastModified: Nov 2025 */ public class XPathImpl extends XPathImplUtil implements javax.xml.xpath.XPath { @@ -175,7 +175,8 @@ public class XPathImpl extends XPathImplUtil implements javax.xml.xpath.XPath { // Can have errorListener XPathExpressionImpl ximpl = new XPathExpressionImpl (xpath, prefixResolver, functionResolver, variableResolver, - featureSecureProcessing, featureManager); + featureSecureProcessing, featureManager, + xmlSecMgr, xmlSecPropMgr); return ximpl; } catch (TransformerException te) { throw new XPathExpressionException (te) ; diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Lint.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Lint.java index 773c573c201..776fd544bfb 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Lint.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/code/Lint.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2005, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -37,11 +37,16 @@ import java.util.Set; import java.util.stream.Stream; import com.sun.tools.javac.main.Option; +import com.sun.tools.javac.util.Assert; import com.sun.tools.javac.util.Context; +import com.sun.tools.javac.util.JCDiagnostic; import com.sun.tools.javac.util.Log; import com.sun.tools.javac.util.Names; import com.sun.tools.javac.util.Options; +import static com.sun.tools.javac.util.JCDiagnostic.DiagnosticFlag.DEFAULT_ENABLED; +import static com.sun.tools.javac.util.JCDiagnostic.DiagnosticFlag.DEPRECATION_SENSITIVE; + /** * A class for handling -Xlint suboptions and @SuppressWarnings. * @@ -76,35 +81,20 @@ public class Lint { */ public Lint augment(Symbol sym) { EnumSet suppressions = suppressionsFrom(sym); - if (!suppressions.isEmpty()) { + boolean symWithinDeprecated = withinDeprecated || isDeprecatedDeclaration(sym); + if (!suppressions.isEmpty() || symWithinDeprecated != withinDeprecated) { Lint lint = new Lint(this); lint.values.removeAll(suppressions); lint.suppressedValues.addAll(suppressions); + lint.withinDeprecated = symWithinDeprecated; return lint; } return this; } - /** - * Returns a new Lint that has the given LintCategorys enabled. - * @param lc one or more categories to be enabled - */ - public Lint enable(LintCategory... lc) { - Lint l = new Lint(this); - l.values.addAll(Arrays.asList(lc)); - l.suppressedValues.removeAll(Arrays.asList(lc)); - return l; - } - - /** - * Returns a new Lint that has the given LintCategorys suppressed. - * @param lc one or more categories to be suppressed - */ - public Lint suppress(LintCategory... lc) { - Lint l = new Lint(this); - l.values.removeAll(Arrays.asList(lc)); - l.suppressedValues.addAll(Arrays.asList(lc)); - return l; + // Does sym's declaration have a (non-useless) @Deprecated annotation? + public static boolean isDeprecatedDeclaration(Symbol sym) { + return sym.isDeprecated() && sym.isDeprecatableViaAnnotation(); } private final Context context; @@ -115,9 +105,12 @@ public class Lint { private Symtab syms; private Names names; - // Invariant: it's never the case that a category is in both "values" and "suppressedValues" + // Invariants: + // - It's never the case that a category is in both "values" and "suppressedValues" + // - All categories in "suppressedValues" have annotationSuppression = true private EnumSet values; private EnumSet suppressedValues; + private boolean withinDeprecated; private static final Map map = new LinkedHashMap<>(40); @@ -129,7 +122,7 @@ public class Lint { log = Log.instance(context); } - // Instantiate a non-root ("symbol scoped") instance + // Copy constructor - used to instantiate a non-root ("symbol scoped") instances protected Lint(Lint other) { other.initializeRootIfNeeded(); this.context = other.context; @@ -139,6 +132,7 @@ public class Lint { this.names = other.names; this.values = other.values.clone(); this.suppressedValues = other.suppressedValues.clone(); + this.withinDeprecated = other.withinDeprecated; } // Process command line options on demand to allow use of root Lint early during startup @@ -169,7 +163,7 @@ public class Lint { @Override public String toString() { initializeRootIfNeeded(); - return "Lint:[enable" + values + ",suppress" + suppressedValues + "]"; + return "Lint:[enable" + values + ",suppress" + suppressedValues + ",deprecated=" + withinDeprecated + "]"; } /** @@ -443,6 +437,34 @@ public class Lint { public final boolean enabledByDefault; } + /** + * Determine if the given diagnostic should be emitted given the state of this instance. + */ + public boolean shouldEmit(JCDiagnostic diag) { + + // Check category + LintCategory category = diag.getLintCategory(); + if (category == null) + return true; + + // Certain warnings within @Deprecated declarations are automatically suppressed (JLS 9.6.4.6) + if (withinDeprecated && diag.isFlagSet(DEPRECATION_SENSITIVE)) { + Assert.check(diag.isFlagSet(DEFAULT_ENABLED) && category.annotationSuppression); + return false; + } + + // If the warning is not enabled by default, then emit only when its lint category is explicitly enabled + if (!diag.isFlagSet(DEFAULT_ENABLED)) + return isEnabled(category); + + // If the lint category doesn't support @SuppressWarnings, then we just check the -Xlint:category flag + if (!category.annotationSuppression) + return !options.isDisabled(Option.XLINT, category); + + // Check whether the lint category is currently suppressed + return !isSuppressed(category); + } + /** * Checks if a warning category is enabled. A warning category may be enabled * on the command line, or by default, and can be temporarily disabled with @@ -454,10 +476,11 @@ public class Lint { } /** - * Checks is a warning category has been specifically suppressed, by means - * of the SuppressWarnings annotation, or, in the case of the deprecated - * category, whether it has been implicitly suppressed by virtue of the - * current entity being itself deprecated. + * Check if a warning category has been specifically suppressed by means of @SuppressWarnings. + * + *

+ * Always returns false for categories that are not suppressible by the annotation, even + * if they (uselessly) happen to appear in one. */ public boolean isSuppressed(LintCategory lc) { initializeRootIfNeeded(); @@ -468,17 +491,14 @@ public class Lint { * Obtain the set of recognized lint warning categories suppressed at the given symbol's declaration. * *

- * This set can be non-empty only if the symbol is annotated with either - * @SuppressWarnings or @Deprecated. + * This set can be non-empty only if the symbol is annotated with @SuppressWarnings, and only categories + * for which {@code annotationSuppression} is true are included. * * @param symbol symbol corresponding to a possibly-annotated declaration * @return new warning suppressions applied to sym */ public EnumSet suppressionsFrom(Symbol symbol) { - EnumSet suppressions = suppressionsFrom(symbol.getDeclarationAttributes().stream()); - if (symbol.isDeprecated() && symbol.isDeprecatableViaAnnotation()) - suppressions.add(LintCategory.DEPRECATION); - return suppressions; + return suppressionsFrom(symbol.getDeclarationAttributes().stream()); } // Find the @SuppressWarnings annotation in the given stream and extract the recognized suppressions diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/ArgumentAttr.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/ArgumentAttr.java index 9b78a02170c..a44b2f96867 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/ArgumentAttr.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/ArgumentAttr.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -565,7 +565,7 @@ public class ArgumentAttr extends JCTree.Visitor { Type lambdaType = targetInfo.descriptor; Type currentTarget = targetInfo.target; //check compatibility - checkLambdaCompatible(lambdaType, resultInfo); + checkLambdaCompatible(lambdaType, currentTarget, resultInfo); return currentTarget; } catch (FunctionDescriptorLookupError ex) { resultInfo.checkContext.report(null, ex.getDiagnostic()); @@ -574,7 +574,7 @@ public class ArgumentAttr extends JCTree.Visitor { } /** Check lambda against given target result */ - private void checkLambdaCompatible(Type descriptor, ResultInfo resultInfo) { + private void checkLambdaCompatible(Type descriptor, Type target, ResultInfo resultInfo) { CheckContext checkContext = resultInfo.checkContext; ResultInfo bodyResultInfo = attr.lambdaBodyResult(speculativeTree, descriptor, resultInfo); switch (speculativeTree.getBodyKind()) { @@ -588,7 +588,7 @@ public class ArgumentAttr extends JCTree.Visitor { break; } - attr.checkLambdaCompatible(speculativeTree, descriptor, checkContext); + attr.checkLambdaCompatible(speculativeTree, descriptor, target.tsym, checkContext); } /** 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 89ae68e85ba..7b589b9fa0b 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 @@ -1342,9 +1342,9 @@ public class Attr extends JCTree.Visitor { private void doQueueScanTreeAndTypeAnnotateForVarInit(JCVariableDecl tree, Env env) { if (tree.init != null && - (tree.mods.flags & Flags.FIELD_INIT_TYPE_ANNOTATIONS_QUEUED) == 0 && + (tree.sym.flags_field & Flags.FIELD_INIT_TYPE_ANNOTATIONS_QUEUED) == 0 && env.info.scope.owner.kind != MTH && env.info.scope.owner.kind != VAR) { - tree.mods.flags |= Flags.FIELD_INIT_TYPE_ANNOTATIONS_QUEUED; + tree.sym.flags_field |= Flags.FIELD_INIT_TYPE_ANNOTATIONS_QUEUED; // Field initializer expression need to be entered. annotate.queueScanTreeAndTypeAnnotate(tree.init, env, tree.sym); annotate.flush(); @@ -3241,7 +3241,7 @@ public class Attr extends JCTree.Visitor { attribStats(that.params, localEnv); if (arityMismatch) { - resultInfo.checkContext.report(that, diags.fragment(Fragments.IncompatibleArgTypesInLambda)); + resultInfo.checkContext.report(that, diags.fragment(Fragments.WrongNumberArgsInLambda(currentTarget.tsym))); result = that.type = types.createErrorType(currentTarget); return; } @@ -3274,7 +3274,7 @@ public class Attr extends JCTree.Visitor { flow.analyzeLambda(env, that, make, isSpeculativeRound); that.type = currentTarget; //avoids recovery at this stage - checkLambdaCompatible(that, lambdaType, resultInfo.checkContext); + checkLambdaCompatible(that, lambdaType, currentTarget.tsym, resultInfo.checkContext); if (!isSpeculativeRound) { //add thrown types as bounds to the thrown types free variables if needed: @@ -3550,7 +3550,7 @@ public class Attr extends JCTree.Visitor { * (i) parameter types must be identical to those of the target descriptor; (ii) return * types must be compatible with the return type of the expected descriptor. */ - void checkLambdaCompatible(JCLambda tree, Type descriptor, CheckContext checkContext) { + void checkLambdaCompatible(JCLambda tree, Type descriptor, TypeSymbol target, CheckContext checkContext) { Type returnType = checkContext.inferenceContext().asUndetVar(descriptor.getReturnType()); //return values have already been checked - but if lambda has no return @@ -3567,7 +3567,9 @@ public class Attr extends JCTree.Visitor { List argTypes = checkContext.inferenceContext().asUndetVars(descriptor.getParameterTypes()); if (!types.isSameTypes(argTypes, TreeInfo.types(tree.params))) { - checkContext.report(tree, diags.fragment(Fragments.IncompatibleArgTypesInLambda)); + checkContext.report(tree, diags.fragment(argTypes.size() != tree.params.size() + ? Fragments.WrongNumberArgsInLambda(target) + : Fragments.IncompatibleArgTypesInLambda(argTypes, TreeInfo.types(tree.params)))); } } diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/DeferredAttr.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/DeferredAttr.java index d16bbf2a2ee..89422ac4671 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/DeferredAttr.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/DeferredAttr.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -427,7 +427,7 @@ public class DeferredAttr extends JCTree.Visitor { ListBuffer stats = new ListBuffer<>(); stats.addAll(that.params); if (that.getBodyKind() == JCLambda.BodyKind.EXPRESSION) { - stats.add(make.Return((JCExpression)that.body)); + stats.add(make.at(that.pos).Return((JCExpression)that.body)); } else { stats.add((JCBlock)that.body); } @@ -444,7 +444,7 @@ public class DeferredAttr extends JCTree.Visitor { if (lambdaBody.hasTag(Tag.RETURN)) { lambdaBody = ((JCReturn)lambdaBody).expr; } - JCLambda speculativeLambda = make.Lambda(args, lambdaBody); + JCLambda speculativeLambda = make.at(that.pos).Lambda(args, lambdaBody); attr.preFlow(speculativeLambda); flow.analyzeLambda(env, speculativeLambda, make, false); return speculativeLambda; @@ -845,7 +845,7 @@ public class DeferredAttr extends JCTree.Visitor { if (descriptorType.getParameterTypes().length() != tree.params.length()) { checkContext.report(tree, - diags.fragment(Fragments.IncompatibleArgTypesInLambda)); + diags.fragment(Fragments.WrongNumberArgsInLambda(pt.tsym))); } Type currentReturnType = descriptorType.getReturnType(); diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Infer.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Infer.java index f5e9bfcd7a8..6021dbd7057 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Infer.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Infer.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -635,7 +635,7 @@ public class Infer { //in the functional interface descriptors) List descParameterTypes = types.findDescriptorType(formalInterface).getParameterTypes(); if (descParameterTypes.size() != paramTypes.size()) { - checkContext.report(pos, diags.fragment(Fragments.IncompatibleArgTypesInLambda)); + checkContext.report(pos, diags.fragment(Fragments.WrongNumberArgsInLambda(funcInterface.tsym))); return types.createErrorType(funcInterface); } for (Type p : descParameterTypes) { diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/main/JavaCompiler.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/main/JavaCompiler.java index 269d2f5de62..56dfd395aed 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/main/JavaCompiler.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/main/JavaCompiler.java @@ -440,7 +440,7 @@ public class JavaCompiler { options.isSet(G_CUSTOM, "lines"); devVerbose = options.isSet("dev"); processPcks = options.isSet("process.packages"); - werrorAny = options.isSet(WERROR) || options.isSet(WERROR_CUSTOM, Option.LINT_CUSTOM_ALL); + werrorNonLint = options.isSet(WERROR) || options.isSet(WERROR_CUSTOM, Option.LINT_CUSTOM_ALL); werrorLint = options.getLintCategoriesOf(WERROR, LintCategory::newEmptySet); verboseCompilePolicy = options.isSet("verboseCompilePolicy"); @@ -510,9 +510,9 @@ public class JavaCompiler { */ protected boolean processPcks; - /** Switch: treat any kind of warning (lint or non-lint) as an error. + /** Switch: treat non-lint warnings as errors. Set by either "-Werror" or "-Werror:all". */ - protected boolean werrorAny; + protected boolean werrorNonLint; /** Switch: treat lint warnings in the specified {@link LintCategory}s as errors. */ @@ -583,7 +583,7 @@ public class JavaCompiler { public int errorCount() { log.reportOutstandingWarnings(); if (log.nerrors == 0 && log.nwarnings > 0 && - (werrorAny || werrorLint.clone().removeAll(log.lintWarnings))) { + ((werrorNonLint && log.nonLintWarnings > 0) || werrorLint.clone().removeAll(log.lintWarnings))) { log.error(Errors.WarningsAndWerror); } return log.nerrors; @@ -593,7 +593,7 @@ public class JavaCompiler { * Should warnings in the given lint category be treated as errors due to a {@code -Werror} flag? */ public boolean isWerror(LintCategory lc) { - return werrorAny || werrorLint.contains(lc); + return werrorLint.contains(lc); } protected final Queue stopIfError(CompileState cs, Queue queue) { diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/compiler.properties b/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/compiler.properties index 58a5333ce4c..1ae2c9de35a 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/compiler.properties +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/resources/compiler.properties @@ -996,8 +996,15 @@ compiler.err.lambda.body.neither.value.nor.void.compatible=\ compiler.err.incompatible.thrown.types.in.mref=\ incompatible thrown types {0} in functional expression +# 0: list of type or message segment, 1: list of type or message segment compiler.misc.incompatible.arg.types.in.lambda=\ - incompatible parameter types in lambda expression + incompatible parameter types in lambda expression\n\ + required: {0}\n\ + found: {1} + +# 0: symbol +compiler.misc.wrong.number.args.in.lambda=\ + wrong number of parameters in lambda expression for functional interface {0} compiler.misc.incompatible.arg.types.in.mref=\ incompatible parameter types in method reference @@ -1960,7 +1967,7 @@ compiler.warn.incubating.modules=\ # 0: symbol, 1: symbol # lint: deprecation -# flags: aggregate, mandatory, default-enabled +# flags: aggregate, mandatory, default-enabled, deprecation-sensitive compiler.warn.has.been.deprecated=\ {0} in {1} has been deprecated diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/util/JCDiagnostic.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/util/JCDiagnostic.java index 328183c0cb3..aed42f7b2b2 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/util/JCDiagnostic.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/util/JCDiagnostic.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -436,6 +436,10 @@ public class JCDiagnostic implements Diagnostic { * is not explicitly enabled, as long as it is not explicitly suppressed. */ DEFAULT_ENABLED, + /** Flag for warnings that are automatically suppressed when they occur inside + * a declaration that is itself annotated as @Deprecated. See JLS 9.6.4.6. + */ + DEPRECATION_SENSITIVE, /** Flags mandatory warnings that should pass through a mandatory warning aggregator. */ AGGREGATE, diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/util/Log.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/util/Log.java index b061d2283a0..dd4e14d373d 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/util/Log.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/util/Log.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -174,16 +174,8 @@ public class Log extends AbstractLog { } // Apply the lint configuration (if any) and discard the warning if it gets filtered out - if (lint != null) { - LintCategory category = diag.getLintCategory(); - boolean emit = !diag.isFlagSet(DEFAULT_ENABLED) ? // is the warning not enabled by default? - lint.isEnabled(category) : // then emit if the category is enabled - category.annotationSuppression ? // else emit if the category is not suppressed, where - !lint.isSuppressed(category) : // ...suppression happens via @SuppressWarnings - !options.isDisabled(Option.XLINT, category); // ...suppression happens via -Xlint:-category - if (!emit) - return; - } + if (lint != null && !lint.shouldEmit(diag)) + return; // Proceed reportReady(diag); @@ -566,6 +558,10 @@ public class Log extends AbstractLog { */ public int nwarnings = 0; + /** The total number of non-lint warnings encountered so far. + */ + public int nonLintWarnings = 0; + /** Tracks whether any warnings have been encountered in each {@link LintCategory}. */ public final EnumSet lintWarnings = LintCategory.newEmptySet(); @@ -896,6 +892,7 @@ public class Log extends AbstractLog { lintWarnings.clear(); nerrors = 0; nwarnings = 0; + nonLintWarnings = 0; nsuppressederrors = 0; nsuppressedwarns = 0; while (diagnosticHandler.prev != null) @@ -989,7 +986,7 @@ public class Log extends AbstractLog { nwarnings++; Optional.of(diag) .map(JCDiagnostic::getLintCategory) - .ifPresent(lintWarnings::add); + .ifPresentOrElse(lintWarnings::add, () -> nonLintWarnings++); break; case ERROR: nerrors++; @@ -1129,6 +1126,7 @@ public class Log extends AbstractLog { } prompt(); nwarnings++; + nonLintWarnings++; warnWriter.flush(); } diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/interpreter/Bytecodes.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/interpreter/Bytecodes.java index 1e061568bc4..d661eb0eb2c 100644 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/interpreter/Bytecodes.java +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/interpreter/Bytecodes.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -401,7 +401,11 @@ public class Bytecodes { public static boolean isZeroConst (int code) { return (code == _aconst_null || code == _iconst_0 || code == _fconst_0 || code == _dconst_0); } - public static boolean isFieldCode (int code) { return (_getstatic <= code && code <= _putfield); } + public static boolean isFieldCode (int code) { + return (_getstatic <= code && code <= _putfield) || + (_fast_agetfield <= code && code <= _fast_sputfield) || + (_nofast_getfield <= code && code <= _nofast_putfield); + } static int flags (int code, boolean is_wide) { assert code == (code & 0xff) : "must be a byte"; diff --git a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/JavaTypeProfile.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/JavaTypeProfile.java index 8827017df6d..5ee9db58cfe 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/JavaTypeProfile.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/JavaTypeProfile.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2011, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2011, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -147,7 +147,7 @@ public final class JavaTypeProfile extends AbstractJavaProfile - * Only the {@linkplain Modifier#fieldModifiers() field flags} specified in the JVM + * Only the {@linkplain Location#FIELD field flags} specified in the JVM * specification will be included in the returned mask. */ @Override diff --git a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/ResolvedJavaMethod.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/ResolvedJavaMethod.java index dcd80170ba9..75ca31ce8b3 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/ResolvedJavaMethod.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/meta/ResolvedJavaMethod.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2009, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -305,9 +305,9 @@ public interface ResolvedJavaMethod extends JavaMethod, InvokeTarget, ModifiersP typename = typename.replaceFirst("\\[\\]$", "..."); } - final StringBuilder sb = new StringBuilder(Modifier.toString(getModifiers())); - if (sb.length() != 0) { - sb.append(' '); + final StringBuilder sb = new StringBuilder(); + if (Modifier.isFinal(getModifiers())) { + sb.append("final "); } return sb.append(typename).append(' ').append(getName()).toString(); } diff --git a/src/jdk.jdeps/share/classes/com/sun/tools/javap/AttributeWriter.java b/src/jdk.jdeps/share/classes/com/sun/tools/javap/AttributeWriter.java index 8b7ac158639..6f7463a4498 100644 --- a/src/jdk.jdeps/share/classes/com/sun/tools/javap/AttributeWriter.java +++ b/src/jdk.jdeps/share/classes/com/sun/tools/javap/AttributeWriter.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -221,7 +221,7 @@ public class AttributeWriter extends BasicWriter { for (var flag : maskToAccessFlagsReportUnknown(access_flags, AccessFlag.Location.INNER_CLASS, cffv)) { if (flag.sourceModifier() && (flag != AccessFlag.ABSTRACT || !info.has(AccessFlag.INTERFACE))) { - print(Modifier.toString(flag.mask()) + " "); + print(flag.name().toLowerCase(Locale.ROOT) + " "); } } if (info.innerName().isPresent()) { diff --git a/src/jdk.jdeps/share/classes/com/sun/tools/javap/ClassWriter.java b/src/jdk.jdeps/share/classes/com/sun/tools/javap/ClassWriter.java index c5c75d8848c..1067dd0d6cb 100644 --- a/src/jdk.jdeps/share/classes/com/sun/tools/javap/ClassWriter.java +++ b/src/jdk.jdeps/share/classes/com/sun/tools/javap/ClassWriter.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -52,6 +52,7 @@ import java.util.Date; import java.util.EnumSet; import java.util.LinkedHashSet; import java.util.List; +import java.util.Locale; import java.util.Set; import static java.lang.classfile.ClassFile.*; @@ -434,8 +435,7 @@ public class ClassWriter extends BasicWriter { return; var flags = f.flags(); - writeModifiers(flagsReportUnknown(flags, cffv()).stream().filter(fl -> fl.sourceModifier()) - .map(fl -> Modifier.toString(fl.mask())).toList()); + writeModifiers(getModifiers(flagsReportUnknown(flags, cffv()))); print(() -> sigPrinter.print( f.findAttribute(Attributes.signature()) .map(SignatureAttribute::asTypeSignature) @@ -494,9 +494,7 @@ public class ClassWriter extends BasicWriter { int flags = m.flags().flagsMask(); - var modifiers = new ArrayList(); - for (var f : flagsReportUnknown(m.flags(), cffv())) - if (f.sourceModifier()) modifiers.add(Modifier.toString(f.mask())); + var modifiers = getModifiers(flagsReportUnknown(m.flags(), cffv())); String name = "???"; try { @@ -815,7 +813,7 @@ public class ClassWriter extends BasicWriter { private static Set getModifiers(Set flags) { Set s = new LinkedHashSet<>(); for (var f : flags) - if (f.sourceModifier()) s.add(Modifier.toString(f.mask())); + if (f.sourceModifier()) s.add(f == AccessFlag.STRICT ? "strictfp" : f.name().toLowerCase(Locale.ROOT)); return s; } diff --git a/src/jdk.jdwp.agent/share/native/libjdwp/log_messages.c b/src/jdk.jdwp.agent/share/native/libjdwp/log_messages.c index e24fcd57156..c6d878fa8fd 100644 --- a/src/jdk.jdwp.agent/share/native/libjdwp/log_messages.c +++ b/src/jdk.jdwp.agent/share/native/libjdwp/log_messages.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -90,8 +90,8 @@ get_time_stamp(char *tbuf, size_t ltbuf) static const char * file_basename(const char *file) { - char *p1; - char *p2; + const char* p1; + const char* p2; if ( file==NULL ) return "unknown"; diff --git a/src/jdk.jfr/share/classes/jdk/jfr/Period.java b/src/jdk.jfr/share/classes/jdk/jfr/Period.java index 97d4676e6a5..dcf673df8bc 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/Period.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/Period.java @@ -54,7 +54,7 @@ public @interface Period { /** * Returns the default setting value for a periodic setting. *

- * String representation of a positive {@code Long} value followed by an empty + * String representation of a positive {@code long} value followed by an empty * space and one of the following units:
*
* {@code "ns"} (nanoseconds)
diff --git a/src/jdk.jfr/share/classes/jdk/jfr/Threshold.java b/src/jdk.jfr/share/classes/jdk/jfr/Threshold.java index 92c40823bbb..b980e765981 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/Threshold.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/Threshold.java @@ -50,7 +50,7 @@ public @interface Threshold { /** * The threshold (for example, {@code "20 ms"}). *

- * A {@code String} representation of a positive {@code Long} value followed by an + * A {@code String} representation of a positive {@code long} value followed by an * empty space and one of the following units:
*
* {@code "ns"} (nanoseconds)
diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/Cutoff.java b/src/jdk.jfr/share/classes/jdk/jfr/internal/Cutoff.java index a00a71b3531..cc1426025d0 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/internal/Cutoff.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/Cutoff.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -55,7 +55,7 @@ public @interface Cutoff { /** * Cutoff, for example {@code "20 ms"}. *

- * String representation of a positive {@code Long} value followed by an empty + * String representation of a positive {@code long} value followed by an empty * space and one of the following units
*
* {@code "ns"} (nanoseconds)
diff --git a/src/jdk.jfr/share/classes/jdk/jfr/package-info.java b/src/jdk.jfr/share/classes/jdk/jfr/package-info.java index 812525e0ff4..2ba7aa5db30 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/package-info.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/package-info.java @@ -119,7 +119,7 @@ * {@code enabled} * Specifies whether the event is recorded * {@code "true"} - * String representation of a {@code Boolean} ({@code "true"} or + * String representation of a {@code boolean} ({@code "true"} or * {@code "false"}) * {@code "true"}
* {@code "false"} @@ -129,7 +129,7 @@ * Specifies the duration below which an event is not recorded * {@code "0"} (no limit) * {@code "0"} if no threshold is used, otherwise a string representation of - * a positive {@code Long} followed by a space and one of the following units: + * a positive {@code long} followed by a space and one of the following units: *

    *
  • {@code "ns"} (nanoseconds) *
  • {@code "us"} (microseconds) @@ -149,7 +149,7 @@ * periodic * {@code "everyChunk"} * {@code "everyChunk"}, if a periodic event should be emitted with every - * file rotation, otherwise a string representation of a positive {@code Long} + * file rotation, otherwise a string representation of a positive {@code long} * value followed by an empty space and one of the following units: *
      *
    • {@code "ns"} (nanoseconds) @@ -171,7 +171,7 @@ * Specifies whether the stack trace from the {@link Event#commit()} method * is recorded * {@code "true"} - * String representation of a {@code Boolean} ({@code "true"} or + * String representation of a {@code boolean} ({@code "true"} or * {@code "false"}) * {@code "true"},
      * {@code "false"} @@ -181,7 +181,7 @@ * Specifies the maximum rate of events per time unit. * {@code "off"} (no throttling) * - * "off", if events should not be throttled, otherwise a string representation of a positive {@code Long} value followed by forward slash ("/") and one of the following units: + * "off", if events should not be throttled, otherwise a string representation of a positive {@code long} value followed by forward slash ("/") and one of the following units: *
        *
      • {@code "ns"} (nanoseconds) *
      • {@code "us"} (microseconds) diff --git a/src/jdk.jpackage/linux/native/applauncher/LinuxPackage.c b/src/jdk.jpackage/linux/native/applauncher/LinuxPackage.c index 26d65f8061c..d346e241035 100644 --- a/src/jdk.jpackage/linux/native/applauncher/LinuxPackage.c +++ b/src/jdk.jpackage/linux/native/applauncher/LinuxPackage.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -109,7 +109,7 @@ static PackageDesc* initPackageDesc(PackageDesc* desc, const char* str, #define POPEN_CALLBACK_USE 1 #define POPEN_CALLBACK_IGNORE 0 -typedef int (*popenCallbackType)(void*, const char*); +typedef int (*popenCallbackType)(void*, char*); static int popenCommand(const char* cmdlineFormat, const char* arg, popenCallbackType callback, void* callbackData) { @@ -220,13 +220,13 @@ static char* concat(const char *x, const char *y) { } -static int initRpmPackage(void* desc, const char* str) { +static int initRpmPackage(void* desc, char* str) { initPackageDesc((PackageDesc*)desc, str, PACKAGE_TYPE_RPM); return POPEN_CALLBACK_IGNORE; } -static int initDebPackage(void* desc, const char* str) { +static int initDebPackage(void* desc, char* str) { char* colonChrPos = strchr(str, ':'); if (colonChrPos) { *colonChrPos = 0; @@ -238,7 +238,7 @@ static int initDebPackage(void* desc, const char* str) { #define LAUNCHER_LIB_NAME "/libapplauncher.so" -static int findLauncherLib(void* launcherLibPath, const char* str) { +static int findLauncherLib(void* launcherLibPath, char* str) { char* buf = 0; const size_t strLen = strlen(str); const size_t launcherLibNameLen = strlen(LAUNCHER_LIB_NAME); diff --git a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/RtfConverter.java b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/RtfConverter.java new file mode 100644 index 00000000000..8886afc7918 --- /dev/null +++ b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/RtfConverter.java @@ -0,0 +1,140 @@ +/* + * Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * 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 jdk.jpackage.internal; + +import static jdk.jpackage.internal.util.function.ThrowingConsumer.toConsumer; + +import java.io.IOException; +import java.io.InputStream; +import java.nio.charset.Charset; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.Optional; +import java.util.stream.Stream; +import jdk.jpackage.internal.util.function.ExceptionBox; + +sealed interface RtfConverter { + + void convert(Path path) throws IOException; + + static boolean isRtfFile(Path path) throws IOException { + if (Files.isDirectory(path)) { + return false; + } + + try (InputStream fin = Files.newInputStream(path)) { + byte[] firstBits = new byte[7]; + + if (fin.read(firstBits) == firstBits.length) { + String header = new String(firstBits); + return "{\\rtf1\\".equals(header); + } + } + + return false; + } + + static Optional createSimple(Path path) throws IOException { + if (isRtfFile(path)) { + return Optional.of(Details.Simple.VALUE); + } else { + return Optional.empty(); + } + } + + static final class Details { + private enum Simple implements RtfConverter { + + VALUE; + + @Override + public void convert(Path path) throws IOException { + var content = Files.readAllLines(path); + try (var w = Files.newBufferedWriter(path, Charset.forName("Windows-1252"))) { + convert(content.stream(), w); + } + } + + private void convert(Stream textFile, Appendable sink) throws IOException { + + sink.append("{\\rtf1\\ansi\\ansicpg1252\\deff0\\deflang1033" + + "{\\fonttbl{\\f0\\fnil\\fcharset0 Arial;}}\n" + + "\\viewkind4\\uc1\\pard\\sa200\\sl276" + + "\\slmult1\\lang9\\fs20 "); + + try { + textFile.forEach(toConsumer(l -> { + for (char c : l.toCharArray()) { + // 0x00 <= ch < 0x20 Escaped (\'hh) + // 0x20 <= ch < 0x80 Raw(non - escaped) char + // 0x80 <= ch <= 0xFF Escaped(\ 'hh) + // 0x5C, 0x7B, 0x7D (special RTF characters + // \,{,})Escaped(\'hh) + // ch > 0xff Escaped (\\ud###?) + if (c < 0x10) { + sink.append("\\'0"); + sink.append(Integer.toHexString(c)); + } else if (c > 0xff) { + sink.append("\\ud"); + sink.append(Integer.toString(c)); + // \\uc1 is in the header and in effect + // so we trail with a replacement char if + // the font lacks that character - '?' + sink.append("?"); + } else if ((c < 0x20) || (c >= 0x80) || + (c == 0x5C) || (c == 0x7B) || + (c == 0x7D)) { + sink.append("\\'"); + sink.append(Integer.toHexString(c)); + } else { + sink.append(c); + } + } + // blank lines are interpreted as paragraph breaks + if (l.length() < 1) { + sink.append("\\par"); + } else { + sink.append(" "); + } + sink.append("\r\n"); + })); + } catch (ExceptionBox ex) { + switch (ExceptionBox.unbox(ex)) { + case IOException ioex -> { + throw ioex; + } + default -> { + throw ex; + } + } + } + + sink.append("}\r\n"); + } + } + + } +} diff --git a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinMsiPackager.java b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinMsiPackager.java index 3eb7b10b846..977b7057ebb 100644 --- a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinMsiPackager.java +++ b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinMsiPackager.java @@ -24,12 +24,10 @@ */ package jdk.jpackage.internal; +import static jdk.jpackage.internal.util.function.ThrowingConsumer.toConsumer; import java.io.IOException; -import java.io.InputStream; import java.io.UncheckedIOException; -import java.io.Writer; -import java.nio.charset.Charset; import java.nio.file.FileSystems; import java.nio.file.Files; import java.nio.file.Path; @@ -169,19 +167,18 @@ final class WinMsiPackager implements Consumer { private void prepareConfigFiles() throws IOException { - pkg.licenseFile().ifPresent(licenseFile -> { + pkg.licenseFile().ifPresent(toConsumer(licenseFile -> { // need to copy license file to the working directory // and convert to rtf if needed Path destFile = env.configDir().resolve(licenseFile.getFileName()); - try { - IOUtils.copyFile(licenseFile, destFile); - } catch (IOException ex) { - throw new UncheckedIOException(ex); - } - destFile.toFile().setWritable(true); - ensureByMutationFileIsRTF(destFile); - }); + IOUtils.copyFile(licenseFile, destFile); + + RtfConverter.createSimple(licenseFile).ifPresent(toConsumer(rtfConverter -> { + destFile.toFile().setWritable(true); + rtfConverter.convert(destFile); + })); + })); for (var wixFragment : wixFragments) { wixFragment.initFromParams(env, pkg); @@ -402,74 +399,6 @@ final class WinMsiPackager implements Consumer { } } - private static void ensureByMutationFileIsRTF(Path f) { - try { - boolean existingLicenseIsRTF = false; - - try (InputStream fin = Files.newInputStream(f)) { - byte[] firstBits = new byte[7]; - - if (fin.read(firstBits) == firstBits.length) { - String header = new String(firstBits); - existingLicenseIsRTF = "{\\rtf1\\".equals(header); - } - } - - if (!existingLicenseIsRTF) { - List oldLicense = Files.readAllLines(f); - try (Writer w = Files.newBufferedWriter( - f, Charset.forName("Windows-1252"))) { - w.write("{\\rtf1\\ansi\\ansicpg1252\\deff0\\deflang1033" - + "{\\fonttbl{\\f0\\fnil\\fcharset0 Arial;}}\n" - + "\\viewkind4\\uc1\\pard\\sa200\\sl276" - + "\\slmult1\\lang9\\fs20 "); - oldLicense.forEach(l -> { - try { - for (char c : l.toCharArray()) { - // 0x00 <= ch < 0x20 Escaped (\'hh) - // 0x20 <= ch < 0x80 Raw(non - escaped) char - // 0x80 <= ch <= 0xFF Escaped(\ 'hh) - // 0x5C, 0x7B, 0x7D (special RTF characters - // \,{,})Escaped(\'hh) - // ch > 0xff Escaped (\\ud###?) - if (c < 0x10) { - w.write("\\'0"); - w.write(Integer.toHexString(c)); - } else if (c > 0xff) { - w.write("\\ud"); - w.write(Integer.toString(c)); - // \\uc1 is in the header and in effect - // so we trail with a replacement char if - // the font lacks that character - '?' - w.write("?"); - } else if ((c < 0x20) || (c >= 0x80) || - (c == 0x5C) || (c == 0x7B) || - (c == 0x7D)) { - w.write("\\'"); - w.write(Integer.toHexString(c)); - } else { - w.write(c); - } - } - // blank lines are interpreted as paragraph breaks - if (l.length() < 1) { - w.write("\\par"); - } else { - w.write(" "); - } - w.write("\r\n"); - } catch (IOException e) { - Log.verbose(e); - } - }); - w.write("}\r\n"); - } - } - } catch (IOException e) { - Log.verbose(e); - } - } - private final WinMsiPackage pkg; private final BuildEnv env; private final Path outputDir; diff --git a/src/jdk.management.jfr/share/classes/jdk/management/jfr/FlightRecorderMXBean.java b/src/jdk.management.jfr/share/classes/jdk/management/jfr/FlightRecorderMXBean.java index 9f61cc3f358..4a1ef30b9cf 100644 --- a/src/jdk.management.jfr/share/classes/jdk/management/jfr/FlightRecorderMXBean.java +++ b/src/jdk.management.jfr/share/classes/jdk/management/jfr/FlightRecorderMXBean.java @@ -90,7 +90,7 @@ import jdk.jfr.Recording; * this parameter is ignored. * {@code "0"} (no limit) * {@code "0"} if no limit is imposed, otherwise a string - * representation of a positive {@code Long} value followed by an empty space + * representation of a positive {@code long} value followed by an empty space * and one of the following units,
        *
        * {@code "ns"} (nanoseconds)
        @@ -112,7 +112,7 @@ import jdk.jfr.Recording; * repository. Only works if * {@code disk=true}, otherwise this parameter is ignored. * {@code "0"} (no limit) - * String representation of a {@code Long} value, must be positive + * String representation of a {@code long} value, must be positive * {@code "0"},
        * {@code "1000000000"} * @@ -120,7 +120,7 @@ import jdk.jfr.Recording; * {@code dumpOnExit} * Dumps recording data to disk on Java Virtual Machine (JVM) exit * {@code "false"} - * String representation of a {@code Boolean} value, {@code "true"} or + * String representation of a {@code boolean} value, {@code "true"} or * {@code "false"} * {@code "true"},
        * {@code "false"} @@ -140,7 +140,7 @@ import jdk.jfr.Recording; * {@code disk} * Stores recorded data as it is recorded * "false" - * String representation of a {@code Boolean} value, {@code "true"} or + * String representation of a {@code boolean} value, {@code "true"} or * {@code "false"} * {@code "true"},
        * {@code "false"} @@ -149,7 +149,7 @@ import jdk.jfr.Recording; * Specifies the duration of the recording. * {@code "0"} (no limit, continuous) * {@code "0"} if no limit should be imposed, otherwise a string - * representation of a positive {@code Long} followed by an empty space and one + * representation of a positive {@code long} followed by an empty space and one * of the following units:
        *
        * {@code "ns"} (nanoseconds)
        diff --git a/src/utils/hsdis/README.md b/src/utils/hsdis/README.md index 98b08477450..eb532088032 100644 --- a/src/utils/hsdis/README.md +++ b/src/utils/hsdis/README.md @@ -61,6 +61,11 @@ backend to use. This is done with the configure switch `--with-hsdis=`, where `` is either `capstone`, `llvm` or `binutils`. For details, see the sections on the respective backends below. +A default value for `PrintAssemblyOptions` can be set at configure time with +`--with-print-assembly-options=` (e.g. `intel` for Intel syntax on x86, +if supported by the chosen backend). The runtime `-XX:PrintAssemblyOptions=...` +flag still takes precedence. + To build the hsdis library, run `make build-hsdis`. This will build the library in a separate directory, but not make it available to the JDK in the configuration. To actually install it in the JDK, run `make install-hsdis`. diff --git a/test/docs/ProblemList.txt b/test/docs/ProblemList.txt index d856f9c955e..6d496f62a21 100644 --- a/test/docs/ProblemList.txt +++ b/test/docs/ProblemList.txt @@ -45,10 +45,14 @@ # Preview project specific failures go here at the end of the file. # # These are NOT failures that occur with the '--enable-preview' option -# specified; those go in the appropriate ProblemList-enable-preview.txt file. +# specified in the task definition; those go in the appropriate +# ProblemList-enable-preview.txt file. +# # These are failures that occur WITHOUT the '--enable-preview' option -# specified AND occur because of some issue with preview project code, -# in either implementation or test code. +# specified in the task definition OR the '--enable-preview' option +# MAY BE specified in the test itself. In either case, the failure +# occurs because of some issue with preview project code, in either +# implementation or test code. ############################################################################# diff --git a/test/hotspot/gtest/concurrentTestRunner.inline.hpp b/test/hotspot/gtest/concurrentTestRunner.inline.hpp index 4cdb342d45c..dcc025bdbf5 100644 --- a/test/hotspot/gtest/concurrentTestRunner.inline.hpp +++ b/test/hotspot/gtest/concurrentTestRunner.inline.hpp @@ -86,7 +86,7 @@ public: done.wait(); } - FREE_C_HEAP_ARRAY(UnitTestThread**, t); + FREE_C_HEAP_ARRAY(t); } private: diff --git a/test/hotspot/gtest/gc/g1/test_freeRegionList.cpp b/test/hotspot/gtest/gc/g1/test_freeRegionList.cpp index e61ce43fdb6..344f32d5ec8 100644 --- a/test/hotspot/gtest/gc/g1/test_freeRegionList.cpp +++ b/test/hotspot/gtest/gc/g1/test_freeRegionList.cpp @@ -91,5 +91,5 @@ TEST_OTHER_VM(G1FreeRegionList, length) { bot_storage->uncommit_regions(0, num_regions_in_test); delete bot_storage; os::release_memory(addr, sz); - FREE_C_HEAP_ARRAY(HeapWord, bot_data); + FREE_C_HEAP_ARRAY(bot_data); } diff --git a/test/hotspot/gtest/gc/g1/test_g1BatchedGangTask.cpp b/test/hotspot/gtest/gc/g1/test_g1BatchedGangTask.cpp index 08df547585a..01e512b6b22 100644 --- a/test/hotspot/gtest/gc/g1/test_g1BatchedGangTask.cpp +++ b/test/hotspot/gtest/gc/g1/test_g1BatchedGangTask.cpp @@ -87,7 +87,7 @@ public: ~G1TestSubTask() { check_and_inc_phase(3); - FREE_C_HEAP_ARRAY(Atomic, _do_work_called_by); + FREE_C_HEAP_ARRAY(_do_work_called_by); } double worker_cost() const override { diff --git a/test/hotspot/gtest/gc/g1/test_g1CardSetContainers.cpp b/test/hotspot/gtest/gc/g1/test_g1CardSetContainers.cpp index 91951b35405..2236b4e83aa 100644 --- a/test/hotspot/gtest/gc/g1/test_g1CardSetContainers.cpp +++ b/test/hotspot/gtest/gc/g1/test_g1CardSetContainers.cpp @@ -69,7 +69,7 @@ public: } ~G1FindCardsInRange() { - FREE_C_HEAP_ARRAY(mtGC, _cards_found); + FREE_C_HEAP_ARRAY(_cards_found); } void operator()(uint card) { ASSERT_TRUE((card - _range_min) < _num_cards); @@ -185,7 +185,7 @@ void G1CardSetContainersTest::cardset_array_test(uint cards_per_array) { found.verify_all_found(); } - FREE_C_HEAP_ARRAY(mtGC, cardset_data); + FREE_C_HEAP_ARRAY(cardset_data); } void G1CardSetContainersTest::cardset_bitmap_test(uint threshold, uint size_in_bits) { @@ -232,7 +232,7 @@ void G1CardSetContainersTest::cardset_bitmap_test(uint threshold, uint size_in_b found.verify_part_found(threshold); } - FREE_C_HEAP_ARRAY(mtGC, cardset_data); + FREE_C_HEAP_ARRAY(cardset_data); } TEST_VM_F(G1CardSetContainersTest, basic_cardset_inptr_test) { diff --git a/test/hotspot/gtest/gc/shared/test_oopStorage.cpp b/test/hotspot/gtest/gc/shared/test_oopStorage.cpp index b343e7fc47f..61115fe9ea0 100644 --- a/test/hotspot/gtest/gc/shared/test_oopStorage.cpp +++ b/test/hotspot/gtest/gc/shared/test_oopStorage.cpp @@ -486,7 +486,7 @@ public: EXPECT_EQ(storage().block_count(), empty_block_count(storage())); - FREE_C_HEAP_ARRAY(oop*, to_release); + FREE_C_HEAP_ARRAY(to_release); } struct PointerCompare { @@ -534,7 +534,7 @@ TEST_VM_F(OopStorageTest, invalid_malloc_pointer) { oop* ptr = reinterpret_cast(align_down(mem + 250, sizeof(oop))); // Predicate returns false for some malloc'ed block. EXPECT_EQ(OopStorage::INVALID_ENTRY, storage().allocation_status(ptr)); - FREE_C_HEAP_ARRAY(char, mem); + FREE_C_HEAP_ARRAY(mem); } TEST_VM_F(OopStorageTest, invalid_random_pointer) { diff --git a/test/hotspot/gtest/gc/shared/test_oopStorage_parperf.cpp b/test/hotspot/gtest/gc/shared/test_oopStorage_parperf.cpp index 3f049eda6ea..72dd61c5cf4 100644 --- a/test/hotspot/gtest/gc/shared/test_oopStorage_parperf.cpp +++ b/test/hotspot/gtest/gc/shared/test_oopStorage_parperf.cpp @@ -137,7 +137,7 @@ public: } ~Task() { - FREE_C_HEAP_ARRAY(Tickspan, _worker_times); + FREE_C_HEAP_ARRAY(_worker_times); } virtual void work(uint worker_id) { diff --git a/test/hotspot/gtest/gc/shenandoah/test_shenandoahMarkBitMap.cpp b/test/hotspot/gtest/gc/shenandoah/test_shenandoahMarkBitMap.cpp index 18cf3b3333f..d395bd27db2 100644 --- a/test/hotspot/gtest/gc/shenandoah/test_shenandoahMarkBitMap.cpp +++ b/test/hotspot/gtest/gc/shenandoah/test_shenandoahMarkBitMap.cpp @@ -555,7 +555,7 @@ public: is_weakly_marked_object_after_2nd_clear, is_strongly_marked_object_after_2nd_clear, all_marked_objects_after_2nd_clear, my_heap_memory, end_of_my_heap); - FREE_C_HEAP_ARRAY(HeapWord, my_bitmap_memory); + FREE_C_HEAP_ARRAY(my_bitmap_memory); _success = true; return true; } diff --git a/test/hotspot/gtest/logging/logTestFixture.cpp b/test/hotspot/gtest/logging/logTestFixture.cpp index 77cc3ee1f75..5a50d050511 100644 --- a/test/hotspot/gtest/logging/logTestFixture.cpp +++ b/test/hotspot/gtest/logging/logTestFixture.cpp @@ -116,7 +116,7 @@ void LogTestFixture::clear_snapshot() { for (size_t i = 0; i < _n_snapshots; i++) { os::free(_configuration_snapshot[i]); } - FREE_C_HEAP_ARRAY(char*, _configuration_snapshot); + FREE_C_HEAP_ARRAY(_configuration_snapshot); _configuration_snapshot = nullptr; _n_snapshots = 0; } diff --git a/test/hotspot/gtest/logging/logTestUtils.inline.hpp b/test/hotspot/gtest/logging/logTestUtils.inline.hpp index 93cace9c689..59045b3a7af 100644 --- a/test/hotspot/gtest/logging/logTestUtils.inline.hpp +++ b/test/hotspot/gtest/logging/logTestUtils.inline.hpp @@ -126,7 +126,7 @@ static inline char* read_line(FILE* fp) { char* ret = fgets(buf, buflen, fp); while (ret != nullptr && buf[strlen(buf) - 1] != '\n' && !feof(fp)) { // retry with a larger buffer - buf = REALLOC_RESOURCE_ARRAY(char, buf, buflen, buflen * 2); + buf = REALLOC_RESOURCE_ARRAY(buf, buflen, buflen * 2); buflen *= 2; // rewind to beginning of line fseek(fp, pos, SEEK_SET); diff --git a/test/hotspot/gtest/logging/test_asynclog.cpp b/test/hotspot/gtest/logging/test_asynclog.cpp index 2634b8dac77..61502f37d80 100644 --- a/test/hotspot/gtest/logging/test_asynclog.cpp +++ b/test/hotspot/gtest/logging/test_asynclog.cpp @@ -234,7 +234,7 @@ TEST_VM_F(AsyncLogTest, logBuffer) { EXPECT_FALSE(buffer->iterator().hasNext()); delete output; // close file - FREE_C_HEAP_ARRAY(char, name); + FREE_C_HEAP_ARRAY(name); const char* strs[4]; strs[0] = "a log line"; diff --git a/test/hotspot/gtest/logging/test_logMessageTest.cpp b/test/hotspot/gtest/logging/test_logMessageTest.cpp index 8ac92f66665..2bc644d9d0c 100644 --- a/test/hotspot/gtest/logging/test_logMessageTest.cpp +++ b/test/hotspot/gtest/logging/test_logMessageTest.cpp @@ -158,7 +158,7 @@ TEST_VM_F(LogMessageTest, long_message) { const char* expected[] = { start_marker, "0123456789", end_marker, nullptr }; EXPECT_TRUE(file_contains_substrings_in_order(_level_filename[LogLevel::Trace], expected)) << "unable to print long line"; - FREE_C_HEAP_ARRAY(char, data); + FREE_C_HEAP_ARRAY(data); } TEST_VM_F(LogMessageTest, message_with_many_lines) { diff --git a/test/hotspot/gtest/memory/test_arena.cpp b/test/hotspot/gtest/memory/test_arena.cpp index 9773aa2d027..abd108a698f 100644 --- a/test/hotspot/gtest/memory/test_arena.cpp +++ b/test/hotspot/gtest/memory/test_arena.cpp @@ -306,9 +306,9 @@ TEST_VM(Arena, random_allocs) { } // Free temp data - FREE_C_HEAP_ARRAY(char*, ptrs); - FREE_C_HEAP_ARRAY(size_t, sizes); - FREE_C_HEAP_ARRAY(size_t, alignments); + FREE_C_HEAP_ARRAY(ptrs); + FREE_C_HEAP_ARRAY(sizes); + FREE_C_HEAP_ARRAY(alignments); } #ifndef LP64 diff --git a/test/hotspot/gtest/metaspace/metaspaceGtestCommon.hpp b/test/hotspot/gtest/metaspace/metaspaceGtestCommon.hpp index 4c9bf67997b..cfa70919bed 100644 --- a/test/hotspot/gtest/metaspace/metaspaceGtestCommon.hpp +++ b/test/hotspot/gtest/metaspace/metaspaceGtestCommon.hpp @@ -42,7 +42,7 @@ public: _arr = NEW_C_HEAP_ARRAY(char, len, mtInternal); memset(_arr, 0, _len); } - ~TestMap() { FREE_C_HEAP_ARRAY(char, _arr); } + ~TestMap() { FREE_C_HEAP_ARRAY(_arr); } int get_num_set(size_t from, size_t to) const { int result = 0; @@ -193,7 +193,7 @@ public: } ~FeederBuffer() { - FREE_C_HEAP_ARRAY(MetaWord, _buf); + FREE_C_HEAP_ARRAY(_buf); } MetaWord* get(size_t word_size) { diff --git a/test/hotspot/gtest/metaspace/metaspaceGtestSparseArray.hpp b/test/hotspot/gtest/metaspace/metaspaceGtestSparseArray.hpp index 6ca6b68baa3..c4ddca624aa 100644 --- a/test/hotspot/gtest/metaspace/metaspaceGtestSparseArray.hpp +++ b/test/hotspot/gtest/metaspace/metaspaceGtestSparseArray.hpp @@ -100,7 +100,7 @@ public: } ~SparseArray() { - FREE_C_HEAP_ARRAY(T, _slots); + FREE_C_HEAP_ARRAY(_slots); } T at(int i) { return _slots[i]; } @@ -165,4 +165,3 @@ public: }; #endif // GTEST_METASPACE_METASPACEGTESTSPARSEARRAY_HPP - diff --git a/test/hotspot/gtest/nmt/test_nmt_locationprinting.cpp b/test/hotspot/gtest/nmt/test_nmt_locationprinting.cpp index c8711004f10..23575fe2c13 100644 --- a/test/hotspot/gtest/nmt/test_nmt_locationprinting.cpp +++ b/test/hotspot/gtest/nmt/test_nmt_locationprinting.cpp @@ -63,7 +63,7 @@ static void test_for_live_c_heap_block(size_t sz, ssize_t offset) { // NMT disabled: we should see nothing. test_pointer(c + offset, false, ""); } - FREE_C_HEAP_ARRAY(char, c); + FREE_C_HEAP_ARRAY(c); } #ifdef LINUX @@ -90,7 +90,7 @@ static void test_for_dead_c_heap_block(size_t sz, ssize_t offset) { test_pointer(c + offset, true, expected_string); hdr->revive(); - FREE_C_HEAP_ARRAY(char, c); + FREE_C_HEAP_ARRAY(c); } #endif diff --git a/test/hotspot/gtest/nmt/test_nmtpreinitmap.cpp b/test/hotspot/gtest/nmt/test_nmtpreinitmap.cpp index c37f5772a5d..6bf42c6f044 100644 --- a/test/hotspot/gtest/nmt/test_nmtpreinitmap.cpp +++ b/test/hotspot/gtest/nmt/test_nmtpreinitmap.cpp @@ -110,7 +110,7 @@ TEST_VM(NMTPreInit, stress_test_map) { print_and_check_table(table, 0); - FREE_C_HEAP_ARRAY(NMTPreInitAllocation*, allocations); + FREE_C_HEAP_ARRAY(allocations); } #ifdef ASSERT diff --git a/test/hotspot/gtest/oops/test_instanceKlass.cpp b/test/hotspot/gtest/oops/test_instanceKlass.cpp index 14fbd7ed53c..ac489b786fd 100644 --- a/test/hotspot/gtest/oops/test_instanceKlass.cpp +++ b/test/hotspot/gtest/oops/test_instanceKlass.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2016, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -29,6 +29,7 @@ #include "oops/instanceKlass.hpp" #include "oops/klass.inline.hpp" #include "oops/method.hpp" +#include "runtime/fieldDescriptor.hpp" #include "runtime/interfaceSupport.inline.hpp" #include "unittest.hpp" @@ -69,6 +70,79 @@ TEST_VM(InstanceKlass, class_loader_printer) { #endif } +TEST_VM(InstanceKlass, class_flag_printer) { + JavaThread* THREAD = JavaThread::current(); + ThreadInVMfromNative scope(THREAD); + ResourceMark rm; + stringStream st; + + vmClasses::String_klass()->print_class_flags(&st); + ASSERT_STREQ("public final ", st.base()); + + st.reset(); + vmClasses::Runnable_klass()->print_class_flags(&st); + ASSERT_STREQ("public interface abstract ", st.base()); + + st.reset(); + Symbol* override_symbol = SymbolTable::new_symbol("java/lang/Override"); + Klass* override_klass = SystemDictionary::resolve_or_fail(override_symbol, true, THREAD); + ASSERT_FALSE(THREAD->has_pending_exception()) << "java/lang/Override must resolve"; + InstanceKlass::cast(override_klass)->print_class_flags(&st); + ASSERT_STREQ("public interface abstract annotation ", st.base()); + + st.reset(); + Symbol* thread_state_symbol = SymbolTable::new_symbol("java/lang/Thread$State"); + Klass* thread_state_klass = SystemDictionary::resolve_or_fail(thread_state_symbol, true, THREAD); + ASSERT_FALSE(THREAD->has_pending_exception()) << "java/lang/Thread$State must resolve"; + InstanceKlass::cast(thread_state_klass)->print_class_flags(&st); + ASSERT_STREQ("public static final enum ", st.base()); + + st.reset(); + Symbol* certificate_rep_symbol = SymbolTable::new_symbol("java/security/cert/Certificate$CertificateRep"); + Klass* certificate_rep_klass = SystemDictionary::resolve_or_fail(certificate_rep_symbol, true, THREAD); + ASSERT_FALSE(THREAD->has_pending_exception()) << "java/security/cert/Certificate$CertificateRep must resolve"; + InstanceKlass::cast(certificate_rep_klass)->print_class_flags(&st); + ASSERT_STREQ("protected static ", st.base()); + + st.reset(); + Symbol* arrays_array_list_symbol = SymbolTable::new_symbol("java/util/Arrays$ArrayList"); + Klass* arrays_array_list_klass = SystemDictionary::resolve_or_fail(arrays_array_list_symbol, true, THREAD); + ASSERT_FALSE(THREAD->has_pending_exception()) << "java/util/Arrays$ArrayList must resolve"; + InstanceKlass::cast(arrays_array_list_klass)->print_class_flags(&st); + ASSERT_STREQ("private static ", st.base()); +} + +TEST_VM(FieldDescriptor, access_flag_printer) { + JavaThread* THREAD = JavaThread::current(); + ThreadInVMfromNative scope(THREAD); + ResourceMark rm; + stringStream st; + + InstanceKlass* integer_klass = vmClasses::Integer_klass(); + Symbol* min_value_symbol = SymbolTable::new_symbol("MIN_VALUE"); + + fieldDescriptor fd; + ASSERT_TRUE(integer_klass->find_local_field(min_value_symbol, vmSymbols::int_signature(), &fd)) + << "Integer.MIN_VALUE must exist"; + fd.print_on(&st); + ASSERT_THAT(st.base(), HasSubstr("public static final 'MIN_VALUE' 'I'")) << "Must print field access flags"; + + st.reset(); + Symbol* thread_state_symbol = SymbolTable::new_symbol("java/lang/Thread$State"); + Klass* thread_state_klass = SystemDictionary::resolve_or_fail(thread_state_symbol, true, THREAD); + ASSERT_FALSE(THREAD->has_pending_exception()) << "java/lang/Thread$State must resolve"; + + fieldDescriptor enum_fd; + Symbol* enum_symbol = SymbolTable::new_symbol("NEW"); + Symbol* enum_signature = SymbolTable::new_symbol("Ljava/lang/Thread$State;"); + ASSERT_TRUE(InstanceKlass::cast(thread_state_klass)->find_local_field(enum_symbol, enum_signature, &enum_fd)) + << "Thread.State.NEW must exist"; + + enum_fd.print_on(&st); + ASSERT_THAT(st.base(), HasSubstr("public static final enum 'NEW' 'Ljava/lang/Thread$State;'")) + << "Must print enum field access flags"; +} + #ifndef PRODUCT // This class is friends with Method. class MethodTest : public ::testing::Test{ @@ -85,4 +159,40 @@ TEST_VM(Method, method_name) { ASSERT_TRUE(method != nullptr) << "Object must have toString"; MethodTest::compare_names(method, tostring); } + +TEST_VM(Method, access_flag_printer) { + ThreadInVMfromNative scope(JavaThread::current()); + ResourceMark rm; + stringStream st; + + InstanceKlass* object_klass = vmClasses::Object_klass(); + Symbol* wait_symbol = SymbolTable::new_symbol("wait"); + Method* wait_method = object_klass->find_method(wait_symbol, vmSymbols::long_void_signature()); + ASSERT_TRUE(wait_method != nullptr) << "Object must have wait(long)"; + wait_method->print_access_flags(&st); + ASSERT_STREQ("public final ", st.base()); + + st.reset(); + Symbol* symbol_hash_code = SymbolTable::new_symbol("hashCode"); + Method* hash_code = object_klass->find_method(symbol_hash_code, vmSymbols::void_int_signature()); + ASSERT_TRUE(hash_code != nullptr) << "Object must have hashCode()"; + hash_code->print_access_flags(&st); + ASSERT_STREQ("public native ", st.base()); + + st.reset(); + InstanceKlass* string_klass = vmClasses::String_klass(); + Symbol* format_symbol = SymbolTable::new_symbol("format"); + Symbol* format_signature = SymbolTable::new_symbol("(Ljava/lang/String;[Ljava/lang/Object;)Ljava/lang/String;"); + Method* format_method = string_klass->find_method(format_symbol, format_signature); + ASSERT_TRUE(format_method != nullptr) << "String must have format(String, Object...)"; + format_method->print_access_flags(&st); + ASSERT_STREQ("public static varargs ", st.base()); + + st.reset(); + Symbol* compare_to_symbol = SymbolTable::new_symbol("compareTo"); + Method* compare_to_bridge_method = string_klass->find_method(compare_to_symbol, vmSymbols::object_int_signature()); + ASSERT_TRUE(compare_to_bridge_method != nullptr) << "String must have bridge compareTo(Object)"; + compare_to_bridge_method->print_access_flags(&st); + ASSERT_STREQ("public bridge synthetic ", st.base()); +} #endif diff --git a/test/hotspot/gtest/runtime/test_os.cpp b/test/hotspot/gtest/runtime/test_os.cpp index 094f16a4262..26c8fb8cd72 100644 --- a/test/hotspot/gtest/runtime/test_os.cpp +++ b/test/hotspot/gtest/runtime/test_os.cpp @@ -746,7 +746,7 @@ static void test_show_mappings(address start, size_t size) { #endif // buf[buflen - 1] = '\0'; // tty->print_raw(buf); - FREE_C_HEAP_ARRAY(char, buf); + FREE_C_HEAP_ARRAY(buf); } TEST_VM(os, show_mappings_small_range) { diff --git a/test/hotspot/gtest/threadHelper.inline.hpp b/test/hotspot/gtest/threadHelper.inline.hpp index 07764c45a7a..cc11b0f6ff5 100644 --- a/test/hotspot/gtest/threadHelper.inline.hpp +++ b/test/hotspot/gtest/threadHelper.inline.hpp @@ -169,7 +169,7 @@ public: } } ~TestThreadGroup() { - FREE_C_HEAP_ARRAY(BasicTestThread*, _threads); + FREE_C_HEAP_ARRAY(_threads); } void doit() { diff --git a/test/hotspot/gtest/utilities/test_bitMap_popcnt.cpp b/test/hotspot/gtest/utilities/test_bitMap_popcnt.cpp index 7f2b0eedaa4..bd5c80093d4 100644 --- a/test/hotspot/gtest/utilities/test_bitMap_popcnt.cpp +++ b/test/hotspot/gtest/utilities/test_bitMap_popcnt.cpp @@ -42,7 +42,7 @@ public: } ~SimpleFakeBitmap() { - FREE_C_HEAP_ARRAY(char, _buffer); + FREE_C_HEAP_ARRAY(_buffer); } // Set or clear the specified bit. diff --git a/test/hotspot/gtest/utilities/test_concurrentHashtable.cpp b/test/hotspot/gtest/utilities/test_concurrentHashtable.cpp index 8094e93b944..163b11c213e 100644 --- a/test/hotspot/gtest/utilities/test_concurrentHashtable.cpp +++ b/test/hotspot/gtest/utilities/test_concurrentHashtable.cpp @@ -609,7 +609,7 @@ class ValueSaver { _vals[_it++] = *val; if (_it == _size) { _size *= 2; - _vals = REALLOC_RESOURCE_ARRAY(uintptr_t, _vals, _size/2, _size); + _vals = REALLOC_RESOURCE_ARRAY(_vals, _size/2, _size); } return true; } diff --git a/test/hotspot/gtest/utilities/test_lockFreeStack.cpp b/test/hotspot/gtest/utilities/test_lockFreeStack.cpp index bdba49b48c0..3c3558f0018 100644 --- a/test/hotspot/gtest/utilities/test_lockFreeStack.cpp +++ b/test/hotspot/gtest/utilities/test_lockFreeStack.cpp @@ -300,5 +300,5 @@ TEST_VM(LockFreeStackTest, stress) { ASSERT_EQ(nelements, final_stack.length()); while (final_stack.pop() != nullptr) {} - FREE_C_HEAP_ARRAY(Element, elements); + FREE_C_HEAP_ARRAY(elements); } diff --git a/test/hotspot/gtest/utilities/test_quicksort.cpp b/test/hotspot/gtest/utilities/test_quicksort.cpp index acdd6a315e5..a84d5ecef92 100644 --- a/test/hotspot/gtest/utilities/test_quicksort.cpp +++ b/test/hotspot/gtest/utilities/test_quicksort.cpp @@ -129,7 +129,7 @@ TEST(QuickSort, random) { // Compare sorting to stdlib::qsort() qsort(expected_array, length, sizeof(int), test_stdlib_comparator); EXPECT_TRUE(sort_and_compare(test_array, expected_array, length, test_comparator)); - FREE_C_HEAP_ARRAY(int, test_array); - FREE_C_HEAP_ARRAY(int, expected_array); + FREE_C_HEAP_ARRAY(test_array); + FREE_C_HEAP_ARRAY(expected_array); } } diff --git a/test/hotspot/gtest/utilities/test_rbtree.cpp b/test/hotspot/gtest/utilities/test_rbtree.cpp index 7eca5f54831..bb306935f45 100644 --- a/test/hotspot/gtest/utilities/test_rbtree.cpp +++ b/test/hotspot/gtest/utilities/test_rbtree.cpp @@ -851,6 +851,46 @@ public: tree.verify_self(); } + void test_update_key() { + RBTreeInt tree; + + tree.upsert(10, 10); + tree.upsert(20, 20); + tree.upsert(30, 30); + + RBTreeIntNode* node = tree.find_node(20); + EXPECT_NOT_NULL(node); + + tree.update_key(node, 25); + + EXPECT_NULL(tree.find_node(20)); + + RBTreeIntNode* updated_node = tree.find_node(25); + EXPECT_NOT_NULL(updated_node); + EXPECT_EQ(updated_node, node); + + EXPECT_EQ(25, updated_node->key()); + EXPECT_EQ(20, updated_node->val()); + + RBTreeInt::Cursor cursor = tree.cursor(10); + EXPECT_TRUE(cursor.found()); + + tree.update_key(cursor, 20); + + EXPECT_FALSE(tree.cursor(10).found()); + + RBTreeInt::Cursor updated_cursor = tree.cursor(20); + EXPECT_TRUE(updated_cursor.found()); + + RBTreeIntNode* updated_cursor_node = updated_cursor.node(); + EXPECT_EQ(updated_cursor_node, cursor.node()); + + EXPECT_EQ(20, updated_cursor_node->key()); + EXPECT_EQ(10, updated_cursor_node->val()); + + tree.verify_self(); + } + void test_intrusive() { IntrusiveTreeInt intrusive_tree; int num_iterations = 100; @@ -1167,11 +1207,30 @@ TEST_VM_F(RBTreeTest, CursorReplace) { this->test_cursor_replace(); } +TEST_VM_F(RBTreeTest, UpdateKey) { + this->test_update_key(); +} + #ifdef ASSERT TEST_VM_F(RBTreeTest, NodesVisitedOnce) { this->test_nodes_visited_once(); } +TEST_VM_ASSERT_MSG(RBTreeTestNonFixture, UpdateKeyAssert, + ".*updated key not LT next node's key.*") { + typedef RBTreeCHeap TreeType; + + TreeType tree; + tree.upsert(10, 10); + tree.upsert(20, 20); + tree.upsert(30, 30); + + RBNode* node = tree.find_node(20); + ASSERT_NOT_NULL(node); + + tree.update_key(node, 35); +} + TEST_VM_ASSERT_MSG(RBTreeTestNonFixture, CustomVerifyAssert, ".*failed on key = 7") { typedef RBTreeCHeap TreeType; typedef RBNode NodeType; diff --git a/test/hotspot/jtreg/ProblemList-AotJdk.txt b/test/hotspot/jtreg/ProblemList-AotJdk.txt index 0a2177b8edb..3ebe405a046 100644 --- a/test/hotspot/jtreg/ProblemList-AotJdk.txt +++ b/test/hotspot/jtreg/ProblemList-AotJdk.txt @@ -62,10 +62,14 @@ compiler/arraycopy/TestCloneWithStressReflectiveCode.java 8323727 generic-all # Preview project specific failures go here at the end of the file. # # These are NOT failures that occur with the '--enable-preview' option -# specified; those go in the appropriate ProblemList-enable-preview.txt file. +# specified in the task definition; those go in the appropriate +# ProblemList-enable-preview.txt file. +# # These are failures that occur WITHOUT the '--enable-preview' option -# specified AND occur because of some issue with preview project code, -# in either implementation or test code. +# specified in the task definition OR the '--enable-preview' option +# MAY BE specified in the test itself. In either case, the failure +# occurs because of some issue with preview project code, in either +# implementation or test code. ############################################################################# diff --git a/test/hotspot/jtreg/ProblemList-StaticJdk.txt b/test/hotspot/jtreg/ProblemList-StaticJdk.txt index a6112169f8d..ce22258d04a 100644 --- a/test/hotspot/jtreg/ProblemList-StaticJdk.txt +++ b/test/hotspot/jtreg/ProblemList-StaticJdk.txt @@ -41,10 +41,14 @@ gtest/NMTGtests.java#nmt-summary 8356201 generic-all # Preview project specific failures go here at the end of the file. # # These are NOT failures that occur with the '--enable-preview' option -# specified; those go in the appropriate ProblemList-enable-preview.txt file. +# specified in the task definition; those go in the appropriate +# ProblemList-enable-preview.txt file. +# # These are failures that occur WITHOUT the '--enable-preview' option -# specified AND occur because of some issue with preview project code, -# in either implementation or test code. +# specified in the task definition OR the '--enable-preview' option +# MAY BE specified in the test itself. In either case, the failure +# occurs because of some issue with preview project code, in either +# implementation or test code. ############################################################################# diff --git a/test/hotspot/jtreg/ProblemList-Virtual.txt b/test/hotspot/jtreg/ProblemList-Virtual.txt index 7c4846a9fb2..c6bea25d275 100644 --- a/test/hotspot/jtreg/ProblemList-Virtual.txt +++ b/test/hotspot/jtreg/ProblemList-Virtual.txt @@ -82,10 +82,14 @@ vmTestbase/nsk/jdi/ThreadReference/isSuspended/issuspended002/TestDescription.ja # Preview project specific failures go here at the end of the file. # # These are NOT failures that occur with the '--enable-preview' option -# specified; those go in the appropriate ProblemList-enable-preview.txt file. +# specified in the task definition; those go in the appropriate +# ProblemList-enable-preview.txt file. +# # These are failures that occur WITHOUT the '--enable-preview' option -# specified AND occur because of some issue with preview project code, -# in either implementation or test code. +# specified in the task definition OR the '--enable-preview' option +# MAY BE specified in the test itself. In either case, the failure +# occurs because of some issue with preview project code, in either +# implementation or test code. ############################################################################# diff --git a/test/hotspot/jtreg/ProblemList-Xcomp.txt b/test/hotspot/jtreg/ProblemList-Xcomp.txt index e4f1774e6e0..f9a4d5ec2a9 100644 --- a/test/hotspot/jtreg/ProblemList-Xcomp.txt +++ b/test/hotspot/jtreg/ProblemList-Xcomp.txt @@ -52,10 +52,14 @@ gc/arguments/TestNewSizeFlags.java 8299116 macosx-aarch64 # Preview project specific failures go here at the end of the file. # # These are NOT failures that occur with the '--enable-preview' option -# specified; those go in the appropriate ProblemList-enable-preview.txt file. +# specified in the task definition; those go in the appropriate +# ProblemList-enable-preview.txt file. +# # These are failures that occur WITHOUT the '--enable-preview' option -# specified AND occur because of some issue with preview project code, -# in either implementation or test code. +# specified in the task definition OR the '--enable-preview' option +# MAY BE specified in the test itself. In either case, the failure +# occurs because of some issue with preview project code, in either +# implementation or test code. ############################################################################# diff --git a/test/hotspot/jtreg/ProblemList-enable-preview.txt b/test/hotspot/jtreg/ProblemList-enable-preview.txt index 1a831a0dde3..b28670c9839 100644 --- a/test/hotspot/jtreg/ProblemList-enable-preview.txt +++ b/test/hotspot/jtreg/ProblemList-enable-preview.txt @@ -23,10 +23,13 @@ ############################################################################# # -# List of quarantined tests for testing with --enable-preview +# List of quarantined tests for testing with the '--enable-preview' option +# where the option IS specified in the task definition and NOT in the test. # -# These are failures that ONLY occur with the '--enable-preview' option -# specified. There are separate sub-sections for each preview project. +# If the '--enable-preview' option is NOT specified in the task definition, +# and the option IS specified in the test, then an entry here WILL NOT work. +# +# There are separate sub-sections for each preview project. # ############################################################################# diff --git a/test/hotspot/jtreg/ProblemList-jvmti-stress-agent.txt b/test/hotspot/jtreg/ProblemList-jvmti-stress-agent.txt index d8779a873cd..a30d6dfecff 100644 --- a/test/hotspot/jtreg/ProblemList-jvmti-stress-agent.txt +++ b/test/hotspot/jtreg/ProblemList-jvmti-stress-agent.txt @@ -100,10 +100,14 @@ serviceability/jvmti/HeapMonitor/MyPackage/HeapMonitorVMEventsTest.java#id1 # Preview project specific failures go here at the end of the file. # # These are NOT failures that occur with the '--enable-preview' option -# specified; those go in the appropriate ProblemList-enable-preview.txt file. +# specified in the task definition; those go in the appropriate +# ProblemList-enable-preview.txt file. +# # These are failures that occur WITHOUT the '--enable-preview' option -# specified AND occur because of some issue with preview project code, -# in either implementation or test code. +# specified in the task definition OR the '--enable-preview' option +# MAY BE specified in the test itself. In either case, the failure +# occurs because of some issue with preview project code, in either +# implementation or test code. ############################################################################# diff --git a/test/hotspot/jtreg/ProblemList-zgc.txt b/test/hotspot/jtreg/ProblemList-zgc.txt index 8514ffce11c..351ef2a540c 100644 --- a/test/hotspot/jtreg/ProblemList-zgc.txt +++ b/test/hotspot/jtreg/ProblemList-zgc.txt @@ -43,10 +43,14 @@ compiler/jvmci/jdk.vm.ci.code.test/src/jdk/vm/ci/code/test/VirtualObjectDebugInf # Preview project specific failures go here at the end of the file. # # These are NOT failures that occur with the '--enable-preview' option -# specified; those go in the appropriate ProblemList-enable-preview.txt file. +# specified in the task definition; those go in the appropriate +# ProblemList-enable-preview.txt file. +# # These are failures that occur WITHOUT the '--enable-preview' option -# specified AND occur because of some issue with preview project code, -# in either implementation or test code. +# specified in the task definition OR the '--enable-preview' option +# MAY BE specified in the test itself. In either case, the failure +# occurs because of some issue with preview project code, in either +# implementation or test code. ############################################################################# diff --git a/test/hotspot/jtreg/ProblemList.txt b/test/hotspot/jtreg/ProblemList.txt index 202570d6486..14c7017052f 100644 --- a/test/hotspot/jtreg/ProblemList.txt +++ b/test/hotspot/jtreg/ProblemList.txt @@ -95,7 +95,10 @@ gc/TestAllocHumongousFragment.java#aggressive 8298781 generic-all gc/TestAllocHumongousFragment.java#g1 8298781 generic-all gc/TestAllocHumongousFragment.java#static 8298781 generic-all gc/shenandoah/oom/TestAllocOutOfMemory.java#large 8344312 linux-ppc64le -gc/shenandoah/TestEvilSyncBug.java#generational 8345501 generic-all +gc/stress/jfr/TestStressAllocationGCEventsWithShenandoah.java#generational 8382335 generic-all +gc/stress/jfr/TestStressAllocationGCEventsWithShenandoah.java#default 8382335 generic-all +gc/stress/jfr/TestStressBigAllocationGCEventsWithShenandoah.java#generational 8382335 generic-all +gc/stress/jfr/TestStressBigAllocationGCEventsWithShenandoah.java#default 8382335 generic-all ############################################################################# @@ -190,9 +193,13 @@ vmTestbase/nsk/monitoring/ThreadMXBean/findMonitorDeadlockedThreads/find006/Test # Preview project specific failures go here at the end of the file. # # These are NOT failures that occur with the '--enable-preview' option -# specified; those go in the appropriate ProblemList-enable-preview.txt file. +# specified in the task definition; those go in the appropriate +# ProblemList-enable-preview.txt file. +# # These are failures that occur WITHOUT the '--enable-preview' option -# specified AND occur because of some issue with preview project code, -# in either implementation or test code. +# specified in the task definition OR the '--enable-preview' option +# MAY BE specified in the test itself. In either case, the failure +# occurs because of some issue with preview project code, in either +# implementation or test code. ############################################################################# diff --git a/test/hotspot/jtreg/compiler/arguments/TestUseCountTrailingZerosInstructionOnSupportedCPU.java b/test/hotspot/jtreg/compiler/arguments/TestUseCountTrailingZerosInstructionOnSupportedCPU.java index 2d344b73802..558c1501314 100644 --- a/test/hotspot/jtreg/compiler/arguments/TestUseCountTrailingZerosInstructionOnSupportedCPU.java +++ b/test/hotspot/jtreg/compiler/arguments/TestUseCountTrailingZerosInstructionOnSupportedCPU.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -67,14 +67,14 @@ public class TestUseCountTrailingZerosInstructionOnSupportedCPU TestUseCountTrailingZerosInstructionOnSupportedCPU.DISABLE_BMI); /* - Verify that option could be turned on even if other BMI1 - instructions were turned off. VM will be launched with following + Verify that option cannot be turned on when BMI1 instructions + are explicitly turned off. VM will be launched with following options: -XX:-UseBMI1Instructions -XX:+UseCountTrailingZerosInstruction -version */ - CommandLineOptionTest.verifyOptionValueForSameVM(optionName, "true", - "Option 'UseCountTrailingZerosInstruction' should be able to " - + "be turned on even if all BMI1 instructions are " + CommandLineOptionTest.verifyOptionValueForSameVM(optionName, "false", + "Option 'UseCountTrailingZerosInstruction' should have " + + "'false' value if all BMI1 instructions are " + "disabled (-XX:-UseBMI1Instructions flag used)", TestUseCountTrailingZerosInstructionOnSupportedCPU.DISABLE_BMI, CommandLineOptionTest.prepareBooleanFlag(optionName, true)); diff --git a/test/hotspot/jtreg/compiler/c2/irTests/TestFloat16ScalarOperations.java b/test/hotspot/jtreg/compiler/c2/irTests/TestFloat16ScalarOperations.java index 445fef5e55a..8f2bbe8a8a7 100644 --- a/test/hotspot/jtreg/compiler/c2/irTests/TestFloat16ScalarOperations.java +++ b/test/hotspot/jtreg/compiler/c2/irTests/TestFloat16ScalarOperations.java @@ -24,7 +24,7 @@ /** * @test -* @bug 8308363 8336406 +* @bug 8308363 8336406 8381617 * @summary Validate compiler IR for various Float16 scalar operations. * @modules jdk.incubator.vector * @requires vm.compiler2.enabled @@ -714,9 +714,13 @@ public class TestFloat16ScalarOperations { @Test @IR(counts = {IRNode.FMA_HF, " 0 ", IRNode.REINTERPRET_S2HF, " 0 ", IRNode.REINTERPRET_HF2S, " 0 "}, - applyIfCPUFeatureOr = {"avx512_fp16", "true", "zfh", "true"}) + applyIfCPUFeatureOr = {"avx512_fp16", "true", "zfh", "true"}, + // On Windows, both GCC and MSVC don't set __STDC_IEC_559__, so FMAs on constants are not folded. + applyIfPlatform = {"windows", "false"}) @IR(counts = {IRNode.FMA_HF, " 0 ", IRNode.REINTERPRET_S2HF, " 0 ", IRNode.REINTERPRET_HF2S, " 0 "}, - applyIfCPUFeatureAnd = {"fphp", "true", "asimdhp", "true"}) + applyIfCPUFeatureAnd = {"fphp", "true", "asimdhp", "true"}, + // On Windows, both GCC and MSVC don't set __STDC_IEC_559__, so FMAs on constants are not folded. + applyIfPlatform = {"windows", "false"}) @Warmup(10000) public void testFMAConstantFolding() { // If any argument is NaN, the result is NaN. @@ -752,9 +756,13 @@ public class TestFloat16ScalarOperations { @Test @IR(failOn = {IRNode.ADD_HF, IRNode.SUB_HF, IRNode.MUL_HF, IRNode.DIV_HF, IRNode.SQRT_HF, IRNode.FMA_HF}, - applyIfCPUFeatureOr = {"avx512_fp16", "true", "zfh", "true"}) + applyIfCPUFeatureOr = {"avx512_fp16", "true", "zfh", "true"}, + // On Windows, both GCC and MSVC don't set __STDC_IEC_559__, so FMAs on constants are not folded. + applyIfPlatform = {"windows", "false"}) @IR(failOn = {IRNode.ADD_HF, IRNode.SUB_HF, IRNode.MUL_HF, IRNode.DIV_HF, IRNode.SQRT_HF, IRNode.FMA_HF}, - applyIfCPUFeatureAnd = {"fphp", "true", "asimdhp", "true"}) + applyIfCPUFeatureAnd = {"fphp", "true", "asimdhp", "true"}, + // On Windows, both GCC and MSVC don't set __STDC_IEC_559__, so FMAs on constants are not folded. + applyIfPlatform = {"windows", "false"}) @Warmup(10000) public void testRounding1() { dst[0] = float16ToRawShortBits(add(RANDOM1, RANDOM2)); diff --git a/test/hotspot/jtreg/compiler/cpuflags/CPUFeaturesClearTest.java b/test/hotspot/jtreg/compiler/cpuflags/CPUFeaturesClearTest.java index 19768a8dc17..9b243ad6b39 100644 --- a/test/hotspot/jtreg/compiler/cpuflags/CPUFeaturesClearTest.java +++ b/test/hotspot/jtreg/compiler/cpuflags/CPUFeaturesClearTest.java @@ -23,6 +23,7 @@ /* * @test + * @bug 8364584 8381988 * @library /test/lib / * @modules java.base/jdk.internal.misc * java.management @@ -38,6 +39,7 @@ package compiler.cpuflags; import java.util.List; +import java.util.Map; import jdk.test.lib.process.OutputAnalyzer; import jdk.test.lib.Platform; @@ -62,15 +64,23 @@ public class CPUFeaturesClearTest { } public void testX86Flags() throws Throwable { + Map vmFlagToCpuFeatureMap = Map.of("UseCLMUL", "clmul", + "UseAES", "aes", + "UseFMA", "fma", + "UseCountLeadingZerosInstruction", "lzcnt", + "UseBMI1Instructions", "bmi1", + "UseBMI2Instructions", "bmi2", + "UsePopCountInstruction", "popcnt", + "UseSHA", "sha"); + vmFlagToCpuFeatureMap.forEach((vmFlag, cpuFeature) -> { + try { + OutputAnalyzer outputAnalyzer = ProcessTools.executeTestJava(generateArgs(prepareBooleanFlag(vmFlag, false))); + outputAnalyzer.shouldNotMatch("[os,cpu] CPU: .* " + cpuFeature + ".*"); + } catch (Exception e) { + throw new RuntimeException (e); + } + }); OutputAnalyzer outputAnalyzer; - String vmFlagsToTest[] = {"UseCLMUL", "UseAES", "UseFMA", "UseSHA"}; - String cpuFeatures[] = {"clmul", "aes", "fma", "sha"}; - for (int i = 0; i < vmFlagsToTest.length; i++) { - String vmFlag = vmFlagsToTest[i]; - String cpuFeature = cpuFeatures[i]; - outputAnalyzer = ProcessTools.executeTestJava(generateArgs(prepareBooleanFlag(vmFlag, false))); - outputAnalyzer.shouldNotMatch("[os,cpu] CPU: .* " + cpuFeatures[i] + ".*"); - } if (isCpuFeatureSupported("sse4")) { outputAnalyzer = ProcessTools.executeTestJava(generateArgs(prepareNumericFlag("UseSSE", 3))); outputAnalyzer.shouldNotMatch("[os,cpu] CPU: .* sse4.*"); @@ -103,18 +113,20 @@ public class CPUFeaturesClearTest { } public void testAArch64Flags() throws Throwable { - OutputAnalyzer outputAnalyzer; - String vmFlagsToTest[] = {"UseCRC32", "UseLSE", "UseAES"}; - String cpuFeatures[] = {"crc32", "lse", "aes"}; - for (int i = 0; i < vmFlagsToTest.length; i++) { - String vmFlag = vmFlagsToTest[i]; - String cpuFeature = cpuFeatures[i]; - outputAnalyzer = ProcessTools.executeTestJava(generateArgs(prepareBooleanFlag(vmFlag, false))); - outputAnalyzer.shouldNotMatch("[os,cpu] CPU: .* " + cpuFeatures[i] + ".*"); - } + Map vmFlagToCpuFeatureMap = Map.of("UseCRC32", "crc32", + "UseLSE", "lse", + "UseAES", "aes"); + vmFlagToCpuFeatureMap.forEach((vmFlag, cpuFeature) -> { + try { + OutputAnalyzer outputAnalyzer = ProcessTools.executeTestJava(generateArgs(prepareBooleanFlag(vmFlag, false))); + outputAnalyzer.shouldNotMatch("[os,cpu] CPU: .* " + cpuFeature + ".*"); + } catch (Exception e) { + throw new RuntimeException(e); + } + }); // Disabling UseSHA should clear all shaXXX cpu features - outputAnalyzer = ProcessTools.executeTestJava(generateArgs(prepareBooleanFlag("UseSHA", false))); + OutputAnalyzer outputAnalyzer = ProcessTools.executeTestJava(generateArgs(prepareBooleanFlag("UseSHA", false))); outputAnalyzer.shouldNotMatch("[os,cpu] CPU: .* sha1.*"); outputAnalyzer.shouldNotMatch("[os,cpu] CPU: .* sha256.*"); outputAnalyzer.shouldNotMatch("[os,cpu] CPU: .* sha3.*"); diff --git a/test/hotspot/jtreg/compiler/debug/TestStressBailout.java b/test/hotspot/jtreg/compiler/debug/TestStressBailout.java index 68610576a39..f79cb679c41 100644 --- a/test/hotspot/jtreg/compiler/debug/TestStressBailout.java +++ b/test/hotspot/jtreg/compiler/debug/TestStressBailout.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2024, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -24,6 +24,7 @@ package compiler.debug; import java.util.Random; +import java.util.stream.Stream; import jdk.test.lib.process.OutputAnalyzer; import jdk.test.lib.process.ProcessTools; @@ -36,24 +37,33 @@ import jdk.test.lib.Utils; * @requires vm.debug == true & vm.compiler2.enabled & (vm.opt.AbortVMOnCompilationFailure == "null" | !vm.opt.AbortVMOnCompilationFailure) * @summary Basic tests for bailout stress flag. * @library /test/lib / - * @run driver compiler.debug.TestStressBailout + * @run main compiler.debug.TestStressBailout + */ + +/* + * @test + * @key stress randomness + * @bug 8375905 + * @requires vm.debug == true & vm.compiler2.enabled & (vm.opt.AbortVMOnCompilationFailure == "null" | !vm.opt.AbortVMOnCompilationFailure) + * @summary Additional crashes revealed by diagnostic code run during VerifyIterativeGVN + * @library /test/lib / + * @run main compiler.debug.TestStressBailout -XX:VerifyIterativeGVN=1111 */ public class TestStressBailout { - static void runTest(int invprob) throws Exception { - String[] procArgs = {"-Xcomp", "-XX:-TieredCompilation", "-XX:+StressBailout", - "-XX:StressBailoutMean=" + invprob, "-version"}; - ProcessBuilder pb = ProcessTools.createTestJavaProcessBuilder(procArgs); + static void runTest(int invprob, Stream vmArgs) throws Exception { + Stream procArgs = Stream.of("-Xcomp", "-XX:-TieredCompilation", "-XX:+StressBailout", "-XX:StressBailoutMean=" + invprob, "-version"); + ProcessBuilder pb = ProcessTools.createTestJavaProcessBuilder(Stream.concat(vmArgs, procArgs).toArray(x -> new String[x])); OutputAnalyzer out = new OutputAnalyzer(pb.start()); out.shouldHaveExitValue(0); } - public static void main(String[] args) throws Exception { + public static void main(String[] vmArgs) throws Exception { Random r = Utils.getRandomInstance(); // Likely bail out on -version, for some low Mean value. - runTest(r.nextInt(1, 10)); + runTest(r.nextInt(1, 10), Stream.of(vmArgs)); // Higher value - runTest(r.nextInt(10, 1_000_000)); + runTest(r.nextInt(10, 1_000_000), Stream.of(vmArgs)); } } diff --git a/test/hotspot/jtreg/compiler/gcbarriers/TestImplicitNullChecks.java b/test/hotspot/jtreg/compiler/gcbarriers/TestImplicitNullChecks.java index 34583b8fea9..06057a34b61 100644 --- a/test/hotspot/jtreg/compiler/gcbarriers/TestImplicitNullChecks.java +++ b/test/hotspot/jtreg/compiler/gcbarriers/TestImplicitNullChecks.java @@ -64,6 +64,8 @@ public class TestImplicitNullChecks { public static void main(String[] args) { TestFramework.runWithFlags("-XX:CompileCommand=inline,java.lang.ref.*::*", "-XX:-TieredCompilation"); + TestFramework.runWithFlags("-XX:CompileCommand=inline,java.lang.ref.*::*", + "-XX:+TieredCompilation", "-XX:TieredStopAtLevel=1"); } @Test diff --git a/test/hotspot/jtreg/compiler/igvn/TestIncorrectDeadPathTypeNode.java b/test/hotspot/jtreg/compiler/igvn/TestIncorrectDeadPathTypeNode.java new file mode 100644 index 00000000000..071c959477e --- /dev/null +++ b/test/hotspot/jtreg/compiler/igvn/TestIncorrectDeadPathTypeNode.java @@ -0,0 +1,138 @@ +/* + * Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * 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 8376587 + * @summary Fatal "dead path discovered by TypeNode during igvn" after C2 compilation + * @run main/othervm -Xbatch -XX:-TieredCompilation -XX:+UnlockDiagnosticVMOptions -XX:+StressIGVN -XX:StressSeed=24476278 ${test.main.class} + * @run main/othervm -Xbatch -XX:-TieredCompilation -XX:+UnlockDiagnosticVMOptions -XX:+StressIGVN ${test.main.class} + * @run main ${test.main.class} + */ + +package compiler.igvn; + +public class TestIncorrectDeadPathTypeNode { + boolean ltIndirect(int p0, int p1) { + return lt(p0, p1); + } + static boolean lt(int p0, int p1) { return p0 < p1; } + boolean ltInstance(int p0, int p1) { return p0 < p1; } + + boolean _mutatorToggle; + boolean _mutatorFlip() { return _mutatorToggle; } + + static class MyInteger { + int v; + MyInteger(int v) { + for (int i = 0; i < 4; i++) + for (int j = 0; j < 8; j++) + switch (i) { + case -2, -3: + case 0: + this.v = v; + } + int limit = 2; + for (; limit < 4; limit *= 2) {} + for (int peel = 2; peel < limit; peel++) {} + } + } + + void test() { + Byte x = 1; + boolean flag = _mutatorFlip(); + int limit = 2; + for (; limit < 4; limit *= 2) {} + int zero = 4; + for (int peel = 2; peel < limit; peel++) { + zero = 0; + } + for (int i = 0; i < 10000; i++) { + if (flag) {} + if (zero == 0) { + if ((i & 1) == 0) { + for (int j = 0; j < 32; j++) { + if (j < 10) { + x = (byte)x; + } + } + for (int j = 0; j < 2; j++) { + if (ltIndirect(j, 10)) { + x = (byte)x; + } + } + int Nj = 32; + for (int j = 0; j < Nj; j++) { + if (j < 10) { + Object o = ""; + for (int k = 0; k < 32; k++) { + o.toString(); + } + Integer.valueOf(1).toString(); + for (int k = 0; k < 32; k++) { + if (k < 10) { + x = (byte)x; + } + } + x = (byte)x; + } + } + for (int j = 0; j < 4; j++) { + for (int k = 0; k < 8; k++) { + switch (j) { + case -2, -3: + case 0: + x = (byte)x; + } + } + } + for (int j = 0; j < 4; j++) { + for (int k = 0; lt(new MyInteger(k).v, 8); k++) { + switch (j) { + case -2, -3: + case 0: + x = (byte)x; + } + } + } + for (int j = 0; ltInstance(j, 4); j++) { + for (int k = 0; k < 8; k++) { + switch (j) { + case -2, -3: + case 0: + x = (byte)x; + } + } + } + x = (byte)x; + } + } + } + } + + public static void main(String args[]) { + TestIncorrectDeadPathTypeNode t = new TestIncorrectDeadPathTypeNode(); + t.test(); + } +} + diff --git a/test/hotspot/jtreg/compiler/inlining/LateInlineQueueDrainTest.java b/test/hotspot/jtreg/compiler/inlining/LateInlineQueueDrainTest.java new file mode 100644 index 00000000000..9675274b3b1 --- /dev/null +++ b/test/hotspot/jtreg/compiler/inlining/LateInlineQueueDrainTest.java @@ -0,0 +1,146 @@ +/* + * Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * 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 8381362 + * @summary Verify no crash for vector late-inline queue draining when MH/virtual late inlining is disabled + * @modules jdk.incubator.vector + * @run main/othervm -Xcomp -XX:+UnlockDiagnosticVMOptions + * -XX:-IncrementalInlineVirtual -XX:-IncrementalInlineMH -XX:-UseInlineCaches + * ${test.main.class} vector + */ + +/* + * @test + * @bug 8381362 + * @summary Verify no crash for non-vector late-inline queue draining when MH/virtual late inlining is disabled + * @modules jdk.incubator.vector + * @run main/othervm -Xcomp -XX:+UnlockDiagnosticVMOptions + * -XX:-IncrementalInlineVirtual -XX:-IncrementalInlineMH -XX:-UseInlineCaches + * -XX:LiveNodeCountInliningCutoff=50 + * -XX:CompileCommand=compileonly,${test.main.class}::nonVector* + * -XX:CompileCommand=delayinline,${test.main.class}::lateInline* + * ${test.main.class} nonvector + */ + +package compiler.inlining; + +import jdk.incubator.vector.*; +import java.lang.invoke.VarHandle; + +public class LateInlineQueueDrainTest { + private static final int SIZE = 60_000; + private static int sink; + + public static void main(String[] args) { + sink = 0; + if (args.length != 1) { + throw new RuntimeException("Expected one argument: vector|nonvector"); + } + switch (args[0]) { + case "vector": + vectorWorkload(); + break; + case "nonvector": + nonVectorWorkload(); + break; + default: + throw new RuntimeException("Unknown mode: " + args[0]); + } + System.out.println("PASS " + args[0] + " " + sink); + } + + private static void vectorWorkload() { + char[] a = new char[SIZE]; + char[] b = new char[SIZE]; + for (int i = 0; i < SIZE; i++) { + a[i] = (char) i; + b[i] = (char) i; + } + vectorKernel(a); + } + + private static void vectorKernel(char[] arr) { + FloatVector lcFloatVec2 = null; + FloatVector lcFloatVec1 = null; + float[] lcFloatArr1 = new float[100]; + float[] lcFloatArr2 = new float[100]; + float[] lcFloatArr3 = new float[100]; + Object Obj = new Object(); + for (int i = 0; i < lcFloatArr1.length; i++) { + lcFloatArr1[i] = (((float) i) * 1.5F) + 7.89F; + } + for (int i = 0; i < lcFloatArr2.length; i++) { + lcFloatArr2[i] = (((float) i) * 1.5F) + 7.89F; + } + for (int i = 0; i < lcFloatArr3.length; i++) { + lcFloatArr3[i] = (((float) i) * 1.5F) + 7.89F; + } + for (int i = 0; i < 50; i++) { + VarHandle.fullFence(); + synchronized (Obj) { + try { + Obj.wait(1); + } catch (InterruptedException ex) { + } + } + VarHandle.fullFence(); + if ((((int) (lcFloatArr1[0])) % 3) < 1) { + lcFloatVec1 = ((FloatVector) (VectorShuffle.iota(FloatVector.SPECIES_PREFERRED, 0, 14, true).toVector())); + } else { + lcFloatVec1 = FloatVector.fromArray(FloatVector.SPECIES_PREFERRED, lcFloatArr2, 14); + } + lcFloatVec1 = FloatVector.fromArray(FloatVector.SPECIES_PREFERRED, lcFloatArr3, 14); + lcFloatVec2 = lcFloatVec1.add(lcFloatVec1); + lcFloatVec2.intoArray(lcFloatArr1, 14); + synchronized (Obj) { + try { + Obj.wait(1); + } catch (InterruptedException ex) { + } + } + } + } + + private static void nonVectorWorkload() { + int r = 0; + for (int i = 0; i < 200_000; i++) { + r += nonVectorKernel(100); + } + sink += r; + } + + private static int nonVectorKernel(int n) { + int s = 0; + for (int i = 0; i < n; i++) { + lateInline(i); + s += i; + } + return s; + } + + private static void lateInline(int x) { + sink += x; + } +} diff --git a/test/hotspot/jtreg/compiler/intrinsics/TestReferenceGet.java b/test/hotspot/jtreg/compiler/intrinsics/TestReferenceGet.java new file mode 100644 index 00000000000..6fca3e9df14 --- /dev/null +++ b/test/hotspot/jtreg/compiler/intrinsics/TestReferenceGet.java @@ -0,0 +1,175 @@ +/* + * Copyright (c) 2020, 2026, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * 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 8382815 + * @run main/othervm -XX:CompileCommand=dontinline,${test.main.class}::test_* ${test.main.class} + */ + +package compiler.intrinsics; + +import java.lang.ref.Reference; +import java.lang.ref.ReferenceQueue; +import java.lang.ref.PhantomReference; +import java.lang.ref.SoftReference; +import java.lang.ref.WeakReference; + +public class TestReferenceGet { + private static final void fail(String msg) throws Exception { + throw new RuntimeException(msg); + } + + private static final void test0(Reference ref, + Object expectedValue, + Object unexpectedValue, + String kind) throws Exception { + if ((expectedValue != null) && ref.get() == null) { + fail(kind + " refers to null"); + } + if (ref.get() != expectedValue) { + fail(kind + " doesn't refer to expected value"); + } + if (ref.get() == unexpectedValue) { + fail(kind + " refers to unexpected value"); + } + } + + private static final void test_phantom0(PhantomReference ref, + String kind) throws Exception { + if (ref.get() != null) { + fail(kind + " does not refer to null"); + } + } + + // Entry points to the test, important to push down type information to + // individual test methods. + + private static final void test_phantom(PhantomReference ref) throws Exception { + test_phantom0(ref, "phantom"); + } + + private static final void test_phantom_shadow(ShadowPhantomReference ref) throws Exception { + test_phantom0(ref, "phantom shadow"); + } + + private static final void test_weak(WeakReference ref, + Object expectedValue, + Object unexpectedValue) throws Exception { + test0(ref, expectedValue, unexpectedValue, "weak"); + } + + private static final void test_weak_shadow(ShadowWeakReference ref, + Object expectedValue, + Object unexpectedValue) throws Exception { + test0(ref, expectedValue, unexpectedValue, "weak shadow"); + } + + private static final void test_soft(SoftReference ref, + Object expectedValue, + Object unexpectedValue) throws Exception { + test0(ref, expectedValue, unexpectedValue, "soft"); + } + + private static final void test_soft_shadow(ShadowSoftReference ref, + Object expectedValue, + Object unexpectedValue) throws Exception { + test0(ref, expectedValue, unexpectedValue, "soft shadow"); + } + + static Object unexpected = new Object(); + + static Object obj0 = new Object(); + static Object obj1 = new Object(); + static Object obj2 = new Object(); + static Object obj3 = new Object(); + static Object obj4 = new Object(); + static Object obj5 = new Object(); + + public static void main(String[] args) throws Exception { + var queue = new ReferenceQueue(); + + // It is important to do all test methods in the loop, so that we + // exercise all paths in intrinsics. + for (int i = 0; i < 100000; i++) { + System.out.println("Create"); + var pref = new PhantomReference(obj0, queue); + var wref = new WeakReference(obj1); + var sref = new SoftReference(obj2); + var psref = new ShadowPhantomReference<>(obj3, queue); + var wsref = new ShadowWeakReference<>(obj4); + var ssref = new ShadowSoftReference<>(obj5); + + System.out.println("After creation"); + test_phantom(pref); + test_weak(wref, obj1, unexpected); + test_soft(sref, obj2, unexpected); + test_phantom_shadow(psref); + test_weak_shadow(wsref, obj4, unexpected); + test_soft_shadow(ssref, obj5, unexpected); + + System.out.println("Cleaning references"); + pref.clear(); + wref.clear(); + sref.clear(); + psref.clear(); + wsref.clear(); + ssref.clear(); + + System.out.println("Testing after cleaning"); + test_phantom(pref); + test_weak(wref, null, unexpected); + test_soft(sref, null, unexpected); + test_phantom_shadow(psref); + test_weak_shadow(wsref, null, unexpected); + test_soft_shadow(ssref, null, unexpected); + } + } + + // References that have their own "shadow" referent. Check that intrinsics + // hit the right referent. + + static class ShadowSoftReference extends SoftReference { + T referent; + public ShadowSoftReference(T ref) { + super(ref); + referent = ref; + } + } + + static class ShadowWeakReference extends WeakReference { + T referent; + public ShadowWeakReference(T ref) { + super(ref); + referent = ref; + } + } + + static class ShadowPhantomReference extends PhantomReference { + T referent; + public ShadowPhantomReference(T ref, ReferenceQueue q) { + super(ref, q); + referent = ref; + } + } +} diff --git a/test/hotspot/jtreg/compiler/intrinsics/TestReferenceRefersTo.java b/test/hotspot/jtreg/compiler/intrinsics/TestReferenceRefersTo.java index f9d36131a8b..c66edb8a6ad 100644 --- a/test/hotspot/jtreg/compiler/intrinsics/TestReferenceRefersTo.java +++ b/test/hotspot/jtreg/compiler/intrinsics/TestReferenceRefersTo.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,10 +23,13 @@ /* * @test - * @bug 8256377 + * @bug 8256377 8382815 * @summary Based on test/jdk/java/lang/ref/ReferenceRefersTo.java. + * @run main/othervm -XX:CompileCommand=dontinline,${test.main.class}::test_* ${test.main.class} */ +package compiler.intrinsics; + import java.lang.ref.Reference; import java.lang.ref.ReferenceQueue; import java.lang.ref.PhantomReference; @@ -39,7 +42,7 @@ public class TestReferenceRefersTo { } // Test java.lang.ref.Reference::refersTo0 intrinsic. - private static final void test(Reference ref, + private static final void test0(Reference ref, Object expectedValue, Object unexpectedValue, String kind) throws Exception { @@ -55,10 +58,10 @@ public class TestReferenceRefersTo { } // Test java.lang.ref.PhantomReference::refersTo0 intrinsic. - private static final void test_phantom(PhantomReference ref, + private static final void test_phantom0(PhantomReference ref, Object expectedValue, - Object unexpectedValue) throws Exception { - String kind = "phantom"; + Object unexpectedValue, + String kind) throws Exception { if ((expectedValue != null) && ref.refersTo(null)) { fail(kind + " refers to null"); } @@ -68,53 +71,120 @@ public class TestReferenceRefersTo { if (ref.refersTo(unexpectedValue)) { fail(kind + " refers to unexpected value"); } + } + // Entry points to the test, important to push down type information to + // individual test methods. + + private static final void test_phantom(PhantomReference ref, + Object expectedValue, + Object unexpectedValue) throws Exception { + test_phantom0(ref, expectedValue, unexpectedValue, "phantom"); + } + + private static final void test_phantom_shadow(ShadowPhantomReference ref, + Object expectedValue, + Object unexpectedValue) throws Exception { + test_phantom0(ref, expectedValue, unexpectedValue, "phantom shadow"); } private static final void test_weak(WeakReference ref, Object expectedValue, Object unexpectedValue) throws Exception { - test(ref, expectedValue, unexpectedValue, "weak"); + test0(ref, expectedValue, unexpectedValue, "weak"); + } + + private static final void test_weak_shadow(ShadowWeakReference ref, + Object expectedValue, + Object unexpectedValue) throws Exception { + test0(ref, expectedValue, unexpectedValue, "weak shadow"); } private static final void test_soft(SoftReference ref, Object expectedValue, Object unexpectedValue) throws Exception { - test(ref, expectedValue, unexpectedValue, "soft"); + test0(ref, expectedValue, unexpectedValue, "soft"); } + private static final void test_soft_shadow(ShadowSoftReference ref, + Object expectedValue, + Object unexpectedValue) throws Exception { + test0(ref, expectedValue, unexpectedValue, "soft shadow"); + } + + static Object unexpected = new Object(); + + static Object obj0 = new Object(); + static Object obj1 = new Object(); + static Object obj2 = new Object(); + static Object obj3 = new Object(); + static Object obj4 = new Object(); + static Object obj5 = new Object(); + public static void main(String[] args) throws Exception { var queue = new ReferenceQueue(); - var obj0 = new Object(); - var obj1 = new Object(); - var obj2 = new Object(); - var obj3 = new Object(); + // It is important to do all test methods in the loop, so that we + // exercise all paths in intrinsics. + for (int i = 0; i < 100000; i++) { + System.out.println("Create"); + var pref = new PhantomReference(obj0, queue); + var wref = new WeakReference(obj1); + var sref = new SoftReference(obj2); + var psref = new ShadowPhantomReference<>(obj3, queue); + var wsref = new ShadowWeakReference<>(obj4); + var ssref = new ShadowSoftReference<>(obj5); - var pref = new PhantomReference(obj0, queue); - var wref = new WeakReference(obj1); - var sref = new SoftReference(obj2); + System.out.println("After creation"); + test_phantom(pref, obj0, unexpected); + test_weak(wref, obj1, unexpected); + test_soft(sref, obj2, unexpected); + test_phantom_shadow(psref, obj3, unexpected); + test_weak_shadow(wsref, obj4, unexpected); + test_soft_shadow(ssref, obj5, unexpected); - System.out.println("Warmup"); - for (int i = 0; i < 10000; i++) { - test_phantom(pref, obj0, obj3); - test_weak(wref, obj1, obj3); - test_soft(sref, obj2, obj3); + System.out.println("Cleaning references"); + pref.clear(); + wref.clear(); + sref.clear(); + psref.clear(); + wsref.clear(); + ssref.clear(); + + System.out.println("Testing after cleaning"); + test_phantom(pref, null, unexpected); + test_weak(wref, null, unexpected); + test_soft(sref, null, unexpected); + test_phantom_shadow(psref, null, unexpected); + test_weak_shadow(wsref, null, unexpected); + test_soft_shadow(ssref, null, unexpected); } + } - System.out.println("Testing starts"); - test_phantom(pref, obj0, obj3); - test_weak(wref, obj1, obj3); - test_soft(sref, obj2, obj3); + // References that have their own "shadow" referent. Check that intrinsics + // hit the right referent. - System.out.println("Cleaning references"); - pref.clear(); - wref.clear(); - sref.clear(); + static class ShadowSoftReference extends SoftReference { + T referent; + public ShadowSoftReference(T ref) { + super(ref); + referent = ref; + } + } - System.out.println("Testing after cleaning"); - test_phantom(pref, null, obj3); - test_weak(wref, null, obj3); - test_soft(sref, null, obj3); + static class ShadowWeakReference extends WeakReference { + T referent; + public ShadowWeakReference(T ref) { + super(ref); + referent = ref; + } + } + + static class ShadowPhantomReference extends PhantomReference { + T referent; + public ShadowPhantomReference(T ref, ReferenceQueue q) { + super(ref, q); + referent = ref; + } } } diff --git a/test/hotspot/jtreg/compiler/intrinsics/bmi/verifycode/AndnTestI.java b/test/hotspot/jtreg/compiler/intrinsics/bmi/verifycode/AndnTestI.java index 30ce3b36af6..d2fc3f29a75 100644 --- a/test/hotspot/jtreg/compiler/intrinsics/bmi/verifycode/AndnTestI.java +++ b/test/hotspot/jtreg/compiler/intrinsics/bmi/verifycode/AndnTestI.java @@ -24,7 +24,7 @@ /* * @test * @bug 8031321 - * @requires vm.flavor == "server" & !vm.graal.enabled + * @requires vm.flavor == "server" & !vm.graal.enabled & vm.cpu.features ~= ".*avx.*" * @library /test/lib / * @modules java.base/jdk.internal.misc * java.management diff --git a/test/hotspot/jtreg/compiler/intrinsics/bmi/verifycode/AndnTestL.java b/test/hotspot/jtreg/compiler/intrinsics/bmi/verifycode/AndnTestL.java index 1a3e7e1314d..374da537619 100644 --- a/test/hotspot/jtreg/compiler/intrinsics/bmi/verifycode/AndnTestL.java +++ b/test/hotspot/jtreg/compiler/intrinsics/bmi/verifycode/AndnTestL.java @@ -24,7 +24,7 @@ /* * @test * @bug 8031321 - * @requires vm.flavor == "server" & !vm.graal.enabled + * @requires vm.flavor == "server" & !vm.graal.enabled & vm.cpu.features ~= ".*avx.*" * @library /test/lib / * @modules java.base/jdk.internal.misc * java.management diff --git a/test/hotspot/jtreg/compiler/intrinsics/bmi/verifycode/BlsiTestI.java b/test/hotspot/jtreg/compiler/intrinsics/bmi/verifycode/BlsiTestI.java index 71d9e52a539..645fde13534 100644 --- a/test/hotspot/jtreg/compiler/intrinsics/bmi/verifycode/BlsiTestI.java +++ b/test/hotspot/jtreg/compiler/intrinsics/bmi/verifycode/BlsiTestI.java @@ -24,7 +24,7 @@ /* * @test * @bug 8031321 - * @requires vm.flavor == "server" & !vm.graal.enabled + * @requires vm.flavor == "server" & !vm.graal.enabled & vm.cpu.features ~= ".*avx.*" * @library /test/lib / * @modules java.base/jdk.internal.misc * java.management diff --git a/test/hotspot/jtreg/compiler/intrinsics/bmi/verifycode/BlsiTestL.java b/test/hotspot/jtreg/compiler/intrinsics/bmi/verifycode/BlsiTestL.java index 425f70f1052..8531f8580c1 100644 --- a/test/hotspot/jtreg/compiler/intrinsics/bmi/verifycode/BlsiTestL.java +++ b/test/hotspot/jtreg/compiler/intrinsics/bmi/verifycode/BlsiTestL.java @@ -24,7 +24,7 @@ /* * @test * @bug 8031321 - * @requires vm.flavor == "server" & !vm.graal.enabled + * @requires vm.flavor == "server" & !vm.graal.enabled & vm.cpu.features ~= ".*avx.*" * @library /test/lib / * @modules java.base/jdk.internal.misc * java.management diff --git a/test/hotspot/jtreg/compiler/intrinsics/bmi/verifycode/BlsmskTestI.java b/test/hotspot/jtreg/compiler/intrinsics/bmi/verifycode/BlsmskTestI.java index 3632d9617b8..2509ed281c3 100644 --- a/test/hotspot/jtreg/compiler/intrinsics/bmi/verifycode/BlsmskTestI.java +++ b/test/hotspot/jtreg/compiler/intrinsics/bmi/verifycode/BlsmskTestI.java @@ -24,7 +24,7 @@ /* * @test * @bug 8031321 - * @requires vm.flavor == "server" & !vm.graal.enabled + * @requires vm.flavor == "server" & !vm.graal.enabled & vm.cpu.features ~= ".*avx.*" * @library /test/lib / * @modules java.base/jdk.internal.misc * java.management diff --git a/test/hotspot/jtreg/compiler/intrinsics/bmi/verifycode/BlsmskTestL.java b/test/hotspot/jtreg/compiler/intrinsics/bmi/verifycode/BlsmskTestL.java index 8f6958d212f..33223c595a6 100644 --- a/test/hotspot/jtreg/compiler/intrinsics/bmi/verifycode/BlsmskTestL.java +++ b/test/hotspot/jtreg/compiler/intrinsics/bmi/verifycode/BlsmskTestL.java @@ -24,7 +24,7 @@ /* * @test * @bug 8031321 - * @requires vm.flavor == "server" & !vm.graal.enabled + * @requires vm.flavor == "server" & !vm.graal.enabled & vm.cpu.features ~= ".*avx.*" * @library /test/lib / * @modules java.base/jdk.internal.misc * java.management diff --git a/test/hotspot/jtreg/compiler/intrinsics/bmi/verifycode/BlsrTestI.java b/test/hotspot/jtreg/compiler/intrinsics/bmi/verifycode/BlsrTestI.java index bd8c26724a1..2c249db8fd0 100644 --- a/test/hotspot/jtreg/compiler/intrinsics/bmi/verifycode/BlsrTestI.java +++ b/test/hotspot/jtreg/compiler/intrinsics/bmi/verifycode/BlsrTestI.java @@ -24,7 +24,7 @@ /* * @test * @bug 8031321 - * @requires vm.flavor == "server" & !vm.graal.enabled + * @requires vm.flavor == "server" & !vm.graal.enabled & vm.cpu.features ~= ".*avx.*" * @library /test/lib / * @modules java.base/jdk.internal.misc * java.management diff --git a/test/hotspot/jtreg/compiler/intrinsics/bmi/verifycode/BlsrTestL.java b/test/hotspot/jtreg/compiler/intrinsics/bmi/verifycode/BlsrTestL.java index 68f82a99bd3..4082cd4aa5b 100644 --- a/test/hotspot/jtreg/compiler/intrinsics/bmi/verifycode/BlsrTestL.java +++ b/test/hotspot/jtreg/compiler/intrinsics/bmi/verifycode/BlsrTestL.java @@ -24,7 +24,7 @@ /* * @test * @bug 8031321 - * @requires vm.flavor == "server" & !vm.graal.enabled + * @requires vm.flavor == "server" & !vm.graal.enabled & vm.cpu.features ~= ".*avx.*" * @library /test/lib / * @modules java.base/jdk.internal.misc * java.management diff --git a/test/hotspot/jtreg/compiler/intrinsics/bmi/verifycode/BmiIntrinsicBase.java b/test/hotspot/jtreg/compiler/intrinsics/bmi/verifycode/BmiIntrinsicBase.java index 8c6120388a1..425f3a92518 100644 --- a/test/hotspot/jtreg/compiler/intrinsics/bmi/verifycode/BmiIntrinsicBase.java +++ b/test/hotspot/jtreg/compiler/intrinsics/bmi/verifycode/BmiIntrinsicBase.java @@ -36,6 +36,7 @@ import java.lang.reflect.Executable; import java.lang.reflect.Method; import java.util.concurrent.Callable; import java.util.function.Function; +import java.util.List; public class BmiIntrinsicBase extends CompilerWhiteBoxTest { diff --git a/test/hotspot/jtreg/compiler/loopopts/TestLoopPeelingDisabled.java b/test/hotspot/jtreg/compiler/loopopts/TestLoopPeelingDisabled.java index e7bbe24d1de..f8ee2084f3e 100644 --- a/test/hotspot/jtreg/compiler/loopopts/TestLoopPeelingDisabled.java +++ b/test/hotspot/jtreg/compiler/loopopts/TestLoopPeelingDisabled.java @@ -51,11 +51,14 @@ public class TestLoopPeelingDisabled { // elide the {BEFORE,AFTER}_LOOP_PEELING compilation phases, causing the // test to throw an IRViolationException. We then check whether the // exception message matches our expectation (that the loop peeling - // phase was not found). + // phase was not found). If IR verification is disabled, this test will + // not throw an IRViolationException. try { TestFramework.runWithFlags("-XX:+UnlockDiagnosticVMOptions", "-XX:LoopPeeling=0"); - Asserts.fail("Expected IRViolationException"); + String verifyIR = System.getProperty("VerifyIR", "true"); + String msg = "Expected IRViolationException when performing IR matching"; + Asserts.assertFalse(Boolean.parseBoolean(verifyIR), msg); } catch (IRViolationException e) { String info = e.getExceptionInfo(); if (!info.contains("NO compilation output found for this phase")) { diff --git a/test/hotspot/jtreg/compiler/loopopts/superword/TestDependencyOffsets.java b/test/hotspot/jtreg/compiler/loopopts/superword/TestDependencyOffsets.java index 2678aab9c40..8179c33557c 100644 --- a/test/hotspot/jtreg/compiler/loopopts/superword/TestDependencyOffsets.java +++ b/test/hotspot/jtreg/compiler/loopopts/superword/TestDependencyOffsets.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -96,6 +96,7 @@ /* * @test id=sse4-v004-A * @bug 8298935 8308606 8310308 8312570 8310190 + * @key randomness * @summary Test SuperWord: vector size, offsets, dependencies, alignment. * @requires vm.compiler2.enabled * @requires (os.arch=="x86" | os.arch=="i386" | os.arch=="amd64" | os.arch=="x86_64") diff --git a/test/hotspot/jtreg/compiler/loopopts/superword/TestReductions.java b/test/hotspot/jtreg/compiler/loopopts/superword/TestReductions.java index 97a55ae2074..599e95bd6ab 100644 --- a/test/hotspot/jtreg/compiler/loopopts/superword/TestReductions.java +++ b/test/hotspot/jtreg/compiler/loopopts/superword/TestReductions.java @@ -33,7 +33,7 @@ /* * @test id=vanilla - * @bug 8340093 8342095 + * @bug 8340093 8342095 8381617 * @summary Test vectorization of reduction loops. * @modules jdk.incubator.vector * @library /test/lib / @@ -42,7 +42,7 @@ /* * @test id=force-vectorization - * @bug 8340093 8342095 + * @bug 8340093 8342095 8381617 * @summary Test vectorization of reduction loops. * @modules jdk.incubator.vector * @library /test/lib / @@ -1802,7 +1802,7 @@ public class TestReductions { @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.MUL_REDUCTION_VL, "> 0", IRNode.MUL_VL, "> 0"}, // vector accumulator - applyIfCPUFeature = {"avx512dq", "true"}, + applyIfCPUFeatureOr = {"avx512dq", "true", "sve", "true"}, applyIf = {"AutoVectorizationOverrideProfitability", "> 0"}) @IR(failOn = IRNode.LOAD_VECTOR_L, applyIfCPUFeatureAnd = {"avx512dq", "false", "sse4.1", "true"}) @@ -1810,7 +1810,7 @@ public class TestReductions { @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.MUL_REDUCTION_VL, "> 0", IRNode.MUL_VL, "= 0"}, // Reduction NOT moved out of loop - applyIfCPUFeatureOr = {"asimd", "true"}, + applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}, applyIf = {"AutoVectorizationOverrideProfitability", "> 0"}) // Note: NEON does not support MulVL for auto vectorization. There is // a scalarized implementation, but that is not profitable for @@ -1874,10 +1874,10 @@ public class TestReductions { @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.AND_REDUCTION_V, "> 0", IRNode.AND_VL, "> 0"}, - applyIfCPUFeature = {"sse4.1", "true"}, + applyIfCPUFeatureOr = {"sse4.1", "true", "sve", "true"}, applyIf = {"AutoVectorizationOverrideProfitability", "> 0"}) @IR(failOn = IRNode.LOAD_VECTOR_L, - applyIfCPUFeatureAnd = {"asimd", "true"}) + applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) // While AndReductionV is implemented in NEON (see longAndSimple), MulVL is not. // Filed: JDK-8370686 @IR(failOn = IRNode.LOAD_VECTOR_L, @@ -1895,10 +1895,10 @@ public class TestReductions { @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.OR_REDUCTION_V, "> 0", IRNode.OR_VL, "> 0"}, - applyIfCPUFeature = {"sse4.1", "true"}, + applyIfCPUFeatureOr = {"sse4.1", "true", "sve", "true"}, applyIf = {"AutoVectorizationOverrideProfitability", "> 0"}) @IR(failOn = IRNode.LOAD_VECTOR_L, - applyIfCPUFeatureAnd = {"asimd", "true"}) + applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) // While OrReductionV is implemented in NEON (see longOrSimple), MulVL is not. // Filed: JDK-8370686 @IR(failOn = IRNode.LOAD_VECTOR_L, @@ -1916,10 +1916,10 @@ public class TestReductions { @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.XOR_REDUCTION_V, "> 0", IRNode.XOR_VL, "> 0"}, - applyIfCPUFeature = {"sse4.1", "true"}, + applyIfCPUFeatureOr = {"sse4.1", "true", "sve", "true"}, applyIf = {"AutoVectorizationOverrideProfitability", "> 0"}) @IR(failOn = IRNode.LOAD_VECTOR_L, - applyIfCPUFeatureAnd = {"asimd", "true"}) + applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) // While MaxReductionV is implemented in NEON (see longXorSimple), MulVL is not. // Filed: JDK-8370686 @IR(failOn = IRNode.LOAD_VECTOR_L, @@ -1937,10 +1937,10 @@ public class TestReductions { @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_REDUCTION_VL, "> 0", IRNode.ADD_VL, "> 0"}, - applyIfCPUFeature = {"sse4.1", "true"}, + applyIfCPUFeatureOr = {"sse4.1", "true", "sve", "true"}, applyIf = {"AutoVectorizationOverrideProfitability", "> 0"}) @IR(failOn = IRNode.LOAD_VECTOR_L, - applyIfCPUFeatureAnd = {"asimd", "true"}) + applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) // While MaxReductionV is implemented in NEON (see longAddSimple), MulVL is not. // Filed: JDK-8370686 @IR(failOn = IRNode.LOAD_VECTOR_L, @@ -1958,13 +1958,13 @@ public class TestReductions { @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.MUL_REDUCTION_VL, "> 0", IRNode.MUL_VL, "> 0"}, - applyIfCPUFeature = {"avx512dq", "true"}, + applyIfCPUFeatureOr = {"avx512dq", "true", "sve", "true"}, applyIf = {"AutoVectorizationOverrideProfitability", "> 0"}) @IR(failOn = IRNode.LOAD_VECTOR_L, applyIfCPUFeatureAnd = {"avx512dq", "false", "sse4.1", "true"}) // I think this could vectorize, but currently does not. Filed: JDK-8370673 @IR(failOn = IRNode.LOAD_VECTOR_L, - applyIfCPUFeatureAnd = {"asimd", "true"}) + applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) // MulVL is not implemented on NEON, so we also not have the reduction. // Filed: JDK-8370686 @IR(failOn = IRNode.LOAD_VECTOR_L, @@ -1982,13 +1982,13 @@ public class TestReductions { @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.MIN_REDUCTION_V, "> 0", IRNode.MIN_VL, "> 0"}, - applyIfCPUFeature = {"avx512", "true"}, + applyIfCPUFeatureOr = {"avx512", "true", "sve", "true"}, applyIf = {"AutoVectorizationOverrideProfitability", "> 0"}) @IR(failOn = IRNode.LOAD_VECTOR_L, applyIfCPUFeatureAnd = {"avx512", "false", "avx2", "true"}) // I think this could vectorize, but currently does not. Filed: JDK-8370671 @IR(failOn = IRNode.LOAD_VECTOR_L, - applyIfCPUFeatureAnd = {"asimd", "true"}) + applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) // While MaxReductionV is implemented in NEON (see longMinSimple), MulVL is not. // Filed: JDK-8370686 @IR(failOn = IRNode.LOAD_VECTOR_L, @@ -2006,13 +2006,13 @@ public class TestReductions { @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.MAX_REDUCTION_V, "> 0", IRNode.MAX_VL, "> 0"}, - applyIfCPUFeature = {"avx512", "true"}, + applyIfCPUFeatureOr = {"avx512", "true", "sve", "true"}, applyIf = {"AutoVectorizationOverrideProfitability", "> 0"}) @IR(failOn = IRNode.LOAD_VECTOR_L, applyIfCPUFeatureAnd = {"avx512", "false", "avx2", "true"}) // I think this could vectorize, but currently does not. Filed: JDK-8370671 @IR(failOn = IRNode.LOAD_VECTOR_L, - applyIfCPUFeatureAnd = {"asimd", "true"}) + applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) // While MaxReductionV is implemented in NEON (see longMaxSimple), MulVL is not. // Filed: JDK-8370686 @IR(failOn = IRNode.LOAD_VECTOR_L, @@ -2031,10 +2031,10 @@ public class TestReductions { @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.AND_REDUCTION_V, "> 0", IRNode.AND_VL, "> 0"}, - applyIfCPUFeature = {"sse4.1", "true"}, + applyIfCPUFeatureOr = {"sse4.1", "true", "sve", "true"}, applyIf = {"AutoVectorizationOverrideProfitability", "> 0"}) @IR(failOn = IRNode.LOAD_VECTOR_L, - applyIfCPUFeatureAnd = {"asimd", "true"}) + applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) // While AndReductionV is implemented in NEON (see longAndSimple), MulVL is not. // Filed: JDK-8370686 @IR(failOn = IRNode.LOAD_VECTOR_L, @@ -2052,10 +2052,10 @@ public class TestReductions { @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.OR_REDUCTION_V, "> 0", IRNode.OR_VL, "> 0"}, - applyIfCPUFeature = {"sse4.1", "true"}, + applyIfCPUFeatureOr = {"sse4.1", "true", "sve", "true"}, applyIf = {"AutoVectorizationOverrideProfitability", "> 0"}) @IR(failOn = IRNode.LOAD_VECTOR_L, - applyIfCPUFeatureAnd = {"asimd", "true"}) + applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) // While OrReductionV is implemented in NEON (see longOrSimple), MulVL is not. // Filed: JDK-8370686 @IR(failOn = IRNode.LOAD_VECTOR_L, @@ -2073,10 +2073,10 @@ public class TestReductions { @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.XOR_REDUCTION_V, "> 0", IRNode.XOR_VL, "> 0"}, - applyIfCPUFeature = {"sse4.1", "true"}, + applyIfCPUFeatureOr = {"sse4.1", "true", "sve", "true"}, applyIf = {"AutoVectorizationOverrideProfitability", "> 0"}) @IR(failOn = IRNode.LOAD_VECTOR_L, - applyIfCPUFeatureAnd = {"asimd", "true"}) + applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) // While MaxReductionV is implemented in NEON (see longXorSimple), MulVL is not. // Filed: JDK-8370686 @IR(failOn = IRNode.LOAD_VECTOR_L, @@ -2094,10 +2094,10 @@ public class TestReductions { @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.ADD_REDUCTION_VL, "> 0", IRNode.ADD_VL, "> 0"}, - applyIfCPUFeature = {"sse4.1", "true"}, + applyIfCPUFeatureOr = {"sse4.1", "true", "sve", "true"}, applyIf = {"AutoVectorizationOverrideProfitability", "> 0"}) @IR(failOn = IRNode.LOAD_VECTOR_L, - applyIfCPUFeatureAnd = {"asimd", "true"}) + applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) // While MaxReductionV is implemented in NEON (see longAddSimple), MulVL is not. // Filed: JDK-8370686 @IR(failOn = IRNode.LOAD_VECTOR_L, @@ -2115,7 +2115,7 @@ public class TestReductions { @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.MUL_REDUCTION_VL, "> 0", IRNode.MUL_VL, "> 0"}, - applyIfCPUFeature = {"avx512dq", "true"}, + applyIfCPUFeatureOr = {"avx512dq", "true", "sve", "true"}, applyIfAnd = {"AutoVectorizationOverrideProfitability", "> 0", "LoopUnrollLimit", ">= 1000"}) @IR(failOn = IRNode.LOAD_VECTOR_L, @@ -2126,7 +2126,7 @@ public class TestReductions { // If you can eliminate this exception for LoopUnrollLimit, please remove // the flag completely from the test, also the "addFlags" at the top. @IR(failOn = IRNode.LOAD_VECTOR_L, - applyIfCPUFeatureAnd = {"asimd", "true"}) + applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) // MulVL is not implemented on NEON, so we also not have the reduction. // Filed: JDK-8370686 @IR(failOn = IRNode.LOAD_VECTOR_L, @@ -2144,13 +2144,13 @@ public class TestReductions { @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.MIN_REDUCTION_V, "> 0", IRNode.MIN_VL, "> 0"}, - applyIfCPUFeature = {"avx512", "true"}, + applyIfCPUFeatureOr = {"avx512", "true", "sve", "true"}, applyIf = {"AutoVectorizationOverrideProfitability", "> 0"}) @IR(failOn = IRNode.LOAD_VECTOR_L, applyIfCPUFeatureAnd = {"avx512", "false", "avx2", "true"}) // I think this could vectorize, but currently does not. Filed: JDK-8370671 @IR(failOn = IRNode.LOAD_VECTOR_L, - applyIfCPUFeatureAnd = {"asimd", "true"}) + applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) // While MaxReductionV is implemented in NEON (see longMinSimple), MulVL is not. // Filed: JDK-8370686 @IR(failOn = IRNode.LOAD_VECTOR_L, @@ -2168,13 +2168,13 @@ public class TestReductions { @IR(counts = {IRNode.LOAD_VECTOR_L, "> 0", IRNode.MAX_REDUCTION_V, "> 0", IRNode.MAX_VL, "> 0"}, - applyIfCPUFeature = {"avx512", "true"}, + applyIfCPUFeatureOr = {"avx512", "true", "sve", "true"}, applyIf = {"AutoVectorizationOverrideProfitability", "> 0"}) @IR(failOn = IRNode.LOAD_VECTOR_L, applyIfCPUFeatureAnd = {"avx512", "false", "avx2", "true"}) // I think this could vectorize, but currently does not. Filed: JDK-8370671 @IR(failOn = IRNode.LOAD_VECTOR_L, - applyIfCPUFeatureAnd = {"asimd", "true"}) + applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) // While MaxReductionV is implemented in NEON (see longMaxSimple), MulVL is not. // Filed: JDK-8370686 @IR(failOn = IRNode.LOAD_VECTOR_L, @@ -2193,10 +2193,10 @@ public class TestReductions { @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.ADD_REDUCTION_V, "> 0", IRNode.ADD_VF, "= 0"}, - applyIfCPUFeature = {"sse4.1", "true"}, + applyIfCPUFeatureOr = {"sse4.1", "true", "sve", "true"}, applyIf = {"AutoVectorizationOverrideProfitability", "= 2"}) @IR(failOn = IRNode.LOAD_VECTOR_F, - applyIfCPUFeatureAnd = {"asimd", "true"}) + applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) // I think this could vectorize, but currently does not. Filed: JDK-8370677 // But: it is not clear that it would be profitable, given the sequential reduction. @IR(failOn = IRNode.LOAD_VECTOR_F, @@ -2217,10 +2217,10 @@ public class TestReductions { @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_REDUCTION_VF, "> 0", IRNode.MUL_VF, "= 0"}, - applyIfCPUFeature = {"sse4.1", "true"}, + applyIfCPUFeatureOr = {"sse4.1", "true", "sve", "true"}, applyIf = {"AutoVectorizationOverrideProfitability", "= 2"}) @IR(failOn = IRNode.LOAD_VECTOR_F, - applyIfCPUFeatureAnd = {"asimd", "true"}) + applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) // I think this could vectorize, but currently does not. Filed: JDK-8370677 // But: it is not clear that it would be profitable, given the sequential reduction. @IR(failOn = IRNode.LOAD_VECTOR_F, @@ -2276,10 +2276,10 @@ public class TestReductions { @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.ADD_REDUCTION_V, "> 0", IRNode.ADD_VF, "= 0"}, - applyIfCPUFeature = {"sse4.1", "true"}, + applyIfCPUFeatureOr = {"sse4.1", "true", "sve", "true"}, applyIf = {"AutoVectorizationOverrideProfitability", "> 0"}) @IR(failOn = IRNode.LOAD_VECTOR_F, - applyIfCPUFeatureAnd = {"asimd", "true"}) + applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) // I think this could vectorize, but currently does not. Filed: JDK-8370677 // But: it is not clear that it would be profitable, given the sequential reduction. @IR(failOn = IRNode.LOAD_VECTOR_F, @@ -2297,10 +2297,10 @@ public class TestReductions { @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_REDUCTION_VF, "> 0", IRNode.MUL_VF, "> 0"}, - applyIfCPUFeature = {"sse4.1", "true"}, + applyIfCPUFeatureOr = {"sse4.1", "true", "sve", "true"}, applyIf = {"AutoVectorizationOverrideProfitability", "> 0"}) @IR(failOn = IRNode.LOAD_VECTOR_F, - applyIfCPUFeatureAnd = {"asimd", "true"}) + applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) // I think this could vectorize, but currently does not. Filed: JDK-8370677 // But: it is not clear that it would be profitable, given the sequential reduction. @IR(failOn = IRNode.LOAD_VECTOR_F, @@ -2353,10 +2353,10 @@ public class TestReductions { @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.ADD_REDUCTION_V, "> 0", IRNode.ADD_VF, "> 0"}, - applyIfCPUFeature = {"sse4.1", "true"}, + applyIfCPUFeatureOr = {"sse4.1", "true", "sve", "true"}, applyIf = {"AutoVectorizationOverrideProfitability", "> 0"}) @IR(failOn = IRNode.LOAD_VECTOR_F, - applyIfCPUFeatureAnd = {"asimd", "true"}) + applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) // I think this could vectorize, but currently does not. Filed: JDK-8370677 // But: it is not clear that it would be profitable, given the sequential reduction. @IR(failOn = IRNode.LOAD_VECTOR_F, @@ -2374,10 +2374,10 @@ public class TestReductions { @IR(counts = {IRNode.LOAD_VECTOR_F, "> 0", IRNode.MUL_REDUCTION_VF, "> 0", IRNode.MUL_VF, "> 0"}, - applyIfCPUFeature = {"sse4.1", "true"}, + applyIfCPUFeatureOr = {"sse4.1", "true", "sve", "true"}, applyIf = {"AutoVectorizationOverrideProfitability", "> 0"}) @IR(failOn = IRNode.LOAD_VECTOR_F, - applyIfCPUFeatureAnd = {"asimd", "true"}) + applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) // I think this could vectorize, but currently does not. Filed: JDK-8370677 // But: it is not clear that it would be profitable, given the sequential reduction. @IR(failOn = IRNode.LOAD_VECTOR_F, @@ -2430,10 +2430,10 @@ public class TestReductions { @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.ADD_REDUCTION_VD, "> 0", IRNode.ADD_VD, "= 0"}, - applyIfCPUFeature = {"sse4.1", "true"}, + applyIfCPUFeatureOr = {"sse4.1", "true", "sve", "true"}, applyIf = {"AutoVectorizationOverrideProfitability", "= 2"}) @IR(failOn = IRNode.LOAD_VECTOR_D, - applyIfCPUFeatureAnd = {"asimd", "true"}) + applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) // I think this could vectorize, but currently does not. Filed: JDK-8370677 // But: it is not clear that it would be profitable, given the sequential reduction. @IR(failOn = IRNode.LOAD_VECTOR_D, @@ -2454,10 +2454,10 @@ public class TestReductions { @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_REDUCTION_VD, "> 0", IRNode.MUL_VD, "= 0"}, - applyIfCPUFeature = {"sse4.1", "true"}, + applyIfCPUFeatureOr = {"sse4.1", "true", "sve", "true"}, applyIf = {"AutoVectorizationOverrideProfitability", "= 2"}) @IR(failOn = IRNode.LOAD_VECTOR_D, - applyIfCPUFeatureAnd = {"asimd", "true"}) + applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) // I think this could vectorize, but currently does not. Filed: JDK-8370677 // But: it is not clear that it would be profitable, given the sequential reduction. @IR(failOn = IRNode.LOAD_VECTOR_D, @@ -2513,10 +2513,10 @@ public class TestReductions { @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.ADD_REDUCTION_V, "> 0", IRNode.ADD_VD, "= 0"}, - applyIfCPUFeature = {"sse4.1", "true"}, + applyIfCPUFeatureOr = {"sse4.1", "true", "sve", "true"}, applyIf = {"AutoVectorizationOverrideProfitability", "> 0"}) @IR(failOn = IRNode.LOAD_VECTOR_D, - applyIfCPUFeatureAnd = {"asimd", "true"}) + applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) // I think this could vectorize, but currently does not. Filed: JDK-8370677 // But: it is not clear that it would be profitable, given the sequential reduction. @IR(failOn = IRNode.LOAD_VECTOR_D, @@ -2534,10 +2534,10 @@ public class TestReductions { @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_REDUCTION_VD, "> 0", IRNode.MUL_VD, "> 0"}, - applyIfCPUFeature = {"sse4.1", "true"}, + applyIfCPUFeatureOr = {"sse4.1", "true", "sve", "true"}, applyIf = {"AutoVectorizationOverrideProfitability", "> 0"}) @IR(failOn = IRNode.LOAD_VECTOR_D, - applyIfCPUFeatureAnd = {"asimd", "true"}) + applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) // I think this could vectorize, but currently does not. Filed: JDK-8370677 // But: it is not clear that it would be profitable, given the sequential reduction. @IR(failOn = IRNode.LOAD_VECTOR_D, @@ -2590,10 +2590,10 @@ public class TestReductions { @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.ADD_REDUCTION_V, "> 0", IRNode.ADD_VD, "> 0"}, - applyIfCPUFeature = {"sse4.1", "true"}, + applyIfCPUFeatureOr = {"sse4.1", "true", "sve", "true"}, applyIf = {"AutoVectorizationOverrideProfitability", "> 0"}) @IR(failOn = IRNode.LOAD_VECTOR_D, - applyIfCPUFeatureAnd = {"asimd", "true"}) + applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) // I think this could vectorize, but currently does not. Filed: JDK-8370677 // But: it is not clear that it would be profitable, given the sequential reduction. @IR(failOn = IRNode.LOAD_VECTOR_D, @@ -2611,10 +2611,10 @@ public class TestReductions { @IR(counts = {IRNode.LOAD_VECTOR_D, "> 0", IRNode.MUL_REDUCTION_VD, "> 0", IRNode.MUL_VD, "> 0"}, - applyIfCPUFeature = {"sse4.1", "true"}, + applyIfCPUFeatureOr = {"sse4.1", "true", "sve", "true"}, applyIf = {"AutoVectorizationOverrideProfitability", "> 0"}) @IR(failOn = IRNode.LOAD_VECTOR_D, - applyIfCPUFeatureAnd = {"asimd", "true"}) + applyIfCPUFeatureAnd = {"asimd", "true", "sve", "false"}) // I think this could vectorize, but currently does not. Filed: JDK-8370677 // But: it is not clear that it would be profitable, given the sequential reduction. @IR(failOn = IRNode.LOAD_VECTOR_D, diff --git a/test/hotspot/jtreg/compiler/print/CompileCommandPrintCompilation2.java b/test/hotspot/jtreg/compiler/print/CompileCommandPrintCompilation2.java new file mode 100644 index 00000000000..f6a0f3086f7 --- /dev/null +++ b/test/hotspot/jtreg/compiler/print/CompileCommandPrintCompilation2.java @@ -0,0 +1,86 @@ +/* + * Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * 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 8255746 + * @summary Checks that -XX:+UnlockDiagnosticVMOptions -XX:CompileCommand=PrintCompilation2,... works + * @library /test/lib + * @run driver compiler.print.CompileCommandPrintCompilation2 + */ + +package compiler.print; + +import java.util.ArrayList; +import java.util.List; + +import jdk.test.lib.Asserts; +import jdk.test.lib.process.OutputAnalyzer; +import jdk.test.lib.process.ProcessTools; + +public class CompileCommandPrintCompilation2 { + + final static String METHOD1 = "method1"; + final static String METHOD2 = "method2"; + + public static void main(String[] args) throws Exception { + test(METHOD1, METHOD2); + test(METHOD2, METHOD1); + } + + private static void test(String include, String exclude) throws Exception { + List options = new ArrayList(); + options.add("-Xcomp"); + options.add("-XX:-Inline"); + options.add("-XX:CompileCommand=compileonly," + getTestClass() + "::*"); + options.add("-XX:+UnlockDiagnosticVMOptions"); + options.add("-XX:CompileCommand=PrintCompilation2," + getTestMethod(include)); + options.add(getTestClass()); + + OutputAnalyzer oa = ProcessTools.executeTestJava(options); + + oa.shouldHaveExitValue(0) + .shouldContain(getTestMethod(include)) + .shouldNotContain(getTestMethod(exclude)); + } + + // Test class that is invoked by the sub process + public static String getTestClass() { + return TestMain.class.getName(); + } + + public static String getTestMethod(String method) { + return getTestClass() + "::" + method; + } + + public static class TestMain { + public static void main(String[] args) { + method1(); + method2(); + } + + static void method1() {} + static void method2() {} + } +} + diff --git a/test/hotspot/jtreg/compiler/print/PrintCompilation2.java b/test/hotspot/jtreg/compiler/print/PrintCompilation2.java new file mode 100644 index 00000000000..ac07bc316d3 --- /dev/null +++ b/test/hotspot/jtreg/compiler/print/PrintCompilation2.java @@ -0,0 +1,82 @@ +/* + * Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * 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 Checks that -XX:PrintCompilation2 works + * @library /test/lib + * @run driver compiler.print.PrintCompilation2 + */ + +package compiler.print; + +import java.util.ArrayList; +import java.util.List; + +import jdk.test.lib.Asserts; +import jdk.test.lib.process.OutputAnalyzer; +import jdk.test.lib.process.ProcessTools; + +public class PrintCompilation2 { + + public static void main(String[] args) throws Exception { + List options = new ArrayList(); + options.add("-XX:+UnlockDiagnosticVMOptions"); + options.add("-XX:+PrintCompilation2"); + options.add("-Xcomp"); + options.add("-XX:-Inline"); + options.add("-XX:CompileCommand=compileonly," + getTestClass() + "::*"); + options.add(getTestClass()); + + OutputAnalyzer oa = ProcessTools.executeTestJava(options); + + oa.shouldHaveExitValue(0) + .shouldContain(getTestMethod("method1")) + .shouldContain(getTestMethod("method2")) + .shouldContain(getTestMethod("method3")) + .shouldNotContain(getTestMethod("notcalled")); + } + + // Test class that is invoked by the sub process + public static String getTestClass() { + return TestMain.class.getName(); + } + + public static String getTestMethod(String method) { + return getTestClass() + "::" + method; + } + + public static class TestMain { + public static void main(String[] args) { + method1(); + method2(); + method3(); + } + + static void method1() { System.out.println("method1()"); } + static void method2() {} + static void method3() {} + static void notcalled() {} + } +} + diff --git a/test/hotspot/jtreg/compiler/vectorapi/TestMultiplyReductionByte.java b/test/hotspot/jtreg/compiler/vectorapi/TestMultiplyReductionByte.java index 13eafd8dc26..b56dc371559 100644 --- a/test/hotspot/jtreg/compiler/vectorapi/TestMultiplyReductionByte.java +++ b/test/hotspot/jtreg/compiler/vectorapi/TestMultiplyReductionByte.java @@ -35,7 +35,7 @@ import jdk.test.lib.Utils; /** * @test - * @bug 8378250 + * @bug 8378250 8381452 * @summary Verify correctness of byte vector MUL reduction across all species. * A register aliasing bug in mulreduce32B caused the upper half of * sign-extended data to overwrite the source, producing wrong results @@ -57,7 +57,7 @@ public class TestMultiplyReductionByte { @Test @IR(counts = {IRNode.MUL_REDUCTION_VI, ">=1"}, - applyIfCPUFeatureOr = {"avx", "true", "asimd", "true"}, + applyIfCPUFeatureOr = {"avx", "true", "asimd", "true", "rvv", "true"}, applyIf = {"MaxVectorSize", ">=8"}) static byte testMulReduce64() { return ByteVector.fromArray(ByteVector.SPECIES_64, input, 0) @@ -75,7 +75,7 @@ public class TestMultiplyReductionByte { @Test @IR(counts = {IRNode.MUL_REDUCTION_VI, ">=1"}, - applyIfCPUFeatureOr = {"avx", "true", "asimd", "true"}, + applyIfCPUFeatureOr = {"avx", "true", "asimd", "true", "rvv", "true"}, applyIf = {"MaxVectorSize", ">=16"}) static byte testMulReduce128() { return ByteVector.fromArray(ByteVector.SPECIES_128, input, 0) @@ -93,8 +93,13 @@ public class TestMultiplyReductionByte { @Test @IR(counts = {IRNode.MUL_REDUCTION_VI, ">=1"}, - applyIfCPUFeatureOr = {"avx2", "true", "asimd", "true"}, + applyIfCPUFeatureOr = {"avx2", "true", "rvv", "true"}, applyIf = {"MaxVectorSize", ">=32"}) + @IR(counts = {IRNode.MUL_REDUCTION_VI, "0"}, + applyIfCPUFeature = {"asimd", "true"}, + applyIf = {"MaxVectorSize", ">=32"}) + // AArch64 currently does not vectorize vectors larger than 128 bits, and + // that may change in the future. static byte testMulReduce256() { return ByteVector.fromArray(ByteVector.SPECIES_256, input, 0) .reduceLanes(VectorOperators.MUL); @@ -111,8 +116,13 @@ public class TestMultiplyReductionByte { @Test @IR(counts = {IRNode.MUL_REDUCTION_VI, ">=1"}, - applyIfCPUFeatureOr = {"avx512f", "true", "asimd", "true"}, + applyIfCPUFeatureOr = {"avx512f", "true", "rvv", "true"}, applyIf = {"MaxVectorSize", ">=64"}) + @IR(counts = {IRNode.MUL_REDUCTION_VI, "0"}, + applyIfCPUFeature = {"asimd", "true"}, + applyIf = {"MaxVectorSize", ">=64"}) + // AArch64 currently does not vectorize vectors larger than 128 bits, and + // that may change in the future. static byte testMulReduce512() { return ByteVector.fromArray(ByteVector.SPECIES_512, input, 0) .reduceLanes(VectorOperators.MUL); diff --git a/test/hotspot/jtreg/compiler/vectorapi/VectorMinMaxTransforms.java b/test/hotspot/jtreg/compiler/vectorapi/VectorMinMaxTransforms.java index be3ec322892..532f0d22927 100644 --- a/test/hotspot/jtreg/compiler/vectorapi/VectorMinMaxTransforms.java +++ b/test/hotspot/jtreg/compiler/vectorapi/VectorMinMaxTransforms.java @@ -640,7 +640,7 @@ public class VectorMinMaxTransforms { @Test @IR(counts = { IRNode.MIN_VI, IRNode.VECTOR_SIZE_ANY, " 1 ", IRNode.MAX_VI, IRNode.VECTOR_SIZE_ANY, " 0 " }, - applyIfCPUFeatureOr = {"avx512f", "true", "sve", "true"}) + applyIfCPUFeatureOr = {"avx512f", "true", "sve", "true", "rvv", "true"}) public void testIntMaskedMinIdealSameMask(int index) { IntVector v1 = IntVector.fromArray(I_SPECIES, ia, index); IntVector v2 = IntVector.fromArray(I_SPECIES, ib, index); @@ -669,7 +669,7 @@ public class VectorMinMaxTransforms { @Test @IR(counts = { IRNode.MIN_VI, IRNode.VECTOR_SIZE_ANY, " 0 ", IRNode.MAX_VI, IRNode.VECTOR_SIZE_ANY, " 1 " }, - applyIfCPUFeatureOr = {"avx512f", "true", "sve", "true"}) + applyIfCPUFeatureOr = {"avx512f", "true", "sve", "true", "rvv", "true"}) public void testIntMaskedMaxIdealSameMask(int index) { IntVector v1 = IntVector.fromArray(I_SPECIES, ia, index); IntVector v2 = IntVector.fromArray(I_SPECIES, ib, index); @@ -698,7 +698,7 @@ public class VectorMinMaxTransforms { @Test @IR(counts = { IRNode.MIN_VI, IRNode.VECTOR_SIZE_ANY, " 0 ", IRNode.MAX_VI, IRNode.VECTOR_SIZE_ANY, " 1 " }, - applyIfCPUFeatureOr = {"avx512f", "true", "sve", "true"}) + applyIfCPUFeatureOr = {"avx512f", "true", "sve", "true", "rvv", "true"}) public void testIntMaskedMaxIdealFlippedInputs(int index) { IntVector v1 = IntVector.fromArray(I_SPECIES, ia, index); IntVector v2 = IntVector.fromArray(I_SPECIES, ib, index); @@ -727,7 +727,7 @@ public class VectorMinMaxTransforms { @Test @IR(counts = { IRNode.MIN_VI, IRNode.VECTOR_SIZE_ANY, " 1 ", IRNode.MAX_VI, IRNode.VECTOR_SIZE_ANY, " 0 " }, - applyIfCPUFeatureOr = {"avx512f", "true", "sve", "true"}) + applyIfCPUFeatureOr = {"avx512f", "true", "sve", "true", "rvv", "true"}) public void testIntMaskedMinIdealFlippedInputs(int index) { IntVector v1 = IntVector.fromArray(I_SPECIES, ia, index); IntVector v2 = IntVector.fromArray(I_SPECIES, ib, index); @@ -756,7 +756,7 @@ public class VectorMinMaxTransforms { @Test @IR(counts = { IRNode.MIN_VI, IRNode.VECTOR_SIZE_ANY, " 2 ", IRNode.MAX_VI, IRNode.VECTOR_SIZE_ANY, " 1 " }, - applyIfCPUFeatureOr = {"avx512f", "true", "sve", "true"}) + applyIfCPUFeatureOr = {"avx512f", "true", "sve", "true", "rvv", "true"}) public void testIntMaskedMinIdealDiffMaskMinMax(int index) { IntVector v1 = IntVector.fromArray(I_SPECIES, ia, index); IntVector v2 = IntVector.fromArray(I_SPECIES, ib, index); @@ -786,7 +786,7 @@ public class VectorMinMaxTransforms { @Test @IR(counts = { IRNode.MIN_VI, IRNode.VECTOR_SIZE_ANY, " 2 ", IRNode.MAX_VI, IRNode.VECTOR_SIZE_ANY, " 1 " }, - applyIfCPUFeatureOr = {"avx512f", "true", "sve", "true"}) + applyIfCPUFeatureOr = {"avx512f", "true", "sve", "true", "rvv", "true"}) public void testIntMaskedMinIdealDiffMaskMinMaxSwapped(int index) { IntVector v1 = IntVector.fromArray(I_SPECIES, ia, index); IntVector v2 = IntVector.fromArray(I_SPECIES, ib, index); @@ -814,7 +814,7 @@ public class VectorMinMaxTransforms { @Test @IR(counts = { IRNode.MIN_VI, IRNode.VECTOR_SIZE_ANY, " 2 ", IRNode.MAX_VI, IRNode.VECTOR_SIZE_ANY, " 1 " }, - applyIfCPUFeatureOr = {"avx512f", "true", "sve", "true"}) + applyIfCPUFeatureOr = {"avx512f", "true", "sve", "true", "rvv", "true"}) public void testIntMaskedMinIdealDiffMaskOuter(int index) { IntVector v1 = IntVector.fromArray(I_SPECIES, ia, index); IntVector v2 = IntVector.fromArray(I_SPECIES, ib, index); @@ -843,7 +843,7 @@ public class VectorMinMaxTransforms { @Test @IR(counts = { IRNode.MIN_VI, IRNode.VECTOR_SIZE_ANY, " 2 ", IRNode.MAX_VI, IRNode.VECTOR_SIZE_ANY, " 1 " }, - applyIfCPUFeatureOr = {"avx512f", "true", "sve", "true"}) + applyIfCPUFeatureOr = {"avx512f", "true", "sve", "true", "rvv", "true"}) public void testIntMaskedMinIdealAllDiffMask(int index) { IntVector v1 = IntVector.fromArray(I_SPECIES, ia, index); IntVector v2 = IntVector.fromArray(I_SPECIES, ib, index); @@ -873,7 +873,7 @@ public class VectorMinMaxTransforms { @Test @IR(counts = { IRNode.MIN_VB, IRNode.VECTOR_SIZE_ANY, " 1 ", IRNode.MAX_VB, IRNode.VECTOR_SIZE_ANY, " 0 " }, - applyIfCPUFeatureOr = {"avx512bw", "true", "sve", "true"}) + applyIfCPUFeatureOr = {"avx512bw", "true", "sve", "true", "rvv", "true"}) public void testByteMaskedMinIdealSameMask(int index) { ByteVector v1 = ByteVector.fromArray(B_SPECIES, ba, index); ByteVector v2 = ByteVector.fromArray(B_SPECIES, bb, index); @@ -902,7 +902,7 @@ public class VectorMinMaxTransforms { @Test @IR(counts = { IRNode.MIN_VB, IRNode.VECTOR_SIZE_ANY, " 0 ", IRNode.MAX_VB, IRNode.VECTOR_SIZE_ANY, " 1 " }, - applyIfCPUFeatureOr = {"avx512bw", "true", "sve", "true"}) + applyIfCPUFeatureOr = {"avx512bw", "true", "sve", "true", "rvv", "true"}) public void testByteMaskedMaxIdealSameMask(int index) { ByteVector v1 = ByteVector.fromArray(B_SPECIES, ba, index); ByteVector v2 = ByteVector.fromArray(B_SPECIES, bb, index); @@ -931,7 +931,7 @@ public class VectorMinMaxTransforms { @Test @IR(counts = { IRNode.MIN_VB, IRNode.VECTOR_SIZE_ANY, " 0 ", IRNode.MAX_VB, IRNode.VECTOR_SIZE_ANY, " 1 " }, - applyIfCPUFeatureOr = {"avx512bw", "true", "sve", "true"}) + applyIfCPUFeatureOr = {"avx512bw", "true", "sve", "true", "rvv", "true"}) public void testByteMaskedMaxIdealFlippedInputs(int index) { ByteVector v1 = ByteVector.fromArray(B_SPECIES, ba, index); ByteVector v2 = ByteVector.fromArray(B_SPECIES, bb, index); @@ -960,7 +960,7 @@ public class VectorMinMaxTransforms { @Test @IR(counts = { IRNode.MIN_VB, IRNode.VECTOR_SIZE_ANY, " 1 ", IRNode.MAX_VB, IRNode.VECTOR_SIZE_ANY, " 0 " }, - applyIfCPUFeatureOr = {"avx512bw", "true", "sve", "true"}) + applyIfCPUFeatureOr = {"avx512bw", "true", "sve", "true", "rvv", "true"}) public void testByteMaskedMinIdealFlippedInputs(int index) { ByteVector v1 = ByteVector.fromArray(B_SPECIES, ba, index); ByteVector v2 = ByteVector.fromArray(B_SPECIES, bb, index); @@ -989,7 +989,7 @@ public class VectorMinMaxTransforms { @Test @IR(counts = { IRNode.MIN_VB, IRNode.VECTOR_SIZE_ANY, " 2 ", IRNode.MAX_VB, IRNode.VECTOR_SIZE_ANY, " 1 " }, - applyIfCPUFeatureOr = {"avx512bw", "true", "sve", "true"}) + applyIfCPUFeatureOr = {"avx512bw", "true", "sve", "true", "rvv", "true"}) public void testByteMaskedMinIdealDiffMaskMinMax(int index) { ByteVector v1 = ByteVector.fromArray(B_SPECIES, ba, index); ByteVector v2 = ByteVector.fromArray(B_SPECIES, bb, index); @@ -1018,7 +1018,7 @@ public class VectorMinMaxTransforms { @Test @IR(counts = { IRNode.MIN_VB, IRNode.VECTOR_SIZE_ANY, " 2 ", IRNode.MAX_VB, IRNode.VECTOR_SIZE_ANY, " 1 " }, - applyIfCPUFeatureOr = {"avx512bw", "true", "sve", "true"}) + applyIfCPUFeatureOr = {"avx512bw", "true", "sve", "true", "rvv", "true"}) public void testByteMaskedMinIdealDiffMaskMinMaxSwapped(int index) { ByteVector v1 = ByteVector.fromArray(B_SPECIES, ba, index); ByteVector v2 = ByteVector.fromArray(B_SPECIES, bb, index); @@ -1047,7 +1047,7 @@ public class VectorMinMaxTransforms { @Test @IR(counts = { IRNode.MIN_VB, IRNode.VECTOR_SIZE_ANY, " 2 ", IRNode.MAX_VB, IRNode.VECTOR_SIZE_ANY, " 1 " }, - applyIfCPUFeatureOr = {"avx512bw", "true", "sve", "true"}) + applyIfCPUFeatureOr = {"avx512bw", "true", "sve", "true", "rvv", "true"}) public void testByteMaskedMinIdealDiffMaskOuter(int index) { ByteVector v1 = ByteVector.fromArray(B_SPECIES, ba, index); ByteVector v2 = ByteVector.fromArray(B_SPECIES, bb, index); @@ -1076,7 +1076,7 @@ public class VectorMinMaxTransforms { @Test @IR(counts = { IRNode.MIN_VB, IRNode.VECTOR_SIZE_ANY, " 2 ", IRNode.MAX_VB, IRNode.VECTOR_SIZE_ANY, " 1 " }, - applyIfCPUFeatureOr = {"avx512bw", "true", "sve", "true"}) + applyIfCPUFeatureOr = {"avx512bw", "true", "sve", "true", "rvv", "true"}) public void testByteMaskedMinIdealAllDiffMask(int index) { ByteVector v1 = ByteVector.fromArray(B_SPECIES, ba, index); ByteVector v2 = ByteVector.fromArray(B_SPECIES, bb, index); @@ -1106,7 +1106,7 @@ public class VectorMinMaxTransforms { @Test @IR(counts = { IRNode.MIN_VS, IRNode.VECTOR_SIZE_ANY, " 1 ", IRNode.MAX_VS, IRNode.VECTOR_SIZE_ANY, " 0 " }, - applyIfCPUFeatureOr = {"avx512bw", "true", "sve", "true"}) + applyIfCPUFeatureOr = {"avx512bw", "true", "sve", "true", "rvv", "true"}) public void testShortMaskedMinIdealSameMask(int index) { ShortVector v1 = ShortVector.fromArray(S_SPECIES, sa, index); ShortVector v2 = ShortVector.fromArray(S_SPECIES, sb, index); @@ -1135,7 +1135,7 @@ public class VectorMinMaxTransforms { @Test @IR(counts = { IRNode.MIN_VS, IRNode.VECTOR_SIZE_ANY, " 0 ", IRNode.MAX_VS, IRNode.VECTOR_SIZE_ANY, " 1 " }, - applyIfCPUFeatureOr = {"avx512bw", "true", "sve", "true"}) + applyIfCPUFeatureOr = {"avx512bw", "true", "sve", "true", "rvv", "true"}) public void testShortMaskedMaxIdealSameMask(int index) { ShortVector v1 = ShortVector.fromArray(S_SPECIES, sa, index); ShortVector v2 = ShortVector.fromArray(S_SPECIES, sb, index); @@ -1164,7 +1164,7 @@ public class VectorMinMaxTransforms { @Test @IR(counts = { IRNode.MIN_VS, IRNode.VECTOR_SIZE_ANY, " 0 ", IRNode.MAX_VS, IRNode.VECTOR_SIZE_ANY, " 1 " }, - applyIfCPUFeatureOr = {"avx512bw", "true", "sve", "true"}) + applyIfCPUFeatureOr = {"avx512bw", "true", "sve", "true", "rvv", "true"}) public void testShortMaskedMaxIdealFlippedInputs(int index) { ShortVector v1 = ShortVector.fromArray(S_SPECIES, sa, index); ShortVector v2 = ShortVector.fromArray(S_SPECIES, sb, index); @@ -1193,7 +1193,7 @@ public class VectorMinMaxTransforms { @Test @IR(counts = { IRNode.MIN_VS, IRNode.VECTOR_SIZE_ANY, " 1 ", IRNode.MAX_VS, IRNode.VECTOR_SIZE_ANY, " 0 " }, - applyIfCPUFeatureOr = {"avx512bw", "true", "sve", "true"}) + applyIfCPUFeatureOr = {"avx512bw", "true", "sve", "true", "rvv", "true"}) public void testShortMaskedMinIdealFlippedInputs(int index) { ShortVector v1 = ShortVector.fromArray(S_SPECIES, sa, index); ShortVector v2 = ShortVector.fromArray(S_SPECIES, sb, index); @@ -1222,7 +1222,7 @@ public class VectorMinMaxTransforms { @Test @IR(counts = { IRNode.MIN_VS, IRNode.VECTOR_SIZE_ANY, " 2 ", IRNode.MAX_VS, IRNode.VECTOR_SIZE_ANY, " 1 " }, - applyIfCPUFeatureOr = {"avx512bw", "true", "sve", "true"}) + applyIfCPUFeatureOr = {"avx512bw", "true", "sve", "true", "rvv", "true"}) public void testShortMaskedMinIdealDiffMaskMinMax(int index) { ShortVector v1 = ShortVector.fromArray(S_SPECIES, sa, index); ShortVector v2 = ShortVector.fromArray(S_SPECIES, sb, index); @@ -1251,7 +1251,7 @@ public class VectorMinMaxTransforms { @Test @IR(counts = { IRNode.MIN_VS, IRNode.VECTOR_SIZE_ANY, " 2 ", IRNode.MAX_VS, IRNode.VECTOR_SIZE_ANY, " 1 " }, - applyIfCPUFeatureOr = {"avx512bw", "true", "sve", "true"}) + applyIfCPUFeatureOr = {"avx512bw", "true", "sve", "true", "rvv", "true"}) public void testShortMaskedMinIdealDiffMaskMinMaxSwapped(int index) { ShortVector v1 = ShortVector.fromArray(S_SPECIES, sa, index); ShortVector v2 = ShortVector.fromArray(S_SPECIES, sb, index); @@ -1280,7 +1280,7 @@ public class VectorMinMaxTransforms { @Test @IR(counts = { IRNode.MIN_VS, IRNode.VECTOR_SIZE_ANY, " 2 ", IRNode.MAX_VS, IRNode.VECTOR_SIZE_ANY, " 1 " }, - applyIfCPUFeatureOr = {"avx512bw", "true", "sve", "true"}) + applyIfCPUFeatureOr = {"avx512bw", "true", "sve", "true", "rvv", "true"}) public void testShortMaskedMinIdealDiffMaskOuter(int index) { ShortVector v1 = ShortVector.fromArray(S_SPECIES, sa, index); ShortVector v2 = ShortVector.fromArray(S_SPECIES, sb, index); @@ -1309,7 +1309,7 @@ public class VectorMinMaxTransforms { @Test @IR(counts = { IRNode.MIN_VS, IRNode.VECTOR_SIZE_ANY, " 2 ", IRNode.MAX_VS, IRNode.VECTOR_SIZE_ANY, " 1 " }, - applyIfCPUFeatureOr = {"avx512bw", "true", "sve", "true"}) + applyIfCPUFeatureOr = {"avx512bw", "true", "sve", "true", "rvv", "true"}) public void testShortMaskedMinIdealAllDiffMask(int index) { ShortVector v1 = ShortVector.fromArray(S_SPECIES, sa, index); ShortVector v2 = ShortVector.fromArray(S_SPECIES, sb, index); @@ -1339,7 +1339,7 @@ public class VectorMinMaxTransforms { @Test @IR(counts = { IRNode.MIN_VL, IRNode.VECTOR_SIZE_ANY, " 1 ", IRNode.MAX_VL, IRNode.VECTOR_SIZE_ANY, " 0 " }, - applyIfCPUFeatureOr = {"avx512f", "true", "sve", "true"}) + applyIfCPUFeatureOr = {"avx512f", "true", "sve", "true", "rvv", "true"}) public void testLongMaskedMinIdealSameMask(int index) { LongVector v1 = LongVector.fromArray(L_SPECIES, la, index); LongVector v2 = LongVector.fromArray(L_SPECIES, lb, index); @@ -1368,7 +1368,7 @@ public class VectorMinMaxTransforms { @Test @IR(counts = { IRNode.MIN_VL, IRNode.VECTOR_SIZE_ANY, " 0 ", IRNode.MAX_VL, IRNode.VECTOR_SIZE_ANY, " 1 " }, - applyIfCPUFeatureOr = {"avx512f", "true", "sve", "true"}) + applyIfCPUFeatureOr = {"avx512f", "true", "sve", "true", "rvv", "true"}) public void testLongMaskedMaxIdealSameMask(int index) { LongVector v1 = LongVector.fromArray(L_SPECIES, la, index); LongVector v2 = LongVector.fromArray(L_SPECIES, lb, index); @@ -1397,7 +1397,7 @@ public class VectorMinMaxTransforms { @Test @IR(counts = { IRNode.MIN_VL, IRNode.VECTOR_SIZE_ANY, " 0 ", IRNode.MAX_VL, IRNode.VECTOR_SIZE_ANY, " 1 " }, - applyIfCPUFeatureOr = {"avx512f", "true", "sve", "true"}) + applyIfCPUFeatureOr = {"avx512f", "true", "sve", "true", "rvv", "true"}) public void testLongMaskedMaxIdealFlippedInputs(int index) { LongVector v1 = LongVector.fromArray(L_SPECIES, la, index); LongVector v2 = LongVector.fromArray(L_SPECIES, lb, index); @@ -1426,7 +1426,7 @@ public class VectorMinMaxTransforms { @Test @IR(counts = { IRNode.MIN_VL, IRNode.VECTOR_SIZE_ANY, " 1 ", IRNode.MAX_VL, IRNode.VECTOR_SIZE_ANY, " 0 " }, - applyIfCPUFeatureOr = {"avx512f", "true", "sve", "true"}) + applyIfCPUFeatureOr = {"avx512f", "true", "sve", "true", "rvv", "true"}) public void testLongMaskedMinIdealFlippedInputs(int index) { LongVector v1 = LongVector.fromArray(L_SPECIES, la, index); LongVector v2 = LongVector.fromArray(L_SPECIES, lb, index); @@ -1455,7 +1455,7 @@ public class VectorMinMaxTransforms { @Test @IR(counts = { IRNode.MIN_VL, IRNode.VECTOR_SIZE_ANY, " 2 ", IRNode.MAX_VL, IRNode.VECTOR_SIZE_ANY, " 1 " }, - applyIfCPUFeatureOr = {"avx512f", "true", "sve", "true"}) + applyIfCPUFeatureOr = {"avx512f", "true", "sve", "true", "rvv", "true"}) public void testLongMaskedMinIdealDiffMaskMinMax(int index) { LongVector v1 = LongVector.fromArray(L_SPECIES, la, index); LongVector v2 = LongVector.fromArray(L_SPECIES, lb, index); @@ -1484,7 +1484,7 @@ public class VectorMinMaxTransforms { @Test @IR(counts = { IRNode.MIN_VL, IRNode.VECTOR_SIZE_ANY, " 2 ", IRNode.MAX_VL, IRNode.VECTOR_SIZE_ANY, " 1 " }, - applyIfCPUFeatureOr = {"avx512f", "true", "sve", "true"}) + applyIfCPUFeatureOr = {"avx512f", "true", "sve", "true", "rvv", "true"}) public void testLongMaskedMinIdealDiffMaskMinMaxSwapped(int index) { LongVector v1 = LongVector.fromArray(L_SPECIES, la, index); LongVector v2 = LongVector.fromArray(L_SPECIES, lb, index); @@ -1513,7 +1513,7 @@ public class VectorMinMaxTransforms { @Test @IR(counts = { IRNode.MIN_VL, IRNode.VECTOR_SIZE_ANY, " 2 ", IRNode.MAX_VL, IRNode.VECTOR_SIZE_ANY, " 1 " }, - applyIfCPUFeatureOr = {"avx512f", "true", "sve", "true"}) + applyIfCPUFeatureOr = {"avx512f", "true", "sve", "true", "rvv", "true"}) public void testLongMaskedMinIdealDiffMaskOuter(int index) { LongVector v1 = LongVector.fromArray(L_SPECIES, la, index); LongVector v2 = LongVector.fromArray(L_SPECIES, lb, index); @@ -1542,7 +1542,7 @@ public class VectorMinMaxTransforms { @Test @IR(counts = { IRNode.MIN_VL, IRNode.VECTOR_SIZE_ANY, " 2 ", IRNode.MAX_VL, IRNode.VECTOR_SIZE_ANY, " 1 " }, - applyIfCPUFeatureOr = {"avx512f", "true", "sve", "true"}) + applyIfCPUFeatureOr = {"avx512f", "true", "sve", "true", "rvv", "true"}) public void testLongMaskedMinIdealAllDiffMask(int index) { LongVector v1 = LongVector.fromArray(L_SPECIES, la, index); LongVector v2 = LongVector.fromArray(L_SPECIES, lb, index); @@ -1572,7 +1572,7 @@ public class VectorMinMaxTransforms { @Test @IR(counts = { IRNode.MIN_VF, IRNode.VECTOR_SIZE_ANY, " 1 ", IRNode.MAX_VF, IRNode.VECTOR_SIZE_ANY, " 0 " }, - applyIfCPUFeatureOr = {"avx10_2", "true", "sve", "true"}) + applyIfCPUFeatureOr = {"avx10_2", "true", "sve", "true", "rvv", "true"}) public void testFloatMaskedMinIdealSameMask(int index) { FloatVector v1 = FloatVector.fromArray(F_SPECIES, fa, index); FloatVector v2 = FloatVector.fromArray(F_SPECIES, fb, index); @@ -1601,7 +1601,7 @@ public class VectorMinMaxTransforms { @Test @IR(counts = { IRNode.MIN_VF, IRNode.VECTOR_SIZE_ANY, " 0 ", IRNode.MAX_VF, IRNode.VECTOR_SIZE_ANY, " 1 " }, - applyIfCPUFeatureOr = {"avx10_2", "true", "sve", "true"}) + applyIfCPUFeatureOr = {"avx10_2", "true", "sve", "true", "rvv", "true"}) public void testFloatMaskedMaxIdealSameMask(int index) { FloatVector v1 = FloatVector.fromArray(F_SPECIES, fa, index); FloatVector v2 = FloatVector.fromArray(F_SPECIES, fb, index); @@ -1630,7 +1630,7 @@ public class VectorMinMaxTransforms { @Test @IR(counts = { IRNode.MIN_VF, IRNode.VECTOR_SIZE_ANY, " 0 ", IRNode.MAX_VF, IRNode.VECTOR_SIZE_ANY, " 1 " }, - applyIfCPUFeatureOr = {"avx10_2", "true", "sve", "true"}) + applyIfCPUFeatureOr = {"avx10_2", "true", "sve", "true", "rvv", "true"}) public void testFloatMaskedMaxIdealFlippedInputs(int index) { FloatVector v1 = FloatVector.fromArray(F_SPECIES, fa, index); FloatVector v2 = FloatVector.fromArray(F_SPECIES, fb, index); @@ -1659,7 +1659,7 @@ public class VectorMinMaxTransforms { @Test @IR(counts = { IRNode.MIN_VF, IRNode.VECTOR_SIZE_ANY, " 1 ", IRNode.MAX_VF, IRNode.VECTOR_SIZE_ANY, " 0 " }, - applyIfCPUFeatureOr = {"avx10_2", "true", "sve", "true"}) + applyIfCPUFeatureOr = {"avx10_2", "true", "sve", "true", "rvv", "true"}) public void testFloatMaskedMinIdealFlippedInputs(int index) { FloatVector v1 = FloatVector.fromArray(F_SPECIES, fa, index); FloatVector v2 = FloatVector.fromArray(F_SPECIES, fb, index); @@ -1688,7 +1688,7 @@ public class VectorMinMaxTransforms { @Test @IR(counts = { IRNode.MIN_VF, IRNode.VECTOR_SIZE_ANY, " 2 ", IRNode.MAX_VF, IRNode.VECTOR_SIZE_ANY, " 1 " }, - applyIfCPUFeatureOr = {"avx10_2", "true", "sve", "true"}) + applyIfCPUFeatureOr = {"avx10_2", "true", "sve", "true", "rvv", "true"}) public void testFloatMaskedMinIdealDiffMaskMinMax(int index) { FloatVector v1 = FloatVector.fromArray(F_SPECIES, fa, index); FloatVector v2 = FloatVector.fromArray(F_SPECIES, fb, index); @@ -1717,7 +1717,7 @@ public class VectorMinMaxTransforms { @Test @IR(counts = { IRNode.MIN_VF, IRNode.VECTOR_SIZE_ANY, " 2 ", IRNode.MAX_VF, IRNode.VECTOR_SIZE_ANY, " 1 " }, - applyIfCPUFeatureOr = {"avx10_2", "true", "sve", "true"}) + applyIfCPUFeatureOr = {"avx10_2", "true", "sve", "true", "rvv", "true"}) public void testFloatMaskedMinIdealDiffMaskMinMaxSwapped(int index) { FloatVector v1 = FloatVector.fromArray(F_SPECIES, fa, index); FloatVector v2 = FloatVector.fromArray(F_SPECIES, fb, index); @@ -1746,7 +1746,7 @@ public class VectorMinMaxTransforms { @Test @IR(counts = { IRNode.MIN_VF, IRNode.VECTOR_SIZE_ANY, " 2 ", IRNode.MAX_VF, IRNode.VECTOR_SIZE_ANY, " 1 " }, - applyIfCPUFeatureOr = {"avx10_2", "true", "sve", "true"}) + applyIfCPUFeatureOr = {"avx10_2", "true", "sve", "true", "rvv", "true"}) public void testFloatMaskedMinIdealDiffMaskOuter(int index) { FloatVector v1 = FloatVector.fromArray(F_SPECIES, fa, index); FloatVector v2 = FloatVector.fromArray(F_SPECIES, fb, index); @@ -1775,7 +1775,7 @@ public class VectorMinMaxTransforms { @Test @IR(counts = { IRNode.MIN_VF, IRNode.VECTOR_SIZE_ANY, " 2 ", IRNode.MAX_VF, IRNode.VECTOR_SIZE_ANY, " 1 " }, - applyIfCPUFeatureOr = {"avx10_2", "true", "sve", "true"}) + applyIfCPUFeatureOr = {"avx10_2", "true", "sve", "true", "rvv", "true"}) public void testFloatMaskedMinIdealAllDiffMask(int index) { FloatVector v1 = FloatVector.fromArray(F_SPECIES, fa, index); FloatVector v2 = FloatVector.fromArray(F_SPECIES, fb, index); @@ -1805,7 +1805,7 @@ public class VectorMinMaxTransforms { @Test @IR(counts = { IRNode.MIN_VD, IRNode.VECTOR_SIZE_ANY, " 1 ", IRNode.MAX_VD, IRNode.VECTOR_SIZE_ANY, " 0 " }, - applyIfCPUFeatureOr = {"avx10_2", "true", "sve", "true"}) + applyIfCPUFeatureOr = {"avx10_2", "true", "sve", "true", "rvv", "true"}) public void testDoubleMaskedMinIdealSameMask(int index) { DoubleVector v1 = DoubleVector.fromArray(D_SPECIES, da, index); DoubleVector v2 = DoubleVector.fromArray(D_SPECIES, db, index); @@ -1834,7 +1834,7 @@ public class VectorMinMaxTransforms { @Test @IR(counts = { IRNode.MIN_VD, IRNode.VECTOR_SIZE_ANY, " 0 ", IRNode.MAX_VD, IRNode.VECTOR_SIZE_ANY, " 1 " }, - applyIfCPUFeatureOr = {"avx10_2", "true", "sve", "true"}) + applyIfCPUFeatureOr = {"avx10_2", "true", "sve", "true", "rvv", "true"}) public void testDoubleMaskedMaxIdealSameMask(int index) { DoubleVector v1 = DoubleVector.fromArray(D_SPECIES, da, index); DoubleVector v2 = DoubleVector.fromArray(D_SPECIES, db, index); @@ -1863,7 +1863,7 @@ public class VectorMinMaxTransforms { @Test @IR(counts = { IRNode.MIN_VD, IRNode.VECTOR_SIZE_ANY, " 0 ", IRNode.MAX_VD, IRNode.VECTOR_SIZE_ANY, " 1 " }, - applyIfCPUFeatureOr = {"avx10_2", "true", "sve", "true"}) + applyIfCPUFeatureOr = {"avx10_2", "true", "sve", "true", "rvv", "true"}) public void testDoubleMaskedMaxIdealFlippedInputs(int index) { DoubleVector v1 = DoubleVector.fromArray(D_SPECIES, da, index); DoubleVector v2 = DoubleVector.fromArray(D_SPECIES, db, index); @@ -1892,7 +1892,7 @@ public class VectorMinMaxTransforms { @Test @IR(counts = { IRNode.MIN_VD, IRNode.VECTOR_SIZE_ANY, " 1 ", IRNode.MAX_VD, IRNode.VECTOR_SIZE_ANY, " 0 " }, - applyIfCPUFeatureOr = {"avx10_2", "true", "sve", "true"}) + applyIfCPUFeatureOr = {"avx10_2", "true", "sve", "true", "rvv", "true"}) public void testDoubleMaskedMinIdealFlippedInputs(int index) { DoubleVector v1 = DoubleVector.fromArray(D_SPECIES, da, index); DoubleVector v2 = DoubleVector.fromArray(D_SPECIES, db, index); @@ -1921,7 +1921,7 @@ public class VectorMinMaxTransforms { @Test @IR(counts = { IRNode.MIN_VD, IRNode.VECTOR_SIZE_ANY, " 2 ", IRNode.MAX_VD, IRNode.VECTOR_SIZE_ANY, " 1 " }, - applyIfCPUFeatureOr = {"avx10_2", "true", "sve", "true"}) + applyIfCPUFeatureOr = {"avx10_2", "true", "sve", "true", "rvv", "true"}) public void testDoubleMaskedMinIdealDiffMaskMinMax(int index) { DoubleVector v1 = DoubleVector.fromArray(D_SPECIES, da, index); DoubleVector v2 = DoubleVector.fromArray(D_SPECIES, db, index); @@ -1950,7 +1950,7 @@ public class VectorMinMaxTransforms { @Test @IR(counts = { IRNode.MIN_VD, IRNode.VECTOR_SIZE_ANY, " 2 ", IRNode.MAX_VD, IRNode.VECTOR_SIZE_ANY, " 1 " }, - applyIfCPUFeatureOr = {"avx10_2", "true", "sve", "true"}) + applyIfCPUFeatureOr = {"avx10_2", "true", "sve", "true", "rvv", "true"}) public void testDoubleMaskedMinIdealDiffMaskMinMaxSwapped(int index) { DoubleVector v1 = DoubleVector.fromArray(D_SPECIES, da, index); DoubleVector v2 = DoubleVector.fromArray(D_SPECIES, db, index); @@ -1979,7 +1979,7 @@ public class VectorMinMaxTransforms { @Test @IR(counts = { IRNode.MIN_VD, IRNode.VECTOR_SIZE_ANY, " 2 ", IRNode.MAX_VD, IRNode.VECTOR_SIZE_ANY, " 1 " }, - applyIfCPUFeatureOr = {"avx10_2", "true", "sve", "true"}) + applyIfCPUFeatureOr = {"avx10_2", "true", "sve", "true", "rvv", "true"}) public void testDoubleMaskedMinIdealDiffMaskOuter(int index) { DoubleVector v1 = DoubleVector.fromArray(D_SPECIES, da, index); DoubleVector v2 = DoubleVector.fromArray(D_SPECIES, db, index); @@ -2008,7 +2008,7 @@ public class VectorMinMaxTransforms { @Test @IR(counts = { IRNode.MIN_VD, IRNode.VECTOR_SIZE_ANY, " 2 ", IRNode.MAX_VD, IRNode.VECTOR_SIZE_ANY, " 1 " }, - applyIfCPUFeatureOr = {"avx10_2", "true", "sve", "true"}) + applyIfCPUFeatureOr = {"avx10_2", "true", "sve", "true", "rvv", "true"}) public void testDoubleMaskedMinIdealAllDiffMask(int index) { DoubleVector v1 = DoubleVector.fromArray(D_SPECIES, da, index); DoubleVector v2 = DoubleVector.fromArray(D_SPECIES, db, index); diff --git a/test/hotspot/jtreg/compiler/vectorapi/VectorStoreMaskIdentityTest.java b/test/hotspot/jtreg/compiler/vectorapi/VectorStoreMaskIdentityTest.java index c019f116373..527041b58a6 100644 --- a/test/hotspot/jtreg/compiler/vectorapi/VectorStoreMaskIdentityTest.java +++ b/test/hotspot/jtreg/compiler/vectorapi/VectorStoreMaskIdentityTest.java @@ -73,7 +73,7 @@ public class VectorStoreMaskIdentityTest { IRNode.VECTOR_LOAD_MASK, "= 0", IRNode.VECTOR_STORE_MASK, "= 0", IRNode.VECTOR_MASK_CAST, "= 0" }, - applyIfCPUFeatureOr = { "asimd", "true", "avx", "true" }, + applyIfCPUFeatureOr = { "asimd", "true", "avx", "true", "rvv", "true" }, applyIf = { "MaxVectorSize", ">= 16" }) public static void testVectorMaskStoreIdentityByte() { VectorMask mask_byte_64 = VectorMask.fromArray(B64, mask_in, 0); @@ -93,7 +93,7 @@ public class VectorStoreMaskIdentityTest { IRNode.VECTOR_LOAD_MASK, "= 0", IRNode.VECTOR_STORE_MASK, "= 0", IRNode.VECTOR_MASK_CAST, "= 0" }, - applyIfCPUFeatureOr = { "sve", "true", "avx2", "true" }, + applyIfCPUFeatureOr = { "sve", "true", "avx2", "true", "rvv", "true" }, applyIf = { "MaxVectorSize", "> 16" }) public static void testVectorMaskStoreIdentityByte256() { VectorMask mask_byte_64 = VectorMask.fromArray(B64, mask_in, 0); @@ -113,7 +113,7 @@ public class VectorStoreMaskIdentityTest { IRNode.VECTOR_LOAD_MASK, "= 0", IRNode.VECTOR_STORE_MASK, "= 0", IRNode.VECTOR_MASK_CAST, "= 0" }, - applyIfCPUFeatureOr = { "asimd", "true", "avx", "true" }, + applyIfCPUFeatureOr = { "asimd", "true", "avx", "true", "rvv", "true" }, applyIf = { "MaxVectorSize", ">= 16" }) public static void testVectorMaskStoreIdentityShort() { VectorMask mask_short_128 = VectorMask.fromArray(S128, mask_in, 0); @@ -133,7 +133,7 @@ public class VectorStoreMaskIdentityTest { IRNode.VECTOR_LOAD_MASK, "= 0", IRNode.VECTOR_STORE_MASK, "= 0", IRNode.VECTOR_MASK_CAST, "= 0" }, - applyIfCPUFeatureOr = { "sve", "true", "avx2", "true" }, + applyIfCPUFeatureOr = { "sve", "true", "avx2", "true", "rvv", "true" }, applyIf = { "MaxVectorSize", "> 16" }) public static void testVectorMaskStoreIdentityShort256() { VectorMask mask_short_128 = VectorMask.fromArray(S128, mask_in, 0); @@ -153,7 +153,7 @@ public class VectorStoreMaskIdentityTest { IRNode.VECTOR_LOAD_MASK, "= 0", IRNode.VECTOR_STORE_MASK, "= 0", IRNode.VECTOR_MASK_CAST, "= 0" }, - applyIfCPUFeatureOr = { "asimd", "true", "avx", "true" }, + applyIfCPUFeatureOr = { "asimd", "true", "avx", "true", "rvv", "true" }, applyIf = { "MaxVectorSize", ">= 16" }) public static void testVectorMaskStoreIdentityInt() { VectorMask mask_int_128 = VectorMask.fromArray(I128, mask_in, 0); @@ -173,7 +173,7 @@ public class VectorStoreMaskIdentityTest { IRNode.VECTOR_LOAD_MASK, "= 0", IRNode.VECTOR_STORE_MASK, "= 0", IRNode.VECTOR_MASK_CAST, "= 0" }, - applyIfCPUFeatureOr = { "sve", "true", "avx2", "true" }, + applyIfCPUFeatureOr = { "sve", "true", "avx2", "true", "rvv", "true" }, applyIf = { "MaxVectorSize", "> 16" }) public static void testVectorMaskStoreIdentityInt256() { VectorMask mask_int_128 = VectorMask.fromArray(I128, mask_in, 0); @@ -193,7 +193,7 @@ public class VectorStoreMaskIdentityTest { IRNode.VECTOR_LOAD_MASK, "= 0", IRNode.VECTOR_STORE_MASK, "= 0", IRNode.VECTOR_MASK_CAST, "= 0" }, - applyIfCPUFeatureOr = { "asimd", "true" }, + applyIfCPUFeatureOr = { "asimd", "true", "rvv", "true" }, applyIf = { "MaxVectorSize", ">= 16" }) public static void testVectorMaskStoreIdentityLong() { VectorMask mask_long_128 = VectorMask.fromArray(L128, mask_in, 0); @@ -213,7 +213,7 @@ public class VectorStoreMaskIdentityTest { IRNode.VECTOR_LOAD_MASK, "= 0", IRNode.VECTOR_STORE_MASK, "= 0", IRNode.VECTOR_MASK_CAST, "= 0" }, - applyIfCPUFeatureOr = { "sve", "true", "avx2", "true" }, + applyIfCPUFeatureOr = { "sve", "true", "avx2", "true", "rvv", "true" }, applyIf = { "MaxVectorSize", "> 16" }) public static void testVectorMaskStoreIdentityLong256() { VectorMask mask_long_256 = VectorMask.fromArray(L256, mask_in, 0); @@ -233,7 +233,7 @@ public class VectorStoreMaskIdentityTest { IRNode.VECTOR_LOAD_MASK, "= 0", IRNode.VECTOR_STORE_MASK, "= 0", IRNode.VECTOR_MASK_CAST, "= 0" }, - applyIfCPUFeatureOr = { "asimd", "true", "avx", "true" }, + applyIfCPUFeatureOr = { "asimd", "true", "avx", "true", "rvv", "true" }, applyIf = { "MaxVectorSize", ">= 16" }) public static void testVectorMaskStoreIdentityFloat() { VectorMask mask_float_128 = VectorMask.fromArray(F128, mask_in, 0); @@ -253,7 +253,7 @@ public class VectorStoreMaskIdentityTest { IRNode.VECTOR_LOAD_MASK, "= 0", IRNode.VECTOR_STORE_MASK, "= 0", IRNode.VECTOR_MASK_CAST, "= 0" }, - applyIfCPUFeatureOr = { "sve", "true", "avx2", "true" }, + applyIfCPUFeatureOr = { "sve", "true", "avx2", "true", "rvv", "true" }, applyIf = { "MaxVectorSize", "> 16" }) public static void testVectorMaskStoreIdentityFloat256() { VectorMask mask_float_128 = VectorMask.fromArray(F128, mask_in, 0); @@ -273,7 +273,7 @@ public class VectorStoreMaskIdentityTest { IRNode.VECTOR_LOAD_MASK, "= 0", IRNode.VECTOR_STORE_MASK, "= 0", IRNode.VECTOR_MASK_CAST, "= 0" }, - applyIfCPUFeatureOr = { "asimd", "true" }, + applyIfCPUFeatureOr = { "asimd", "true", "rvv", "true" }, applyIf = { "MaxVectorSize", ">= 16" }) public static void testVectorMaskStoreIdentityDouble() { VectorMask mask_double_128 = VectorMask.fromArray(D128, mask_in, 0); @@ -293,7 +293,7 @@ public class VectorStoreMaskIdentityTest { IRNode.VECTOR_LOAD_MASK, "= 0", IRNode.VECTOR_STORE_MASK, "= 0", IRNode.VECTOR_MASK_CAST, "= 0" }, - applyIfCPUFeatureOr = { "sve", "true", "avx2", "true" }, + applyIfCPUFeatureOr = { "sve", "true", "avx2", "true", "rvv", "true" }, applyIf = { "MaxVectorSize", "> 16" }) public static void testVectorMaskStoreIdentityDouble256() { VectorMask mask_double_256 = VectorMask.fromArray(D256, mask_in, 0); @@ -314,4 +314,4 @@ public class VectorStoreMaskIdentityTest { .addFlags("--add-modules=jdk.incubator.vector") .start(); } -} \ No newline at end of file +} diff --git a/test/hotspot/jtreg/compiler/vectorization/TestFloat16VectorOperations.java b/test/hotspot/jtreg/compiler/vectorization/TestFloat16VectorOperations.java index 929a70f304a..00a556cff8f 100644 --- a/test/hotspot/jtreg/compiler/vectorization/TestFloat16VectorOperations.java +++ b/test/hotspot/jtreg/compiler/vectorization/TestFloat16VectorOperations.java @@ -24,7 +24,7 @@ /** * @test -* @bug 8346236 +* @bug 8346236 8381617 * @summary Auto-vectorization support for various Float16 operations * @modules jdk.incubator.vector * @library /test/lib / @@ -96,7 +96,7 @@ public class TestFloat16VectorOperations { @Test @Warmup(50) @IR(counts = {IRNode.ADD_VHF, " >0 "}, - applyIfCPUFeatureOr = {"avx512_fp16", "true", "zvfh", "true", "sve", "true"}) + applyIfCPUFeatureOr = {"avx512_fp16", "true", "zvfh", "true"}) @IR(counts = {IRNode.ADD_VHF, " >0 "}, applyIfCPUFeatureAnd = {"fphp", "true", "asimdhp", "true"}) public void vectorAddFloat16() { @@ -117,7 +117,7 @@ public class TestFloat16VectorOperations { @Test @Warmup(50) @IR(counts = {IRNode.SUB_VHF, " >0 "}, - applyIfCPUFeatureOr = {"avx512_fp16", "true", "zvfh", "true", "sve", "true"}) + applyIfCPUFeatureOr = {"avx512_fp16", "true", "zvfh", "true"}) @IR(counts = {IRNode.SUB_VHF, " >0 "}, applyIfCPUFeatureAnd = {"fphp", "true", "asimdhp", "true"}) public void vectorSubFloat16() { @@ -138,7 +138,7 @@ public class TestFloat16VectorOperations { @Test @Warmup(50) @IR(counts = {IRNode.MUL_VHF, " >0 "}, - applyIfCPUFeatureOr = {"avx512_fp16", "true", "zvfh", "true", "sve", "true"}) + applyIfCPUFeatureOr = {"avx512_fp16", "true", "zvfh", "true"}) @IR(counts = {IRNode.MUL_VHF, " >0 "}, applyIfCPUFeatureAnd = {"fphp", "true", "asimdhp", "true"}) public void vectorMulFloat16() { @@ -158,7 +158,7 @@ public class TestFloat16VectorOperations { @Test @Warmup(50) @IR(counts = {IRNode.DIV_VHF, " >0 "}, - applyIfCPUFeatureOr = {"avx512_fp16", "true", "zvfh", "true", "sve", "true"}) + applyIfCPUFeatureOr = {"avx512_fp16", "true", "zvfh", "true"}) @IR(counts = {IRNode.DIV_VHF, " >0 "}, applyIfCPUFeatureAnd = {"fphp", "true", "asimdhp", "true"}) public void vectorDivFloat16() { @@ -178,7 +178,7 @@ public class TestFloat16VectorOperations { @Test @Warmup(50) @IR(counts = {IRNode.MIN_VHF, " >0 "}, - applyIfCPUFeatureOr = {"avx512_fp16", "true", "zvfh", "true", "sve", "true"}) + applyIfCPUFeatureOr = {"avx512_fp16", "true", "zvfh", "true"}) @IR(counts = {IRNode.MIN_VHF, " >0 "}, applyIfCPUFeatureAnd = {"fphp", "true", "asimdhp", "true"}) public void vectorMinFloat16() { @@ -198,7 +198,7 @@ public class TestFloat16VectorOperations { @Test @Warmup(50) @IR(counts = {IRNode.MAX_VHF, " >0 "}, - applyIfCPUFeatureOr = {"avx512_fp16", "true", "zvfh", "true", "sve", "true"}) + applyIfCPUFeatureOr = {"avx512_fp16", "true", "zvfh", "true"}) @IR(counts = {IRNode.MAX_VHF, " >0 "}, applyIfCPUFeatureAnd = {"fphp", "true", "asimdhp", "true"}) public void vectorMaxFloat16() { @@ -218,7 +218,7 @@ public class TestFloat16VectorOperations { @Test @Warmup(50) @IR(counts = {IRNode.SQRT_VHF, " >0 "}, - applyIfCPUFeatureOr = {"avx512_fp16", "true", "zvfh", "true", "sve", "true"}) + applyIfCPUFeatureOr = {"avx512_fp16", "true", "zvfh", "true"}) @IR(counts = {IRNode.SQRT_VHF, " >0 "}, applyIfCPUFeatureAnd = {"fphp", "true", "asimdhp", "true"}) public void vectorSqrtFloat16() { @@ -238,7 +238,7 @@ public class TestFloat16VectorOperations { @Test @Warmup(50) @IR(counts = {IRNode.FMA_VHF, " >0 "}, - applyIfCPUFeatureOr = {"avx512_fp16", "true", "zvfh", "true", "sve", "true"}) + applyIfCPUFeatureOr = {"avx512_fp16", "true", "zvfh", "true"}) @IR(counts = {IRNode.FMA_VHF, " >0 "}, applyIfCPUFeatureAnd = {"fphp", "true", "asimdhp", "true"}) public void vectorFmaFloat16() { @@ -260,7 +260,7 @@ public class TestFloat16VectorOperations { @Test @Warmup(50) @IR(counts = {IRNode.FMA_VHF, " >0 "}, - applyIfCPUFeatureOr = {"avx512_fp16", "true", "zvfh", "true", "sve", "true"}) + applyIfCPUFeatureOr = {"avx512_fp16", "true", "zvfh", "true"}) @IR(counts = {IRNode.FMA_VHF, " >0 "}, applyIfCPUFeatureAnd = {"fphp", "true", "asimdhp", "true"}) public void vectorFmaFloat16ScalarMixedConstants() { @@ -283,7 +283,7 @@ public class TestFloat16VectorOperations { @Test @Warmup(50) @IR(counts = {IRNode.FMA_VHF, " >0 "}, - applyIfCPUFeatureOr = {"avx512_fp16", "true", "zvfh", "true", "sve", "true"}) + applyIfCPUFeatureOr = {"avx512_fp16", "true", "zvfh", "true"}) @IR(counts = {IRNode.FMA_VHF, " >0 "}, applyIfCPUFeatureAnd = {"fphp", "true", "asimdhp", "true"}) public void vectorFmaFloat16MixedConstants() { @@ -306,7 +306,7 @@ public class TestFloat16VectorOperations { @Test @Warmup(50) @IR(counts = {IRNode.FMA_VHF, " 0 "}, - applyIfCPUFeatureOr = {"avx512_fp16", "true", "zvfh", "true", "sve", "true"}) + applyIfCPUFeatureOr = {"avx512_fp16", "true", "zvfh", "true"}) @IR(counts = {IRNode.FMA_VHF, " 0 "}, applyIfCPUFeatureAnd = {"fphp", "true", "asimdhp", "true"}) public void vectorFmaFloat16AllConstants() { @@ -333,7 +333,7 @@ public class TestFloat16VectorOperations { @Test @Warmup(50) @IR(counts = {IRNode.ADD_VHF, " >0 "}, - applyIfCPUFeatureOr = {"avx512_fp16", "true", "zvfh", "true", "sve", "true"}) + applyIfCPUFeatureOr = {"avx512_fp16", "true", "zvfh", "true"}) @IR(counts = {IRNode.ADD_VHF, " >0 "}, applyIfCPUFeatureAnd = {"fphp", "true", "asimdhp", "true"}) public void vectorAddConstInputFloat16() { diff --git a/test/hotspot/jtreg/containers/docker/TestMemoryWithSubgroups.java b/test/hotspot/jtreg/containers/docker/TestMemoryWithSubgroups.java index 35b7bf993f7..016bb5bf592 100644 --- a/test/hotspot/jtreg/containers/docker/TestMemoryWithSubgroups.java +++ b/test/hotspot/jtreg/containers/docker/TestMemoryWithSubgroups.java @@ -62,66 +62,48 @@ public class TestMemoryWithSubgroups { Common.prepareWhiteBox(); DockerTestUtils.buildJdkContainerImage(imageName); - if ("cgroupv1".equals(metrics.getProvider())) { - try { - testMemoryLimitSubgroupV1("200m", "100m", "104857600", false); - testMemoryLimitSubgroupV1("1g", "500m", "524288000", false); - testMemoryLimitSubgroupV1("200m", "100m", "104857600", true); - testMemoryLimitSubgroupV1("1g", "500m", "524288000", true); - } finally { - DockerTestUtils.removeDockerImage(imageName); - } - } else if ("cgroupv2".equals(metrics.getProvider())) { - try { - testMemoryLimitSubgroupV2("200m", "100m", "104857600", false); - testMemoryLimitSubgroupV2("1g", "500m", "524288000", false); - testMemoryLimitSubgroupV2("200m", "100m", "104857600", true); - testMemoryLimitSubgroupV2("1g", "500m", "524288000", true); - } finally { - DockerTestUtils.removeDockerImage(imageName); - } - } else { + String provider = metrics.getProvider(); + if (!"cgroupv1".equals(provider) && !"cgroupv2".equals(provider)) { throw new SkippedException("Metrics are from neither cgroup v1 nor v2, skipped for now."); } + + try { + testMemoryLimitSubgroup(provider, "200m", "100m", "104857600", false); + testMemoryLimitSubgroup(provider, "1g", "500m", "524288000", false); + testMemoryLimitSubgroup(provider, "200m", "100m", "104857600", true); + testMemoryLimitSubgroup(provider, "1g", "500m", "524288000", true); + } finally { + DockerTestUtils.removeDockerImage(imageName); + } } - private static void testMemoryLimitSubgroupV1(String containerMemorySize, String valueToSet, String expectedValue, boolean privateNamespace) + private static void testMemoryLimitSubgroup(String cgroupVersion, String containerMemorySize, + String valueToSet, String expectedValue, boolean privateNamespace) throws Exception { - Common.logNewTestCase("Cgroup V1 subgroup memory limit: " + valueToSet); + final String upperVersion = "cgroupv1".equals(cgroupVersion) ? "V1" : "V2"; + Common.logNewTestCase("Cgroup " + upperVersion + " subgroup memory limit: " + valueToSet); DockerRunOptions opts = new DockerRunOptions(imageName, "sh", "-c"); opts.javaOpts = new ArrayList<>(); opts.appendTestJavaOptions = false; opts.addDockerOpts("--privileged") + .addDockerOpts("--user", "root") .addDockerOpts("--cgroupns=" + (privateNamespace ? "private" : "host")) .addDockerOpts("--memory", containerMemorySize); - opts.addClassOptions("mkdir -p /sys/fs/cgroup/memory/test ; " + - "echo " + valueToSet + " > /sys/fs/cgroup/memory/test/memory.limit_in_bytes ; " + - "echo $$ > /sys/fs/cgroup/memory/test/cgroup.procs ; " + - "/jdk/bin/java -Xlog:os+container=trace -version"); - - Common.run(opts) - .shouldMatch("Lowest limit was:.*" + expectedValue); - } - - private static void testMemoryLimitSubgroupV2(String containerMemorySize, String valueToSet, String expectedValue, boolean privateNamespace) - throws Exception { - - Common.logNewTestCase("Cgroup V2 subgroup memory limit: " + valueToSet); - - DockerRunOptions opts = new DockerRunOptions(imageName, "sh", "-c"); - opts.javaOpts = new ArrayList<>(); - opts.appendTestJavaOptions = false; - opts.addDockerOpts("--privileged") - .addDockerOpts("--cgroupns=" + (privateNamespace ? "private" : "host")) - .addDockerOpts("--memory", containerMemorySize); - opts.addClassOptions("mkdir -p /sys/fs/cgroup/memory/test ; " + - "echo $$ > /sys/fs/cgroup/memory/test/cgroup.procs ; " + - "echo '+memory' > /sys/fs/cgroup/cgroup.subtree_control ; " + - "echo '+memory' > /sys/fs/cgroup/memory/cgroup.subtree_control ; " + - "echo " + valueToSet + " > /sys/fs/cgroup/memory/test/memory.max ; " + - "/jdk/bin/java -Xlog:os+container=trace -version"); + if ("cgroupv1".equals(cgroupVersion)) { + opts.addClassOptions("mkdir -p /sys/fs/cgroup/memory/test ; " + + "echo " + valueToSet + " > /sys/fs/cgroup/memory/test/memory.limit_in_bytes ; " + + "echo $$ > /sys/fs/cgroup/memory/test/cgroup.procs ; " + + "/jdk/bin/java -Xlog:os+container=trace -version"); + } else { + opts.addClassOptions("mkdir -p /sys/fs/cgroup/memory/test ; " + + "echo $$ > /sys/fs/cgroup/memory/test/cgroup.procs ; " + + "echo '+memory' > /sys/fs/cgroup/cgroup.subtree_control ; " + + "echo '+memory' > /sys/fs/cgroup/memory/cgroup.subtree_control ; " + + "echo " + valueToSet + " > /sys/fs/cgroup/memory/test/memory.max ; " + + "/jdk/bin/java -Xlog:os+container=trace -version"); + } Common.run(opts) .shouldMatch("Lowest limit was:.*" + expectedValue); diff --git a/test/hotspot/jtreg/containers/systemd/SystemdContainerDetectionTest.java b/test/hotspot/jtreg/containers/systemd/SystemdContainerDetectionTest.java new file mode 100644 index 00000000000..266e9a00309 --- /dev/null +++ b/test/hotspot/jtreg/containers/systemd/SystemdContainerDetectionTest.java @@ -0,0 +1,121 @@ +/* + * Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * 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 jdk.internal.platform.Metrics; +import jdk.test.lib.containers.systemd.SystemdRunOptions; +import jdk.test.lib.containers.systemd.SystemdTestUtils; +import jdk.test.lib.process.OutputAnalyzer; +import jtreg.SkippedException; + +/* + * @test + * @summary Container detection test for a JDK inside a systemd slice. + * @requires systemd.support + * @library /test/lib + * @modules java.base/jdk.internal.platform + * @build HelloSystemd jdk.test.whitebox.WhiteBox + * @run driver jdk.test.lib.helpers.ClassFileInstaller -jar whitebox.jar jdk.test.whitebox.WhiteBox + * @run main/othervm SystemdContainerDetectionTest + */ +public class SystemdContainerDetectionTest { + + private static final int MB = 1024 * 1024; + private static final int EXPECTED_LIMIT_MB = 512; + + public static void main(String[] args) throws Exception { + Metrics metrics = Metrics.systemMetrics(); + + testWithoutLimits(); + testCpuLimit(); + testMemoryLimit(); + if ("cgroupv2".equals(metrics.getProvider())) { + // MemoryHigh/MemoryLow based detection requires cgroup v2 + testMemoryLow(); + testMemoryHigh(); + } + } + + private static void testWithoutLimits() throws Exception { + OutputAnalyzer out = runWithLimits("infinity", null, null, null); + assertContainerized(out, false); + } + + private static void testCpuLimit() throws Exception { + OutputAnalyzer out = runWithLimits("infinity", null, null, "50%"); + assertContainerized(out, true); + out.shouldContain("OSContainer::active_processor_count:"); + } + + private static void testMemoryLimit() throws Exception { + OutputAnalyzer out = runWithLimits(String.format("%dM", EXPECTED_LIMIT_MB), null, null, null); + assertContainerized(out, true); + out.shouldContain(String.format("Memory Limit is: %d", EXPECTED_LIMIT_MB * MB)); + } + + private static void testMemoryLow() throws Exception { + OutputAnalyzer out = runWithLimits("infinity", String.format("%dM", EXPECTED_LIMIT_MB), null, null); + assertContainerized(out, true); + out.shouldContain(String.format("Memory Soft Limit is: %d", EXPECTED_LIMIT_MB * MB)); + } + + private static void testMemoryHigh() throws Exception { + OutputAnalyzer out = runWithLimits("infinity", null, String.format("%dM", EXPECTED_LIMIT_MB), null); + assertContainerized(out, true); + out.shouldContain(String.format("Memory Throttle Limit is: %d", EXPECTED_LIMIT_MB * MB)); + } + + private static void assertContainerized(OutputAnalyzer out, boolean expected) { + try { + out.shouldHaveExitValue(0) + .shouldContain("Hello Systemd") + .shouldContain(String.format("OSContainer::init: is_containerized() = %b", expected)); + } catch (RuntimeException e) { + // CPU/memory delegation needs to be enabled when run as user on cg v2 + if (SystemdTestUtils.RUN_AS_USER) { + String hint = "When run as user on cg v2 cpu/memory delegation needs to be configured!"; + throw new SkippedException(hint); + } + throw e; + } + } + + private static OutputAnalyzer runWithLimits(String memoryLimit, + String memoryLow, + String memoryHigh, + String cpuLimit) throws Exception { + SystemdRunOptions opts = SystemdTestUtils.newOpts("HelloSystemd"); + opts.memoryLimit(memoryLimit); + if (memoryHigh != null) { + opts.memoryHigh(memoryHigh); + } + if (memoryLow != null) { + opts.memoryLow(memoryLow); + } + if (cpuLimit != null) { + opts.cpuLimit(cpuLimit); + } + return SystemdTestUtils.buildAndRunSystemdJava(opts); + } + +} diff --git a/test/hotspot/jtreg/gc/arguments/TestAggressiveHeap.java b/test/hotspot/jtreg/gc/arguments/TestAggressiveHeap.java deleted file mode 100644 index 758747d451a..00000000000 --- a/test/hotspot/jtreg/gc/arguments/TestAggressiveHeap.java +++ /dev/null @@ -1,95 +0,0 @@ -/* - * Copyright (c) 2017, 2024, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package gc.arguments; - -/* - * @test TestAggressiveHeap - * @bug 8179084 - * @requires vm.gc.Parallel - * @summary Test argument processing for -XX:+AggressiveHeap. - * @library /test/lib - * @library / - * @modules java.management - * @run driver gc.arguments.TestAggressiveHeap - */ - -import java.lang.management.ManagementFactory; -import javax.management.MBeanServer; -import javax.management.ObjectName; - -import jdk.test.lib.process.OutputAnalyzer; -import jtreg.SkippedException; - -public class TestAggressiveHeap { - - public static void main(String args[]) throws Exception { - if (canUseAggressiveHeapOption()) { - testFlag(); - } - } - - // Note: Not a normal boolean flag; -XX:-AggressiveHeap is invalid. - private static final String option = "-XX:+AggressiveHeap"; - - // Option requires at least 256M, else error during option processing. - private static final long minMemory = 256 * 1024 * 1024; - - // Setting the heap to half of the physical memory is not suitable for - // a test environment with many tests running concurrently, setting to - // half of the required size instead. - private static final String heapSizeOption = "-Xmx128M"; - - // bool UseParallelGC = true {product} {command line} - private static final String parallelGCPattern = - " *bool +UseParallelGC *= *true +\\{product\\} *\\{command line\\}"; - - private static void testFlag() throws Exception { - OutputAnalyzer output = GCArguments.executeTestJava( - option, heapSizeOption, "-XX:+PrintFlagsFinal", "-version"); - - output.shouldHaveExitValue(0); - - String value = output.firstMatch(parallelGCPattern); - if (value == null) { - throw new RuntimeException( - option + " didn't set UseParallelGC as if from command line"); - } - } - - private static boolean haveRequiredMemory() throws Exception { - MBeanServer server = ManagementFactory.getPlatformMBeanServer(); - ObjectName os = new ObjectName("java.lang", "type", "OperatingSystem"); - Object attr = server.getAttribute(os, "TotalPhysicalMemorySize"); - String value = attr.toString(); - long memory = Long.parseLong(value); - return memory >= minMemory; - } - - private static boolean canUseAggressiveHeapOption() throws Exception { - if (!haveRequiredMemory()) { - throw new SkippedException("Skipping test of " + option + " : insufficient memory"); - } - return true; - } -} diff --git a/test/hotspot/jtreg/gc/g1/TestVerifyGCType.java b/test/hotspot/jtreg/gc/g1/TestVerifyGCType.java index 710236e1aae..fb04f54f641 100644 --- a/test/hotspot/jtreg/gc/g1/TestVerifyGCType.java +++ b/test/hotspot/jtreg/gc/g1/TestVerifyGCType.java @@ -166,6 +166,7 @@ public class TestVerifyGCType { "-Xmx16m", "-XX:ParallelGCThreads=1", "-XX:G1HeapWastePercent=1", + "-XX:+G1VerifyBitmaps", "-XX:+VerifyBeforeGC", "-XX:+VerifyAfterGC", "-XX:+VerifyDuringGC"}); diff --git a/test/hotspot/jtreg/gc/shenandoah/TestLargeArrayInit.java b/test/hotspot/jtreg/gc/shenandoah/TestLargeArrayInit.java new file mode 100644 index 00000000000..9ce254ff845 --- /dev/null +++ b/test/hotspot/jtreg/gc/shenandoah/TestLargeArrayInit.java @@ -0,0 +1,128 @@ +/* + * 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 id=adaptive + * @summary Verify zero-initialization completeness for large arrays under Shenandoah adaptive mode + * @requires vm.gc.Shenandoah + * @library /test/lib + * + * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions -Xmx512m -Xms512m + * -XX:+UseShenandoahGC -XX:ShenandoahGCHeuristics=adaptive + * TestLargeArrayInit + */ + +/* + * @test id=generational + * @summary Verify zero-initialization completeness for large arrays under Shenandoah generational mode + * @requires vm.gc.Shenandoah + * @library /test/lib + * + * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions -Xmx512m -Xms512m + * -XX:+UseShenandoahGC -XX:ShenandoahGCHeuristics=adaptive -XX:ShenandoahGCMode=generational + * TestLargeArrayInit + */ + +/* + * @test id=compact-on + * @summary Verify zero-initialization completeness for large arrays with compact object headers enabled + * @requires vm.gc.Shenandoah + * @library /test/lib + * + * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions -Xmx512m -Xms512m + * -XX:+UseShenandoahGC -XX:ShenandoahGCHeuristics=adaptive + * -XX:+UseCompactObjectHeaders + * TestLargeArrayInit + */ + +/* + * @test id=compact-off + * @summary Verify zero-initialization completeness for large arrays with compact object headers disabled + * @requires vm.gc.Shenandoah + * @library /test/lib + * + * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions -Xmx512m -Xms512m + * -XX:+UseShenandoahGC -XX:ShenandoahGCHeuristics=adaptive + * -XX:-UseCompactObjectHeaders + * TestLargeArrayInit + */ + +/** + * + * Allocates large byte[], int[], long[], and Object[] arrays whose sizes span + * multiple 64K-word segments (~100MB each), then verifies every element is + * zero (or null for reference arrays). + */ +public class TestLargeArrayInit { + + // ~100MB for each array type + static final int BYTE_LEN = 100 * 1024 * 1024; // 100M elements + static final int INT_LEN = 25 * 1024 * 1024; // 25M elements * 4 bytes = 100MB + static final int LONG_LEN = 12 * 1024 * 1024 + 512*1024; // ~100MB in longs + static final int OBJ_LEN = 12 * 1024 * 1024 + 512*1024; // ~100MB in refs (8 bytes each on 64-bit) + + public static void main(String[] args) { + testByteArray(); + testIntArray(); + testLongArray(); + testObjectArray(); + System.out.println("TestLargeArrayInit PASSED"); + } + + static void testByteArray() { + byte[] arr = new byte[BYTE_LEN]; + for (int i = 0; i < arr.length; i++) { + if (arr[i] != 0) { + throw new RuntimeException("byte[] not zero at index " + i + ": " + arr[i]); + } + } + } + + static void testIntArray() { + int[] arr = new int[INT_LEN]; + for (int i = 0; i < arr.length; i++) { + if (arr[i] != 0) { + throw new RuntimeException("int[] not zero at index " + i + ": " + arr[i]); + } + } + } + + static void testLongArray() { + long[] arr = new long[LONG_LEN]; + for (int i = 0; i < arr.length; i++) { + if (arr[i] != 0L) { + throw new RuntimeException("long[] not zero at index " + i + ": " + arr[i]); + } + } + } + + static void testObjectArray() { + Object[] arr = new Object[OBJ_LEN]; + for (int i = 0; i < arr.length; i++) { + if (arr[i] != null) { + throw new RuntimeException("Object[] not null at index " + i + ": " + arr[i]); + } + } + } +} diff --git a/test/hotspot/jtreg/gc/shenandoah/TestLargeArrayInitGCStress.java b/test/hotspot/jtreg/gc/shenandoah/TestLargeArrayInitGCStress.java new file mode 100644 index 00000000000..34f3b70197a --- /dev/null +++ b/test/hotspot/jtreg/gc/shenandoah/TestLargeArrayInitGCStress.java @@ -0,0 +1,190 @@ +/* + * 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 id=aggressive + * @summary Verify correct object metadata for large arrays under Shenandoah GC stress (aggressive heuristics) + * @requires vm.gc.Shenandoah + * @library /test/lib + * + * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions -Xmx256m -Xms256m + * -XX:+UseShenandoahGC -XX:ShenandoahGCHeuristics=aggressive + * TestLargeArrayInitGCStress + */ + +/* + * @test id=generational-aggressive + * @summary Verify correct object metadata for large arrays under Shenandoah generational mode with aggressive heuristics + * @requires vm.gc.Shenandoah + * @library /test/lib + * + * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions -Xmx256m -Xms256m + * -XX:+UseShenandoahGC -XX:ShenandoahGCHeuristics=aggressive -XX:ShenandoahGCMode=generational + * TestLargeArrayInitGCStress + */ + +/* + * @test id=compact-on + * @summary Verify correct object metadata for large arrays with compact object headers enabled + * @requires vm.gc.Shenandoah + * @library /test/lib + * + * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions -Xmx256m -Xms256m + * -XX:+UseShenandoahGC -XX:ShenandoahGCHeuristics=aggressive + + * -XX:+UseCompactObjectHeaders + * TestLargeArrayInitGCStress + */ + +/* + * @test id=compact-off + * @summary Verify correct object metadata for large arrays with compact object headers disabled + * @requires vm.gc.Shenandoah + * @library /test/lib + * + * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions -Xmx256m -Xms256m + * -XX:+UseShenandoahGC -XX:ShenandoahGCHeuristics=aggressive + * -XX:-UseCompactObjectHeaders + * TestLargeArrayInitGCStress + */ + +/** + * + * Allocates large arrays of various types under GC stress (aggressive heuristics, + * tight 256MB heap) and verifies that after each allocation: + * - array.length matches the requested length + * - array.getClass() matches the expected array type + * - All elements are zero/null + * + * Arrays are sized to span multiple 64K-word segments to exercise the segmented + * clearing path in ShenandoahObjArrayAllocator. The loop creates sustained GC + * pressure so that safepoints are likely to occur during array initialization. + */ +public class TestLargeArrayInitGCStress { + + static final int ITERATIONS = 50; + + // Array sizes: small (within one segment), medium (a few segments), large (many segments) + static final int[] BYTE_SIZES = {1024, 256 * 1024, 2 * 1024 * 1024, 16 * 1024 * 1024}; + static final int[] INT_SIZES = {1024, 64 * 1024, 512 * 1024, 4 * 1024 * 1024}; + static final int[] LONG_SIZES = {1024, 32 * 1024, 256 * 1024, 2 * 1024 * 1024}; + static final int[] OBJ_SIZES = {1024, 32 * 1024, 256 * 1024, 2 * 1024 * 1024}; + + // Volatile sink to prevent dead code elimination + static volatile Object sink; + + public static void main(String[] args) { + for (int iter = 0; iter < ITERATIONS; iter++) { + testByteArrays(); + testIntArrays(); + testLongArrays(); + testObjectArrays(); + } + System.out.println("TestLargeArrayInitGCStress PASSED"); + } + + static void testByteArrays() { + for (int len : BYTE_SIZES) { + byte[] arr = new byte[len]; + sink = arr; + verifyLength(arr.length, len, "byte[]"); + verifyClass(arr.getClass(), byte[].class, "byte[]"); + verifyByteZeros(arr, len); + } + } + + static void testIntArrays() { + for (int len : INT_SIZES) { + int[] arr = new int[len]; + sink = arr; + verifyLength(arr.length, len, "int[]"); + verifyClass(arr.getClass(), int[].class, "int[]"); + verifyIntZeros(arr, len); + } + } + + static void testLongArrays() { + for (int len : LONG_SIZES) { + long[] arr = new long[len]; + sink = arr; + verifyLength(arr.length, len, "long[]"); + verifyClass(arr.getClass(), long[].class, "long[]"); + verifyLongZeros(arr, len); + } + } + + static void testObjectArrays() { + for (int len : OBJ_SIZES) { + Object[] arr = new Object[len]; + sink = arr; + verifyLength(arr.length, len, "Object[]"); + verifyClass(arr.getClass(), Object[].class, "Object[]"); + verifyObjectNulls(arr, len); + } + } + + static void verifyLength(int actual, int expected, String type) { + if (actual != expected) { + throw new RuntimeException(type + " length mismatch: expected " + expected + ", got " + actual); + } + } + + static void verifyClass(Class actual, Class expected, String type) { + if (actual != expected) { + throw new RuntimeException(type + " class mismatch: expected " + expected.getName() + ", got " + actual.getName()); + } + } + + static void verifyByteZeros(byte[] arr, int len) { + for (int i = 0; i < len; i++) { + if (arr[i] != 0) { + throw new RuntimeException("byte[] not zero at index " + i + ": " + arr[i]); + } + } + } + + static void verifyIntZeros(int[] arr, int len) { + for (int i = 0; i < len; i++) { + if (arr[i] != 0) { + throw new RuntimeException("int[] not zero at index " + i + ": " + arr[i]); + } + } + } + + static void verifyLongZeros(long[] arr, int len) { + for (int i = 0; i < len; i++) { + if (arr[i] != 0L) { + throw new RuntimeException("long[] not zero at index " + i + ": " + arr[i]); + } + } + } + + static void verifyObjectNulls(Object[] arr, int len) { + for (int i = 0; i < len; i++) { + if (arr[i] != null) { + throw new RuntimeException("Object[] not null at index " + i + ": " + arr[i]); + } + } + } +} diff --git a/test/hotspot/jtreg/gc/shenandoah/TestRegionSamplingLogging.java b/test/hotspot/jtreg/gc/shenandoah/TestRegionSamplingLogging.java index 0017328b517..5c9536223f3 100644 --- a/test/hotspot/jtreg/gc/shenandoah/TestRegionSamplingLogging.java +++ b/test/hotspot/jtreg/gc/shenandoah/TestRegionSamplingLogging.java @@ -59,8 +59,10 @@ public class TestRegionSamplingLogging { } File directory = new File("."); - File[] files = directory.listFiles((dir, name) -> name.startsWith("region-snapshots") && name.endsWith(".log")); + File[] files = directory.listFiles((dir, name) -> name.startsWith("region-snapshots")); System.out.println(Arrays.toString(files)); + + // Expect one or more log files when region logging is enabled if (files == null || files.length == 0) { throw new IllegalStateException("Did not find expected snapshot log file."); } diff --git a/test/hotspot/jtreg/gc/shenandoah/TestShenandoahRegionLogging.java b/test/hotspot/jtreg/gc/shenandoah/TestShenandoahRegionLogging.java index 81e66c9d0cb..a5fe1589d25 100644 --- a/test/hotspot/jtreg/gc/shenandoah/TestShenandoahRegionLogging.java +++ b/test/hotspot/jtreg/gc/shenandoah/TestShenandoahRegionLogging.java @@ -33,6 +33,7 @@ * TestShenandoahRegionLogging */ import java.io.File; +import java.util.Arrays; public class TestShenandoahRegionLogging { public static void main(String[] args) throws Exception { @@ -40,9 +41,10 @@ public class TestShenandoahRegionLogging { File directory = new File("."); File[] files = directory.listFiles((dir, name) -> name.startsWith("region-snapshots")); + System.out.println(Arrays.toString(files)); // Expect one or more log files when region logging is enabled - if (files.length == 0) { + if (files == null || files.length == 0) { throw new Error("Expected at least one log file for region sampling data."); } } diff --git a/test/hotspot/jtreg/gc/shenandoah/TestSmallArrayInit.java b/test/hotspot/jtreg/gc/shenandoah/TestSmallArrayInit.java new file mode 100644 index 00000000000..3c15a140d18 --- /dev/null +++ b/test/hotspot/jtreg/gc/shenandoah/TestSmallArrayInit.java @@ -0,0 +1,141 @@ +/* + * 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 id=adaptive + * @summary Verify behavioral equivalence for small arrays under Shenandoah adaptive mode + * @requires vm.gc.Shenandoah + * @library /test/lib + * + * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions -Xmx256m -Xms256m + * -XX:+UseShenandoahGC -XX:ShenandoahGCHeuristics=adaptive + * TestSmallArrayInit + */ + +/* + * @test id=generational + * @summary Verify behavioral equivalence for small arrays under Shenandoah generational mode + * @requires vm.gc.Shenandoah + * @library /test/lib + * + * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+UnlockExperimentalVMOptions -Xmx256m -Xms256m + * -XX:+UseShenandoahGC -XX:ShenandoahGCHeuristics=adaptive -XX:ShenandoahGCMode=generational + * TestSmallArrayInit + */ + +/** + * + * For arrays with word_size <= 64K words (the segment size threshold), + * ShenandoahObjArrayAllocator delegates to ObjArrayAllocator::initialize(). + * This test verifies that small arrays of various types and sizes are correctly + * zero-initialized, confirming no regression vs. the default allocator behavior. + * + * Test sizes: + * - Tiny: 10 elements + * - Small: 1000 elements + * - Near boundary: just under 64K words (65536 words = 524288 bytes on 64-bit) + * byte[] -> 524288 elements (524288 bytes = 64K words) + * int[] -> 131072 elements (524288 bytes = 64K words) + * long[] -> 65536 elements (524288 bytes = 64K words) + * Object[] -> 65536 elements (524288 bytes = 64K words, 8 bytes/ref) + */ +public class TestSmallArrayInit { + + // Tiny sizes + static final int TINY = 10; + + // Small sizes + static final int SMALL = 1000; + + // Near 64K-word boundary sizes (just under 524288 bytes of element data) + // 64K words = 65536 words = 524288 bytes on 64-bit + static final int NEAR_BOUNDARY_BYTE = 524288; // 524288 bytes + static final int NEAR_BOUNDARY_INT = 131072; // 131072 * 4 = 524288 bytes + static final int NEAR_BOUNDARY_LONG = 65536; // 65536 * 8 = 524288 bytes + static final int NEAR_BOUNDARY_OBJ = 65536; // 65536 * 8 = 524288 bytes (8 bytes/ref on 64-bit) + + public static void main(String[] args) { + testByteArrays(); + testIntArrays(); + testLongArrays(); + testObjectArrays(); + System.out.println("TestSmallArrayInit PASSED"); + } + + static void testByteArrays() { + verifyByteArray(new byte[TINY], "tiny"); + verifyByteArray(new byte[SMALL], "small"); + verifyByteArray(new byte[NEAR_BOUNDARY_BYTE], "near-boundary"); + } + + static void testIntArrays() { + verifyIntArray(new int[TINY], "tiny"); + verifyIntArray(new int[SMALL], "small"); + verifyIntArray(new int[NEAR_BOUNDARY_INT], "near-boundary"); + } + + static void testLongArrays() { + verifyLongArray(new long[TINY], "tiny"); + verifyLongArray(new long[SMALL], "small"); + verifyLongArray(new long[NEAR_BOUNDARY_LONG], "near-boundary"); + } + + static void testObjectArrays() { + verifyObjectArray(new Object[TINY], "tiny"); + verifyObjectArray(new Object[SMALL], "small"); + verifyObjectArray(new Object[NEAR_BOUNDARY_OBJ], "near-boundary"); + } + + static void verifyByteArray(byte[] arr, String label) { + for (int i = 0; i < arr.length; i++) { + if (arr[i] != 0) { + throw new RuntimeException("byte[" + label + "] not zero at index " + i + ": " + arr[i]); + } + } + } + + static void verifyIntArray(int[] arr, String label) { + for (int i = 0; i < arr.length; i++) { + if (arr[i] != 0) { + throw new RuntimeException("int[" + label + "] not zero at index " + i + ": " + arr[i]); + } + } + } + + static void verifyLongArray(long[] arr, String label) { + for (int i = 0; i < arr.length; i++) { + if (arr[i] != 0L) { + throw new RuntimeException("long[" + label + "] not zero at index " + i + ": " + arr[i]); + } + } + } + + static void verifyObjectArray(Object[] arr, String label) { + for (int i = 0; i < arr.length; i++) { + if (arr[i] != null) { + throw new RuntimeException("Object[" + label + "] not null at index " + i + ": " + arr[i]); + } + } + } +} diff --git a/test/hotspot/jtreg/gc/shenandoah/mxbeans/TestPauseNotifications.java b/test/hotspot/jtreg/gc/shenandoah/mxbeans/TestPauseNotifications.java index 1ae3b690b0d..e5c3acaccac 100644 --- a/test/hotspot/jtreg/gc/shenandoah/mxbeans/TestPauseNotifications.java +++ b/test/hotspot/jtreg/gc/shenandoah/mxbeans/TestPauseNotifications.java @@ -109,6 +109,8 @@ public class TestPauseNotifications { static final long HEAP_MB = 128; // adjust for test configuration above static final long TARGET_MB = Long.getLong("target", 2_000); // 2 Gb allocation + static final long STEP_MS = 1000; + static final int SIZE = 100_000; static volatile Object sink; @@ -160,24 +162,21 @@ public class TestPauseNotifications { ((NotificationEmitter) bean).addNotificationListener(listener, null, null); } - final int size = 100_000; - long count = TARGET_MB * 1024 * 1024 / (16 + 4 * size); - + final long count = TARGET_MB * 1024 * 1024 / (16 + 4 * SIZE); for (int c = 0; c < count; c++) { - sink = new int[size]; + sink = new int[SIZE]; } // Look at test timeout to figure out how long we can wait without breaking into timeout. // Default to 1/4 of the remaining time in 1s steps. - final long STEP_MS = 1000; - long spentTimeNanos = System.nanoTime() - startTimeNanos; - long maxTries = (Utils.adjustTimeout(Utils.DEFAULT_TEST_TIMEOUT) - (spentTimeNanos / 1_000_000L)) / STEP_MS / 4; + final long spentTimeNanos = System.nanoTime() - startTimeNanos; + final long maxTries = (Utils.adjustTimeout(Utils.DEFAULT_TEST_TIMEOUT) - (spentTimeNanos / 1_000_000L)) / STEP_MS / 4; long actualPauses = 0; long actualCycles = 0; // Wait until enough notifications are accrued to match minimum boundary. - long minExpected = 10; + final long minExpected = 10; long tries = 0; while (tries++ < maxTries) { @@ -186,13 +185,20 @@ public class TestPauseNotifications { if (minExpected <= actualPauses && minExpected <= actualCycles) { // Wait a little bit to catch the lingering notifications. Thread.sleep(5000); - actualPauses = pausesCount.get(); - actualCycles = cyclesCount.get(); break; } Thread.sleep(STEP_MS); } + for (GarbageCollectorMXBean bean : ManagementFactory.getGarbageCollectorMXBeans()) { + ((NotificationEmitter) bean).removeNotificationListener(listener); + } + + actualPauses = pausesCount.get(); + actualCycles = cyclesCount.get(); + long actualPauseDuration = pausesDuration.get(); + long actualCycleDuration = cyclesDuration.get(); + { String msg = "Pauses expected = [" + minExpected + "; +inf], actual = " + actualPauses; if (minExpected <= actualPauses) { @@ -212,11 +218,7 @@ public class TestPauseNotifications { } { - long actualPauseDuration = pausesDuration.get(); - long actualCycleDuration = cyclesDuration.get(); - String msg = "Pauses duration (" + actualPauseDuration + ") is expected to be not larger than cycles duration (" + actualCycleDuration + ")"; - if (actualPauseDuration <= actualCycleDuration) { System.out.println(msg); } else { diff --git a/test/hotspot/jtreg/gc/shenandoah/options/TestRegionSizeArgs.java b/test/hotspot/jtreg/gc/shenandoah/options/TestRegionSizeArgs.java index 80962f0ffa6..1ce829c7dd9 100644 --- a/test/hotspot/jtreg/gc/shenandoah/options/TestRegionSizeArgs.java +++ b/test/hotspot/jtreg/gc/shenandoah/options/TestRegionSizeArgs.java @@ -38,8 +38,6 @@ import jdk.test.lib.process.OutputAnalyzer; public class TestRegionSizeArgs { public static void main(String[] args) throws Exception { testInvalidRegionSizes(); - testMinRegionSize(); - testMaxRegionSize(); } private static void testInvalidRegionSizes() throws Exception { @@ -146,88 +144,4 @@ public class TestRegionSizeArgs { output.shouldHaveExitValue(1); } } - - private static void testMinRegionSize() throws Exception { - - { - OutputAnalyzer output = ProcessTools.executeLimitedTestJava("-XX:+UnlockExperimentalVMOptions", - "-XX:+UseShenandoahGC", - "-Xms100m", - "-Xmx1g", - "-XX:ShenandoahMinRegionSize=255K", - "-version"); - output.shouldMatch("Invalid -XX:ShenandoahMinRegionSize option"); - output.shouldHaveExitValue(1); - } - - { - OutputAnalyzer output = ProcessTools.executeLimitedTestJava("-XX:+UnlockExperimentalVMOptions", - "-XX:+UseShenandoahGC", - "-Xms100m", - "-Xmx1g", - "-XX:ShenandoahMinRegionSize=1M", - "-XX:ShenandoahMaxRegionSize=260K", - "-version"); - output.shouldMatch("Invalid -XX:ShenandoahMinRegionSize or -XX:ShenandoahMaxRegionSize"); - output.shouldHaveExitValue(1); - } - { - OutputAnalyzer output = ProcessTools.executeLimitedTestJava("-XX:+UnlockExperimentalVMOptions", - "-XX:+UseShenandoahGC", - "-Xms100m", - "-Xmx1g", - "-XX:ShenandoahMinRegionSize=200m", - "-version"); - output.shouldMatch("Invalid -XX:ShenandoahMinRegionSize option"); - output.shouldHaveExitValue(1); - } - - { - OutputAnalyzer output = ProcessTools.executeLimitedTestJava("-XX:+UnlockExperimentalVMOptions", - "-XX:+UseShenandoahGC", - "-Xms100m", - "-Xmx1g", - "-XX:ShenandoahMinRegionSize=9m", - "-version"); - output.shouldHaveExitValue(0); - } - - // This used to assert that _conservative_max_heap_alignment is not a power-of-2. - { - OutputAnalyzer output = ProcessTools.executeLimitedTestJava("-XX:+UnlockExperimentalVMOptions", - "-XX:+UseShenandoahGC", - "-Xms100m", - "-Xmx1g", - "-XX:ShenandoahMaxRegionSize=33m", - "-version"); - output.shouldHaveExitValue(0); - } - - } - - private static void testMaxRegionSize() throws Exception { - - { - OutputAnalyzer output = ProcessTools.executeLimitedTestJava("-XX:+UnlockExperimentalVMOptions", - "-XX:+UseShenandoahGC", - "-Xms100m", - "-Xmx1g", - "-XX:ShenandoahMaxRegionSize=255K", - "-version"); - output.shouldMatch("Invalid -XX:ShenandoahMaxRegionSize option"); - output.shouldHaveExitValue(1); - } - - { - OutputAnalyzer output = ProcessTools.executeLimitedTestJava("-XX:+UnlockExperimentalVMOptions", - "-XX:+UseShenandoahGC", - "-Xms100m", - "-Xmx1g", - "-XX:ShenandoahMinRegionSize=1M", - "-XX:ShenandoahMaxRegionSize=260K", - "-version"); - output.shouldMatch("Invalid -XX:ShenandoahMinRegionSize or -XX:ShenandoahMaxRegionSize"); - output.shouldHaveExitValue(1); - } - } } diff --git a/test/hotspot/jtreg/runtime/8359166/Test.java b/test/hotspot/jtreg/runtime/8359166/Test.java new file mode 100644 index 00000000000..509a06a3de1 --- /dev/null +++ b/test/hotspot/jtreg/runtime/8359166/Test.java @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2026, IBM Corp. + * 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 8359166 + * @requires os.arch=="amd64" | os.arch=="x86_64" + * @requires vm.debug + * + * @run main/othervm + * -XX:-UseAddressNop -Xcomp -Xbatch -XX:-TieredCompilation Test + */ + +public class Test { + public static void main(String[] args) { + + } +} diff --git a/test/hotspot/jtreg/runtime/Nestmates/membership/TestNestmateMembership.java b/test/hotspot/jtreg/runtime/Nestmates/membership/TestNestmateMembership.java index 62bbcf7d5a7..4eddc765b51 100644 --- a/test/hotspot/jtreg/runtime/Nestmates/membership/TestNestmateMembership.java +++ b/test/hotspot/jtreg/runtime/Nestmates/membership/TestNestmateMembership.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -680,7 +680,7 @@ public class TestNestmateMembership { check_expected(expected, msg); } msg = "TestNestmateMembership$Caller cannot access a member of class " + - "TestNestmateMembership$TargetNoHost with modifiers \"private static\""; + "TestNestmateMembership$TargetNoHost with private access"; try { Caller.invokeTargetNoHostReflectively(); throw new Error("Missing IllegalAccessException: " + msg); @@ -729,7 +729,7 @@ public class TestNestmateMembership { check_expected(expected, msg); } msg = "class TestNestmateMembership$Caller cannot access a member of class " + - "TestNestmateMembership$TargetSelfHost with modifiers \"private static\""; + "TestNestmateMembership$TargetSelfHost with private access"; try { Caller.invokeTargetSelfHostReflectively(); throw new Error("Missing IllegalAccessError: " + msg); @@ -776,7 +776,7 @@ public class TestNestmateMembership { check_expected(expected, msg); } msg = "class TestNestmateMembership$Caller cannot access a member of class" + - " TestNestmateMembership$TargetMissingHost with modifiers \"private static\""; + " TestNestmateMembership$TargetMissingHost with private access"; try { Caller.invokeTargetMissingHostReflectively(); throw new Error("Missing IllegalAccessException: " + msg); @@ -831,7 +831,7 @@ public class TestNestmateMembership { check_expected(expected, msg); } msg = "class TestNestmateMembership$Caller cannot access a member of class "+ - "TestNestmateMembership$TargetNotInstanceHost with modifiers \"private static\""; + "TestNestmateMembership$TargetNotInstanceHost with private access"; try { Caller.invokeTargetNotInstanceHostReflectively(); throw new Error("Missing IllegalAccessException: " + msg); @@ -878,7 +878,7 @@ public class TestNestmateMembership { check_expected(expected, msg); } msg = "class TestNestmateMembership$Caller cannot access a member of class " + - "TestNestmateMembership$TargetNotOurHost with modifiers \"private static\""; + "TestNestmateMembership$TargetNotOurHost with private access"; try { Caller.invokeTargetNotOurHostReflectively(); throw new Error("Missing IllegalAccessException: " + msg); @@ -956,7 +956,7 @@ public class TestNestmateMembership { check_expected(expected, msg); } msg = "class TestNestmateMembership$Caller cannot access a member of class " + - "TestNestmateMembership$TargetNoHost with modifiers \"private\""; + "TestNestmateMembership$TargetNoHost with private access"; try { Caller.newTargetNoHostReflectively(); throw new Error("Missing IllegalAccessException: " + msg); @@ -1005,7 +1005,7 @@ public class TestNestmateMembership { check_expected(expected, msg); } msg = "class TestNestmateMembership$Caller cannot access a member of class " + - "TestNestmateMembership$TargetSelfHost with modifiers \"private\""; + "TestNestmateMembership$TargetSelfHost with private access"; try { Caller.newTargetSelfHostReflectively(); throw new Error("Missing IllegalAccessException: " + msg); @@ -1052,7 +1052,7 @@ public class TestNestmateMembership { check_expected(expected, msg); } msg = "class TestNestmateMembership$Caller cannot access a member of class " + - "TestNestmateMembership$TargetMissingHost with modifiers \"private\""; + "TestNestmateMembership$TargetMissingHost with private access"; try { Caller.newTargetMissingHostReflectively(); throw new Error("Missing IllegalAccessException: " + msg); @@ -1099,7 +1099,7 @@ public class TestNestmateMembership { check_expected(expected, msg); } msg = "class TestNestmateMembership$Caller cannot access a member of class " + - "TestNestmateMembership$TargetNotInstanceHost with modifiers \"private\""; + "TestNestmateMembership$TargetNotInstanceHost with private access"; try { Caller.newTargetNotInstanceHostReflectively(); throw new Error("Missing IllegalAccessException: " + msg); @@ -1146,7 +1146,7 @@ public class TestNestmateMembership { check_expected(expected, msg); } msg = "class TestNestmateMembership$Caller cannot access a member of class " + - "TestNestmateMembership$TargetNotOurHost with modifiers \"private\""; + "TestNestmateMembership$TargetNotOurHost with private access"; try { Caller.newTargetNotOurHostReflectively(); throw new Error("Missing IllegalAccessException: " + msg); @@ -1226,7 +1226,7 @@ public class TestNestmateMembership { check_expected(expected, msg); } msg = "class TestNestmateMembership$Caller cannot access a member of class " + - "TestNestmateMembership$TargetNoHost with modifiers \"private static\""; + "TestNestmateMembership$TargetNoHost with private access"; try { Caller.getFieldTargetNoHostReflectively(); throw new Error("Missing IllegalAccessException: " + msg); @@ -1275,7 +1275,7 @@ public class TestNestmateMembership { check_expected(expected, msg); } msg = "class TestNestmateMembership$Caller cannot access a member of class " + - "TestNestmateMembership$TargetSelfHost with modifiers \"private static\""; + "TestNestmateMembership$TargetSelfHost with private access"; try { Caller.getFieldTargetSelfHostReflectively(); throw new Error("Missing IllegalAccessException: " + msg); @@ -1323,7 +1323,7 @@ public class TestNestmateMembership { check_expected(expected, msg); } msg = "class TestNestmateMembership$Caller cannot access a member of class " + - "TestNestmateMembership$TargetMissingHost with modifiers \"private static\""; + "TestNestmateMembership$TargetMissingHost with private access"; try { Caller.getFieldTargetMissingHostReflectively(); throw new Error("Missing IllegalAccessException: " + msg); @@ -1371,7 +1371,7 @@ public class TestNestmateMembership { check_expected(expected, msg); } msg = "class TestNestmateMembership$Caller cannot access a member of class " + - "TestNestmateMembership$TargetNotInstanceHost with modifiers \"private static\""; + "TestNestmateMembership$TargetNotInstanceHost with private access"; try { Caller.getFieldTargetNotInstanceHostReflectively(); throw new Error("Missing IllegalAccessException: " + msg); @@ -1419,7 +1419,7 @@ public class TestNestmateMembership { check_expected(expected, msg); } msg = "class TestNestmateMembership$Caller cannot access a member of class " + - "TestNestmateMembership$TargetNotOurHost with modifiers \"private static\""; + "TestNestmateMembership$TargetNotOurHost with private access"; try { Caller.getFieldTargetNotOurHostReflectively(); throw new Error("Missing IllegalAccessException: " + msg); @@ -1496,7 +1496,7 @@ public class TestNestmateMembership { check_expected(expected, msg); } msg = "class TestNestmateMembership$Caller cannot access a member of class " + - "TestNestmateMembership$TargetNoHost with modifiers \"private static\""; + "TestNestmateMembership$TargetNoHost with private access"; try { Caller.putFieldTargetNoHostReflectively(); throw new Error("Missing IllegalAccessException: " + msg); @@ -1545,7 +1545,7 @@ public class TestNestmateMembership { check_expected(expected, msg); } msg = "class TestNestmateMembership$Caller cannot access a member of class " + - "TestNestmateMembership$TargetSelfHost with modifiers \"private static\""; + "TestNestmateMembership$TargetSelfHost with private access"; try { Caller.putFieldTargetSelfHostReflectively(); throw new Error("Missing IllegalAccessException: " + msg); @@ -1593,7 +1593,7 @@ public class TestNestmateMembership { check_expected(expected, msg); } msg = "class TestNestmateMembership$Caller cannot access a member of class " + - "TestNestmateMembership$TargetMissingHost with modifiers \"private static\""; + "TestNestmateMembership$TargetMissingHost with private access"; try { Caller.putFieldTargetMissingHostReflectively(); throw new Error("Missing IllegalAccessException: " + msg); @@ -1640,7 +1640,7 @@ public class TestNestmateMembership { check_expected(expected, msg); } msg = "class TestNestmateMembership$Caller cannot access a member of class " + - "TestNestmateMembership$TargetNotInstanceHost with modifiers \"private static\""; + "TestNestmateMembership$TargetNotInstanceHost with private access"; try { Caller.putFieldTargetNotInstanceHostReflectively(); throw new Error("Missing IllegalAccessException: " + msg); @@ -1688,7 +1688,7 @@ public class TestNestmateMembership { check_expected(expected, msg); } msg = "class TestNestmateMembership$Caller cannot access a member of class " + - "TestNestmateMembership$TargetNotOurHost with modifiers \"private static\""; + "TestNestmateMembership$TargetNotOurHost with private access"; try { Caller.putFieldTargetNotOurHostReflectively(); throw new Error("Missing IllegalAccessException: " + msg); diff --git a/test/hotspot/jtreg/runtime/cds/appcds/aotCache/AOTCacheConsistency.java b/test/hotspot/jtreg/runtime/cds/appcds/aotCache/AOTCacheConsistency.java new file mode 100644 index 00000000000..a48051bb672 --- /dev/null +++ b/test/hotspot/jtreg/runtime/cds/appcds/aotCache/AOTCacheConsistency.java @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * 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 + * @key randomness + * @summary AOTCacheConsistency This test checks that there is a CRC validation of the AOT Cache regions. + * @bug 8382166 + * @requires vm.cds.supports.aot.class.linking + * @library /test/lib /test/setup_aot + * @build jdk.test.whitebox.WhiteBox AOTCacheConsistency HelloWorld + * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox + * @run driver jdk.test.lib.helpers.ClassFileInstaller -jar app.jar HelloWorld + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI AOTCacheConsistency + */ + +import jdk.test.lib.cds.CDSArchiveUtils; +import jdk.test.lib.cds.SimpleCDSAppTester; +import jdk.test.lib.process.OutputAnalyzer; +import java.io.File; + +public class AOTCacheConsistency { + public static void main(String args[]) throws Exception { + // Train and run the app + SimpleCDSAppTester tester = SimpleCDSAppTester.of("AOTCacheConsistency") + .classpath("app.jar") + .appCommandLine("HelloWorld") + .setProductionChecker((OutputAnalyzer out) -> { + out.shouldContain("HelloWorld"); + }) + .runAOTWorkflow(); + + String aotCache = tester.aotCacheFile(); + + String[] regions = CDSArchiveUtils.getRegions(); + String orig = aotCache + ".orig"; + CDSArchiveUtils.copyArchiveFile(new File(aotCache), orig); // save original copy + + // Modify each of the region individually. The production should fail to run + // with these args; + String extraVMArgs[] = {"-XX:+VerifySharedSpaces", "-XX:AOTMode=on"}; + tester.setCheckExitValue(false); + + for (int i = 0; i < regions.length; i++) { + File f = CDSArchiveUtils.copyArchiveFile(new File(orig), aotCache); + System.out.println("\n=======\nTesting region " + i + " = " + regions[i]); + if (CDSArchiveUtils.modifyRegionContent(i, f)) { + tester.setProductionChecker((OutputAnalyzer out) -> { + out.shouldContain("Checksum verification failed."); + }); + tester.rerunProduction(extraVMArgs); + } + } + } +} \ No newline at end of file diff --git a/test/hotspot/jtreg/runtime/cds/appcds/aotCache/JcmdOnTrainingProcess.java b/test/hotspot/jtreg/runtime/cds/appcds/aotCache/JcmdOnTrainingProcess.java new file mode 100644 index 00000000000..f0342d85773 --- /dev/null +++ b/test/hotspot/jtreg/runtime/cds/appcds/aotCache/JcmdOnTrainingProcess.java @@ -0,0 +1,92 @@ +/* + * Copyright (c) 2026, Microsoft, Inc. All rights reserved. + * 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 8378894 + * @requires vm.cds.supports.aot.class.linking + * @requires vm.cds.write.archived.java.heap + * @summary Test the use of jcmd on a JVM process that's running in AOT training mode. + * @library /test/lib + * @build JcmdOnTrainingProcess + * @run driver jdk.test.lib.helpers.ClassFileInstaller -jar LingeredApp.jar + * jdk/test/lib/apps/LingeredApp + * jdk/test/lib/apps/LingeredApp$1 + * jdk/test/lib/apps/LingeredApp$SteadyStateLock + * jdk/test/lib/process/OutputBuffer + * @run driver JcmdOnTrainingProcess + */ + +import java.io.IOException; + +import jdk.test.lib.JDKToolLauncher; +import jdk.test.lib.apps.LingeredApp; +import jdk.test.lib.process.OutputAnalyzer; +import jdk.test.lib.process.ProcessTools; + +public class JcmdOnTrainingProcess { + public static void main(String[] args) throws Exception { + test_VM_native_memory(); + // Add other test cases here if needed in the future. + } + + static void test_VM_native_memory() throws Exception { + // In training run, we should not map any read-only regions. + OutputAnalyzer out = runJcmdOnTrainingProcess("VM.native_memory"); + out.shouldMatch("Shared class space .* readonly=0KB"); + } + + static OutputAnalyzer runJcmdOnTrainingProcess(String... cmds) throws Exception { + LingeredApp theApp = null; + try { + theApp = new LingeredApp(); + theApp.setUseDefaultClasspath(false); + LingeredApp.startApp(theApp, + "-cp", "LingeredApp.jar", + "-XX:AOTMode=record", + "-XX:AOTConfiguration=LingeredApp.aotconfig", + "-XX:NativeMemoryTracking=summary"); + long pid = theApp.getPid(); + + JDKToolLauncher jcmd = JDKToolLauncher.createUsingTestJDK("jcmd"); + jcmd.addToolArg(String.valueOf(pid)); + for (String cmd : cmds) { + jcmd.addToolArg(cmd); + } + + try { + OutputAnalyzer output = ProcessTools.executeProcess(jcmd.getCommand()); + output.shouldHaveExitValue(0); + return output; + } catch (Exception e) { + throw new RuntimeException("Test failed: " + e); + } + } catch (IOException e) { + throw new RuntimeException("Test failed: " + e); + } + finally { + LingeredApp.stopApp(theApp); + } + } +} diff --git a/test/hotspot/jtreg/runtime/cds/appcds/aotCode/AOTCodeCPUFeatureIncompatibilityTest.java b/test/hotspot/jtreg/runtime/cds/appcds/aotCode/AOTCodeCPUFeatureIncompatibilityTest.java index aa7becdb6f8..eebace23fea 100644 --- a/test/hotspot/jtreg/runtime/cds/appcds/aotCode/AOTCodeCPUFeatureIncompatibilityTest.java +++ b/test/hotspot/jtreg/runtime/cds/appcds/aotCode/AOTCodeCPUFeatureIncompatibilityTest.java @@ -51,41 +51,77 @@ import jdk.test.whitebox.WhiteBox; import jdk.test.whitebox.cpuinfo.CPUInfo; public class AOTCodeCPUFeatureIncompatibilityTest { + enum IncompatibilityMode { + MISSING, + ADDITIONAL + } public static void main(String... args) throws Exception { + int mode; List cpuFeatures = CPUInfo.getFeatures(); if (Platform.isX64()) { // Minimum value of UseSSE required by JVM is 2. So the production run has to be executed with UseSSE=2. // To simulate the case of incmpatible SSE feature, we can run this test only on system with higher SSE level (sse3 or above). if (isSSE3Supported(cpuFeatures)) { - testIncompatibleFeature("-XX:UseSSE=2", "sse3"); + testIncompatibleFeature("-XX:UseSSE=2", "sse3", IncompatibilityMode.MISSING); + testIncompatibleFeature("-XX:UseSSE=2", "sse3", IncompatibilityMode.ADDITIONAL); } if (isAVXSupported(cpuFeatures)) { - testIncompatibleFeature("-XX:UseAVX=0", "avx"); + testIncompatibleFeature("-XX:UseAVX=0", "avx", IncompatibilityMode.MISSING); + testIncompatibleFeature("-XX:UseAVX=0", "avx", IncompatibilityMode.ADDITIONAL); + } + } else if (Platform.isAArch64()) { + if (isCRC32Supported(cpuFeatures)) { + testIncompatibleFeature("-XX:-UseCRC32", "crc32", IncompatibilityMode.MISSING); + testIncompatibleFeature("-XX:-UseCRC32", "crc32", IncompatibilityMode.ADDITIONAL); } } } // vmOption = command line option to disable CPU feature // featureName = name of the CPU feature used by the JVM in the log messages - public static void testIncompatibleFeature(String vmOption, String featureName) throws Exception { + public static void testIncompatibleFeature(String vmOption, String featureName, IncompatibilityMode mode) throws Exception { new CDSAppTester("AOTCodeCPUFeatureIncompatibilityTest") { @Override public String[] vmArgs(RunMode runMode) { - if (runMode == RunMode.PRODUCTION) { - return new String[] {vmOption, "-Xlog:aot+codecache*=debug"}; - } else { - return new String[] {"-Xlog:aot+codecache*=debug"}; + if (runMode == RunMode.ASSEMBLY) { + if (mode == IncompatibilityMode.MISSING) { + return new String[] {"-Xlog:aot+codecache*=debug"}; + } else { + return new String[] {vmOption, "-Xlog:aot+codecache*=debug"}; + } + } else if (runMode == RunMode.PRODUCTION) { + if (mode == IncompatibilityMode.MISSING) { + return new String[] {vmOption, + "-XX:+UnlockDiagnosticVMOptions", + // Prevent exiting VM on failure + "-XX:-AbortVMOnAOTCodeFailure", + "-Xlog:aot+codecache*=debug"}; + } else { + return new String[] {"-XX:+UnlockDiagnosticVMOptions", + // Prevent exiting VM on failure + "-XX:-AbortVMOnAOTCodeFailure", + "-Xlog:aot+codecache*=debug"}; + } } + return new String[]{}; } @Override public void checkExecution(OutputAnalyzer out, RunMode runMode) throws Exception { if (runMode == RunMode.ASSEMBLY || runMode == RunMode.PRODUCTION) { - out.shouldMatch("CPU features recorded in AOTCodeCache:.*" + featureName + ".*"); + if (mode == IncompatibilityMode.MISSING) { + out.shouldMatch("CPU features recorded in AOTCodeCache:.*" + featureName + ".*"); + } else { + out.shouldNotMatch("CPU features recorded in AOTCodeCache:.*" + featureName + ".*"); + } } if (runMode == RunMode.PRODUCTION) { - out.shouldMatch("AOT Code Cache disabled: required cpu features are missing:.*" + featureName + ".*"); - out.shouldContain("Unable to use AOT Code Cache"); + out.shouldMatch("AOT Code Cache disabled: cpu features are incompatible"); + if (mode == IncompatibilityMode.MISSING) { + out.shouldMatch("cpu features that are required:.*" + featureName + ".*"); + } else { + out.shouldMatch("cpu features that are additional:.*" + featureName + ".*"); + } } } @Override @@ -108,4 +144,9 @@ public class AOTCodeCPUFeatureIncompatibilityTest { static boolean isAVXSupported(List cpuFeatures) { return cpuFeatures.contains("avx"); } + + // Only used on aarch64 platofrm + static boolean isCRC32Supported(List cpuFeatures) { + return cpuFeatures.contains("crc32"); + } } diff --git a/test/hotspot/jtreg/runtime/cds/appcds/aotCode/AOTCodeCompressedOopsTest.java b/test/hotspot/jtreg/runtime/cds/appcds/aotCode/AOTCodeCompressedOopsTest.java index 0fe11235749..9ca8ba9ed91 100644 --- a/test/hotspot/jtreg/runtime/cds/appcds/aotCode/AOTCodeCompressedOopsTest.java +++ b/test/hotspot/jtreg/runtime/cds/appcds/aotCode/AOTCodeCompressedOopsTest.java @@ -134,6 +134,7 @@ public class AOTCodeCompressedOopsTest { case RunMode.PRODUCTION: { List args = getVMArgsForHeapConfig(zeroBaseInProdPhase, zeroShiftInProdPhase); args.addAll(List.of("-XX:+UnlockDiagnosticVMOptions", + "-XX:-AbortVMOnAOTCodeFailure", "-Xlog:aot=info", // we need this to parse CompressedOops settings "-Xlog:aot+codecache+init=debug", "-Xlog:aot+codecache+exit=debug")); diff --git a/test/hotspot/jtreg/runtime/interpreter/TraceBytecodesSignatures.java b/test/hotspot/jtreg/runtime/interpreter/TraceBytecodesSignatures.java new file mode 100644 index 00000000000..a7881582d8c --- /dev/null +++ b/test/hotspot/jtreg/runtime/interpreter/TraceBytecodesSignatures.java @@ -0,0 +1,194 @@ +/* + * Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * 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 8370102 + * @requires vm.debug + * @library / /test/lib + * @summary Test to ensure the signatures in -XX:+TraceBytecodes are printed in edge cases + * @run driver TraceBytecodesSignatures + */ + +import java.io.IOException; +import java.util.List; + +import jdk.test.lib.Utils; +import jdk.test.lib.process.OutputAnalyzer; +import jdk.test.lib.process.ProcessTools; + +public class TraceBytecodesSignatures { + + public static void main(String[] args) + throws InterruptedException, IOException { + if (args.length == 1 && "worker".equals(args[0])) { + runTest(); + return; + } + // Enable byteocde tracing but disable compilation of the key methods + // that we will trace. + String[] processArgs = new String[] { + "-XX:+TraceBytecodes", + exclude("runTest"), + exclude("testSameMethod"), + exclude("testSameMethodHelper"), + excludeConstructor(), + exclude("testSelfRecursive"), + exclude("testSelfRecursiveHelper"), + klass(), + "worker" + }; + // Create a VM process and trace its bytecodes. + ProcessBuilder pb = ProcessTools.createTestJavaProcessBuilder(processArgs); + OutputAnalyzer oa = new OutputAnalyzer(pb.start()) + .shouldHaveExitValue(0); + analyze(oa.stdoutAsLines()); + } + + private static void runTest() { + testSameMethod(true); + testSameMethod(false); + new TestConstructor(); + new TestConstructor(); + testSelfRecursive(3); + } + + // Expect 3 signature prints: + // 1. The first call + // 2. The first call switch back after the helper is called + // 3. The second call + private static final int EXPECTED_SAME_METHOD = 3; + + // Expect 2 signature prints: + // 1. The first call of the no-arg constructor + // 2. Switch back after calling the 1-arg constructor + // 3. The second call of the no-arg constructor + // 4. Switch back again + private static final int EXPECTED_CONSTRUCTOR = 4; + + // Expect 10 signature prints: + // 1. The first recursive call + // 2. The first switch back after the helper is called. + // 3. The second recursive call + // 4. The second switch back + // 5. The third recursive call + // 6. The third switch back + // 7. The fourth recursive call: base case hit + // 8-10. Switch back to i=1, i=2, i=3, respectively + private static final int EXPECTED_SELF_RECURSIVE_METHOD = 10; + + // Ensure that the expected signatures are printed the correct nr of times. + // The signatures here need to be changed if any of the test code is changed. + private static void analyze(List lines) { + System.out.println("Analyzing " + lines.size() + " lines"); + int testSameMethodCount = 0; + int testConstructorCount = 0; + int testSelfRecursiveCount = 0; + for (String line : lines) { + if (line.contains("static void TraceBytecodesSignatures.testSameMethod(jboolean)")) { + testSameMethodCount++; + } else if (line.contains("virtual void TraceBytecodesSignatures$TestConstructor.()")) { + testConstructorCount++; + } else if (line.contains("static void TraceBytecodesSignatures.testSelfRecursive(jint)")) { + testSelfRecursiveCount++; + } + } + if (testSameMethodCount != EXPECTED_SAME_METHOD) { + throw new RuntimeException("testSameMethod: " + + EXPECTED_SAME_METHOD + + " != " + + testSameMethodCount); + } + if (testConstructorCount != EXPECTED_CONSTRUCTOR) { + throw new RuntimeException("testConstructor: " + + EXPECTED_CONSTRUCTOR + + " != " + + testConstructorCount); + } + if (testSelfRecursiveCount != EXPECTED_SELF_RECURSIVE_METHOD) { + throw new RuntimeException("testSelfRecursive: " + + EXPECTED_SELF_RECURSIVE_METHOD + + " != " + + testSelfRecursiveCount); + } + } + + // Use a variable to do some arithmetic on to represent work. + // This work should not produce method invocations, hence integer arithmetic. + private static int globalState = 0; + + private static void testSameMethod(boolean other) { + globalState = 1; + if (other) { + testSameMethodHelper(); + } + globalState = 1; + } + + private static void testSameMethodHelper() { + globalState = 5; + } + + private static final class TestConstructor { + // Represents some kind of mutable state, not necessarily a object attribute. + private static String foo = "test"; + + public TestConstructor() { + this("bar"); + } + + public TestConstructor(String other) { + foo = other; + } + } + + private static void testSelfRecursive(int i) { + if (i == 0) { + return; + } + globalState += 2; + // Ensure to generate another method call within the recursive method. + // This will trigger the method switches more often. + testSelfRecursiveHelper(); + globalState -= 2; + testSelfRecursive(i - 1); + } + + private static void testSelfRecursiveHelper() { + globalState = -1; + } + + // CompileCommand is accepted even if the VM does not use JIT compilation. + private static String exclude(String methodName) { + return "-XX:CompileCommand=exclude," + klass() + "." + methodName; + } + + private static String excludeConstructor() { + return "-XX:CompileCommand=exclude," + klass() + "$TestConstructor."; + } + + private static String klass() { + return TraceBytecodesSignatures.class.getName(); + } +} diff --git a/test/hotspot/jtreg/serviceability/dcmd/compiler/CodeCacheTest.java b/test/hotspot/jtreg/serviceability/dcmd/compiler/CodeCacheTest.java index 157c1713ec2..ab459f31931 100644 --- a/test/hotspot/jtreg/serviceability/dcmd/compiler/CodeCacheTest.java +++ b/test/hotspot/jtreg/serviceability/dcmd/compiler/CodeCacheTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,7 +23,7 @@ /* * @test CodeCacheTest - * @bug 8054889 + * @bug 8054889 8307537 * @library /test/lib * @modules java.base/jdk.internal.misc * java.compiler @@ -57,26 +57,30 @@ public class CodeCacheTest { * * CodeCache: size=245760Kb used=1366Kb max_used=1935Kb free=244393Kb * bounds [0x00007ff4d89f2000, 0x00007ff4d8c62000, 0x00007ff4e79f2000] - * total_blobs=474, nmethods=87, adapters=293, full_count=0 + * blobs=474, nmethods=87, adapters=293, full_count=0 * Compilation: enabled, stopped_count=0, restarted_count=0 * * Expected output with code cache segmentation (number of segments may change): * - * CodeHeap 'non-profiled nmethods': size=118592Kb used=29Kb max_used=29Kb free=118562Kb - * bounds [0x00007f09f8622000, 0x00007f09f8892000, 0x00007f09ff9f2000] - * CodeHeap 'profiled nmethods': size=118588Kb used=80Kb max_used=80Kb free=118507Kb - * bounds [0x00007f09f09f2000, 0x00007f09f0c62000, 0x00007f09f7dc1000] - * CodeHeap 'non-nmethods': size=8580Kb used=1257Kb max_used=1833Kb free=7323Kb - * bounds [0x00007f09f7dc1000, 0x00007f09f8031000, 0x00007f09f8622000] - * CodeCache: size=245760Kb, used=1366Kb, max_used=1942Kb, free=244392Kb - * total_blobs=474, nmethods=87, adapters=293, full_count=0 + * CodeHeap 'non-profiled nmethods': size=118592Kb used=370Kb max_used=370Kb free=118221Kb + * bounds [0x00007f2093d3a000, 0x00007f2093faa000, 0x00007f209b10a000] + * blobs=397, nmethods=397, adapters=0, full_count=0 + * CodeHeap 'profiled nmethods': size=118592Kb used=2134Kb max_used=2134Kb free=116457Kb + * bounds [0x00007f208c109000, 0x00007f208c379000, 0x00007f20934d9000] + * blobs=1091, nmethods=1091, adapters=0, full_count=0 + * CodeHeap 'non-nmethods': size=8580Kb used=4461Kb max_used=4506Kb free=4118Kb + * bounds [0x00007f20934d9000, 0x00007f2093949000, 0x00007f2093d3a000] + * blobs=478, nmethods=0, adapters=387, full_count=0 + * CodeCache: size=245764Kb, used=6965Kb, max_used=7010Kb, free=238796Kb + * total blobs=1966, nmethods=1488, adapters=387, full_count=0 * Compilation: enabled, stopped_count=0, restarted_count=0 */ static Pattern line1 = Pattern.compile("(CodeCache|CodeHeap.*): size=(\\p{Digit}*)Kb used=(\\p{Digit}*)Kb max_used=(\\p{Digit}*)Kb free=(\\p{Digit}*)Kb"); static Pattern line2 = Pattern.compile(" bounds \\[0x(\\p{XDigit}*), 0x(\\p{XDigit}*), 0x(\\p{XDigit}*)\\]"); - static Pattern line3 = Pattern.compile(" total_blobs=(\\p{Digit}*), nmethods=(\\p{Digit}*), adapters=(\\p{Digit}*), full_count=(\\p{Digit}*)"); - static Pattern line4 = Pattern.compile("Compilation: (.*?), stopped_count=(\\p{Digit}*), restarted_count=(\\p{Digit}*)"); + static Pattern line3 = Pattern.compile(" blobs=(\\p{Digit}*), nmethods=(\\p{Digit}*), adapters=(\\p{Digit}*), full_count=(\\p{Digit}*)"); + static Pattern line4 = Pattern.compile(" total blobs=(\\p{Digit}*), nmethods=(\\p{Digit}*), adapters=(\\p{Digit}*), full_count=(\\p{Digit}*)"); + static Pattern line5 = Pattern.compile("Compilation: (.*?), stopped_count=(\\p{Digit}*), restarted_count=(\\p{Digit}*)"); private static boolean getFlagBool(String flag, String where) { Matcher m = Pattern.compile(flag + "\\s+:?= (true|false)").matcher(where); @@ -118,6 +122,9 @@ public class CodeCacheTest { String line; Matcher m; int matchedCount = 0; + int totalBlobs = 0; + int totalNmethods = 0; + int totalAdapters = 0; while (true) { // Validate first line line = lines.next(); @@ -151,6 +158,33 @@ public class CodeCacheTest { } else { Assert.fail("Regexp 2 failed to match line: " + line); } + + // Validate third line + line = lines.next(); + m = line3.matcher(line); + if (m.matches()) { + int blobs = Integer.parseInt(m.group(1)); + if (blobs < 0) { + Assert.fail("Failed parsing dcmd codecache output"); + } + totalBlobs += blobs; + int nmethods = Integer.parseInt(m.group(2)); + if (nmethods < 0) { + Assert.fail("Failed parsing dcmd codecache output"); + } + totalNmethods += nmethods; + int adapters = Integer.parseInt(m.group(3)); + if (adapters < 0) { + Assert.fail("Failed parsing dcmd codecache output"); + } + totalAdapters += adapters; + if (blobs < (nmethods + adapters)) { + Assert.fail("Failed parsing dcmd codecache output"); + } + } else { + Assert.fail("Regexp 3 failed to match line: " + line); + } + ++matchedCount; } // Because of CodeCacheExtensions, we could match more than expected @@ -161,32 +195,33 @@ public class CodeCacheTest { if (segmentsCount != 1) { // Skip this line CodeCache: size=245760Kb, used=5698Kb, max_used=5735Kb, free=240059Kb line = lines.next(); - } - // Validate third line - m = line3.matcher(line); - if (m.matches()) { - int blobs = Integer.parseInt(m.group(1)); - if (blobs <= 0) { - Assert.fail("Failed parsing dcmd codecache output"); + + // Validate fourth line + m = line4.matcher(line); + if (m.matches()) { + int blobs = Integer.parseInt(m.group(1)); + if (blobs != totalBlobs) { + Assert.fail("Failed parsing dcmd codecache output"); + } + int nmethods = Integer.parseInt(m.group(2)); + if (nmethods != totalNmethods) { + Assert.fail("Failed parsing dcmd codecache output"); + } + int adapters = Integer.parseInt(m.group(3)); + if (adapters != totalAdapters) { + Assert.fail("Failed parsing dcmd codecache output"); + } + if (blobs < (nmethods + adapters)) { + Assert.fail("Failed parsing dcmd codecache output"); + } + } else { + Assert.fail("Regexp 4 failed to match line: " + line); } - int nmethods = Integer.parseInt(m.group(2)); - if (nmethods < 0) { - Assert.fail("Failed parsing dcmd codecache output"); - } - int adapters = Integer.parseInt(m.group(3)); - if (adapters <= 0) { - Assert.fail("Failed parsing dcmd codecache output"); - } - if (blobs < (nmethods + adapters)) { - Assert.fail("Failed parsing dcmd codecache output"); - } - } else { - Assert.fail("Regexp 3 failed to match line: " + line); + line = lines.next(); } - // Validate fourth line - line = lines.next(); - m = line4.matcher(line); + // Validate last line + m = line5.matcher(line); if (m.matches()) { if (!m.group(1).contains("enabled") && !m.group(1).contains("disabled")) { Assert.fail("Failed parsing dcmd codecache output"); @@ -200,7 +235,7 @@ public class CodeCacheTest { Assert.fail("Failed parsing dcmd codecache output"); } } else { - Assert.fail("Regexp 4 failed to match line: " + line); + Assert.fail("Regexp 5 failed to match line: " + line); } } diff --git a/test/hotspot/jtreg/vmTestbase/vm/compiler/CodeCacheInfo/Test.java b/test/hotspot/jtreg/vmTestbase/vm/compiler/CodeCacheInfo/Test.java index b9218480788..7ca852f2726 100644 --- a/test/hotspot/jtreg/vmTestbase/vm/compiler/CodeCacheInfo/Test.java +++ b/test/hotspot/jtreg/vmTestbase/vm/compiler/CodeCacheInfo/Test.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -56,15 +56,16 @@ public class Test { static { String p1 = " size=\\d+Kb used=\\d+Kb max_used=\\d+Kb free=\\d+Kb\\n"; String p2 = " bounds \\[0x[0-9a-f]+, 0x[0-9a-f]+, 0x[0-9a-f]+\\]\\n"; - String p3 = "CodeCache:.*\\n"; - String p4 = " total_blobs=\\d+, nmethods=\\d+, adapters=\\d+, full_count=\\d+\\n"; - String p5 = "Compilation: enabled.*\\n"; + String p3 = " blobs=\\d+, nmethods=\\d+, adapters=\\d+, full_count=\\d+\\n"; + String p4 = "CodeCache:.*\\n"; + String p5 = " total blobs=\\d+, nmethods=\\d+, adapters=\\d+, full_count=\\d+\\n"; + String p6 = "Compilation: enabled.*\\n"; - String segPrefix = "^(CodeHeap '[^']+':" + p1 + p2 + ")+"; - String nosegPrefix = "^CodeCache:" + p1 + p2; + String segPrefix = "^(CodeHeap '[^']+':" + p1 + p2 + p3 + ")+"; + String nosegPrefix = "^CodeCache:" + p1 + p2 + p3; - SEG_REGEXP = segPrefix + p3 + p4 + p5; - NOSEG_REGEXP = nosegPrefix + p4 + p5; + SEG_REGEXP = segPrefix + p4 + p5 + p6; + NOSEG_REGEXP = nosegPrefix + p6; } public static void main(String[] args) throws Exception { diff --git a/test/jaxp/ProblemList.txt b/test/jaxp/ProblemList.txt index 8f7380a43f8..a30f1ad30ed 100644 --- a/test/jaxp/ProblemList.txt +++ b/test/jaxp/ProblemList.txt @@ -28,10 +28,14 @@ # Preview project specific failures go here at the end of the file. # # These are NOT failures that occur with the '--enable-preview' option -# specified; those go in the appropriate ProblemList-enable-preview.txt file. +# specified in the task definition; those go in the appropriate +# ProblemList-enable-preview.txt file. +# # These are failures that occur WITHOUT the '--enable-preview' option -# specified AND occur because of some issue with preview project code, -# in either implementation or test code. +# specified in the task definition OR the '--enable-preview' option +# MAY BE specified in the test itself. In either case, the failure +# occurs because of some issue with preview project code, in either +# implementation or test code. ############################################################################# diff --git a/test/jdk/ProblemList-AotJdk.txt b/test/jdk/ProblemList-AotJdk.txt index c98bf63b25f..1f99d0f6859 100644 --- a/test/jdk/ProblemList-AotJdk.txt +++ b/test/jdk/ProblemList-AotJdk.txt @@ -49,10 +49,14 @@ java/util/Locale/UseOldISOCodesTest.java 0000000 generic-a # Preview project specific failures go here at the end of the file. # # These are NOT failures that occur with the '--enable-preview' option -# specified; those go in the appropriate ProblemList-enable-preview.txt file. +# specified in the task definition; those go in the appropriate +# ProblemList-enable-preview.txt file. +# # These are failures that occur WITHOUT the '--enable-preview' option -# specified AND occur because of some issue with preview project code, -# in either implementation or test code. +# specified in the task definition OR the '--enable-preview' option +# MAY BE specified in the test itself. In either case, the failure +# occurs because of some issue with preview project code, in either +# implementation or test code. ############################################################################# diff --git a/test/jdk/ProblemList-StaticJdk.txt b/test/jdk/ProblemList-StaticJdk.txt index 700099656e8..fc3f2226100 100644 --- a/test/jdk/ProblemList-StaticJdk.txt +++ b/test/jdk/ProblemList-StaticJdk.txt @@ -30,10 +30,14 @@ # Preview project specific failures go here at the end of the file. # # These are NOT failures that occur with the '--enable-preview' option -# specified; those go in the appropriate ProblemList-enable-preview.txt file. +# specified in the task definition; those go in the appropriate +# ProblemList-enable-preview.txt file. +# # These are failures that occur WITHOUT the '--enable-preview' option -# specified AND occur because of some issue with preview project code, -# in either implementation or test code. +# specified in the task definition OR the '--enable-preview' option +# MAY BE specified in the test itself. In either case, the failure +# occurs because of some issue with preview project code, in either +# implementation or test code. ############################################################################# diff --git a/test/jdk/ProblemList-Virtual.txt b/test/jdk/ProblemList-Virtual.txt index 52f187086de..8dd65f257f8 100644 --- a/test/jdk/ProblemList-Virtual.txt +++ b/test/jdk/ProblemList-Virtual.txt @@ -39,10 +39,14 @@ java/lang/ScopedValue/StressStackOverflow.java#TieredStopAtLevel1 8309646 generi # Preview project specific failures go here at the end of the file. # # These are NOT failures that occur with the '--enable-preview' option -# specified; those go in the appropriate ProblemList-enable-preview.txt file. +# specified in the task definition; those go in the appropriate +# ProblemList-enable-preview.txt file. +# # These are failures that occur WITHOUT the '--enable-preview' option -# specified AND occur because of some issue with preview project code, -# in either implementation or test code. +# specified in the task definition OR the '--enable-preview' option +# MAY BE specified in the test itself. In either case, the failure +# occurs because of some issue with preview project code, in either +# implementation or test code. ############################################################################# diff --git a/test/jdk/ProblemList-Xcomp.txt b/test/jdk/ProblemList-Xcomp.txt index 44bad411f26..5b104f08b16 100644 --- a/test/jdk/ProblemList-Xcomp.txt +++ b/test/jdk/ProblemList-Xcomp.txt @@ -35,10 +35,14 @@ java/lang/reflect/callerCache/ReflectionCallerCacheTest.java 8332028 generic- # Preview project specific failures go here at the end of the file. # # These are NOT failures that occur with the '--enable-preview' option -# specified; those go in the appropriate ProblemList-enable-preview.txt file. +# specified in the task definition; those go in the appropriate +# ProblemList-enable-preview.txt file. +# # These are failures that occur WITHOUT the '--enable-preview' option -# specified AND occur because of some issue with preview project code, -# in either implementation or test code. +# specified in the task definition OR the '--enable-preview' option +# MAY BE specified in the test itself. In either case, the failure +# occurs because of some issue with preview project code, in either +# implementation or test code. ############################################################################# diff --git a/test/jdk/ProblemList-enable-preview.txt b/test/jdk/ProblemList-enable-preview.txt index 1a831a0dde3..b28670c9839 100644 --- a/test/jdk/ProblemList-enable-preview.txt +++ b/test/jdk/ProblemList-enable-preview.txt @@ -23,10 +23,13 @@ ############################################################################# # -# List of quarantined tests for testing with --enable-preview +# List of quarantined tests for testing with the '--enable-preview' option +# where the option IS specified in the task definition and NOT in the test. # -# These are failures that ONLY occur with the '--enable-preview' option -# specified. There are separate sub-sections for each preview project. +# If the '--enable-preview' option is NOT specified in the task definition, +# and the option IS specified in the test, then an entry here WILL NOT work. +# +# There are separate sub-sections for each preview project. # ############################################################################# diff --git a/test/jdk/ProblemList-jvmti-stress-agent.txt b/test/jdk/ProblemList-jvmti-stress-agent.txt index e9019b6014e..e96ad2d9b99 100644 --- a/test/jdk/ProblemList-jvmti-stress-agent.txt +++ b/test/jdk/ProblemList-jvmti-stress-agent.txt @@ -35,10 +35,14 @@ java/lang/ref/ReachabilityFenceTest.java 0000 # Preview project specific failures go here at the end of the file. # # These are NOT failures that occur with the '--enable-preview' option -# specified; those go in the appropriate ProblemList-enable-preview.txt file. +# specified in the task definition; those go in the appropriate +# ProblemList-enable-preview.txt file. +# # These are failures that occur WITHOUT the '--enable-preview' option -# specified AND occur because of some issue with preview project code, -# in either implementation or test code. +# specified in the task definition OR the '--enable-preview' option +# MAY BE specified in the test itself. In either case, the failure +# occurs because of some issue with preview project code, in either +# implementation or test code. ############################################################################# diff --git a/test/jdk/ProblemList-shenandoah.txt b/test/jdk/ProblemList-shenandoah.txt index 522b77cb502..533ad5d613c 100644 --- a/test/jdk/ProblemList-shenandoah.txt +++ b/test/jdk/ProblemList-shenandoah.txt @@ -63,10 +63,14 @@ jdk/jfr/startupargs/TestOldObjectQueueSize.java 8342951 generic-all # Preview project specific failures go here at the end of the file. # # These are NOT failures that occur with the '--enable-preview' option -# specified; those go in the appropriate ProblemList-enable-preview.txt file. +# specified in the task definition; those go in the appropriate +# ProblemList-enable-preview.txt file. +# # These are failures that occur WITHOUT the '--enable-preview' option -# specified AND occur because of some issue with preview project code, -# in either implementation or test code. +# specified in the task definition OR the '--enable-preview' option +# MAY BE specified in the test itself. In either case, the failure +# occurs because of some issue with preview project code, in either +# implementation or test code. ############################################################################# diff --git a/test/jdk/ProblemList-zgc.txt b/test/jdk/ProblemList-zgc.txt index a669f3e3abf..ae3d8c33e96 100644 --- a/test/jdk/ProblemList-zgc.txt +++ b/test/jdk/ProblemList-zgc.txt @@ -34,10 +34,14 @@ com/sun/jdi/ThreadMemoryLeakTest.java 8307402 generic-all # Preview project specific failures go here at the end of the file. # # These are NOT failures that occur with the '--enable-preview' option -# specified; those go in the appropriate ProblemList-enable-preview.txt file. +# specified in the task definition; those go in the appropriate +# ProblemList-enable-preview.txt file. +# # These are failures that occur WITHOUT the '--enable-preview' option -# specified AND occur because of some issue with preview project code, -# in either implementation or test code. +# specified in the task definition OR the '--enable-preview' option +# MAY BE specified in the test itself. In either case, the failure +# occurs because of some issue with preview project code, in either +# implementation or test code. ############################################################################# diff --git a/test/jdk/ProblemList.txt b/test/jdk/ProblemList.txt index f1bd91d86aa..b14e882665a 100644 --- a/test/jdk/ProblemList.txt +++ b/test/jdk/ProblemList.txt @@ -151,16 +151,11 @@ java/awt/grab/EmbeddedFrameTest1/EmbeddedFrameTest1.java 7080150 macosx-all java/awt/event/InputEvent/EventWhenTest/EventWhenTest.java 8168646 generic-all java/awt/List/KeyEventsTest/KeyEventsTest.java 8201307 linux-all java/awt/List/NoEvents/ProgrammaticChange.java 8201307 linux-all +java/awt/List/ListSelection/SelectInvalidTest.java 8369455 linux-all java/awt/Paint/ListRepaint.java 8201307 linux-all -java/awt/Mixing/AWT_Mixing/OpaqueOverlapping.java 8370584 windows-x64 java/awt/Mixing/AWT_Mixing/OpaqueOverlappingChoice.java 8048171 generic-all -java/awt/Mixing/AWT_Mixing/JMenuBarOverlapping.java 8159451 linux-all,windows-all,macosx-all -java/awt/Mixing/AWT_Mixing/JSplitPaneOverlapping.java 6986109 generic-all java/awt/Mixing/AWT_Mixing/JInternalFrameMoveOverlapping.java 6986109 windows-all -java/awt/Mixing/AWT_Mixing/MixingPanelsResizing.java 8049405 generic-all -java/awt/Mixing/AWT_Mixing/JComboBoxOverlapping.java 8049405 macosx-all -java/awt/Mixing/AWT_Mixing/JPopupMenuOverlapping.java 8049405 macosx-all -java/awt/Mixing/AWT_Mixing/JTableInGlassPaneOverlapping.java 8357360 windows-all,linux-all +java/awt/Mixing/AWT_Mixing/JTableInGlassPaneOverlapping.java 8357360 linux-all java/awt/Mixing/NonOpaqueInternalFrame.java 7124549 macosx-all java/awt/Focus/ActualFocusedWindowTest/ActualFocusedWindowRetaining.java 6829264 generic-all java/awt/datatransfer/DragImage/MultiResolutionDragImageTest.java 8080982 generic-all @@ -222,7 +217,6 @@ sun/awt/datatransfer/SuplementaryCharactersTransferTest.java 8011371 generic-all sun/awt/shell/ShellFolderMemoryLeak.java 8197794 windows-all sun/java2d/DirectX/OverriddenInsetsTest/OverriddenInsetsTest.java 8196102 generic-all sun/java2d/DirectX/RenderingToCachedGraphicsTest/RenderingToCachedGraphicsTest.java 8196180 windows-all,macosx-all -sun/java2d/OpenGL/MultiWindowFillTest.java 8378506 macosx-all sun/java2d/OpenGL/OpaqueDest.java#id1 8367574 macosx-all sun/java2d/OpenGL/ScaleParamsOOB.java#id0 8377908 linux-all sun/java2d/SunGraphics2D/EmptyClipRenderingTest.java 8144029 macosx-all,linux-all @@ -349,32 +343,29 @@ java/awt/Modal/ModalExclusionTests/ToolkitExcludeFramePageSetupTest.java 8196431 java/awt/Modal/ModalExclusionTests/ToolkitExcludeFramePrintSetupTest.java 8196431 linux-all,macosx-all java/awt/Modal/ModalFocusTransferTests/FocusTransferWDFAppModal2Test.java 8058813 windows-all java/awt/Modal/ModalFocusTransferTests/FocusTransferWDFModeless2Test.java 8196191 windows-all -java/awt/Modal/ModalFocusTransferTests/FocusTransferDWFDocModalTest.java 8196432 linux-all,macosx-all -java/awt/Modal/ModalFocusTransferTests/FocusTransferDWFModelessTest.java 8196432 linux-all,macosx-all -java/awt/Modal/ModalFocusTransferTests/FocusTransferDWFNonModalTest.java 8196432 linux-all,macosx-all + +java/awt/Modal/ModalFocusTransferTests/FocusTransferDWFDocModalTest.java 8196432 macosx-all +java/awt/Modal/ModalFocusTransferTests/FocusTransferDWFModelessTest.java 8196432 macosx-all +java/awt/Modal/ModalFocusTransferTests/FocusTransferDWFNonModalTest.java 8196432 macosx-all java/awt/Modal/ModalFocusTransferTests/FocusTransferDialogsModelessTest.java 8196432 linux-all java/awt/Modal/ModalFocusTransferTests/FocusTransferDialogsNonModalTest.java 8196432 linux-all -java/awt/Modal/ModalFocusTransferTests/FocusTransferFDWDocModalTest.java 8196432 linux-all -java/awt/Modal/ModalFocusTransferTests/FocusTransferFDWModelessTest.java 8196432 linux-all -java/awt/Modal/ModalFocusTransferTests/FocusTransferFDWNonModalTest.java 8196432 linux-all -java/awt/Modal/ModalFocusTransferTests/FocusTransferFWDAppModal1Test.java 8196432 linux-all,macosx-all -java/awt/Modal/ModalFocusTransferTests/FocusTransferFWDAppModal2Test.java 8196432 linux-all,macosx-all -java/awt/Modal/ModalFocusTransferTests/FocusTransferFWDAppModal3Test.java 8196432 linux-all,macosx-all -java/awt/Modal/ModalFocusTransferTests/FocusTransferFWDAppModal4Test.java 8196432 linux-all,macosx-all -java/awt/Modal/ModalFocusTransferTests/FocusTransferFWDDocModal1Test.java 8196432 linux-all,macosx-all -java/awt/Modal/ModalFocusTransferTests/FocusTransferFWDDocModal2Test.java 8196432 linux-all,macosx-all -java/awt/Modal/ModalFocusTransferTests/FocusTransferFWDDocModal3Test.java 8196432 linux-all,macosx-all -java/awt/Modal/ModalFocusTransferTests/FocusTransferFWDDocModal4Test.java 8196432 linux-all,macosx-all -java/awt/Modal/ModalFocusTransferTests/FocusTransferFWDModeless1Test.java 8196432 linux-all,macosx-all -java/awt/Modal/ModalFocusTransferTests/FocusTransferFWDModeless2Test.java 8196432 linux-all,macosx-all -java/awt/Modal/ModalFocusTransferTests/FocusTransferFWDModeless3Test.java 8196432 linux-all,macosx-all -java/awt/Modal/ModalFocusTransferTests/FocusTransferFWDModeless4Test.java 8196432 linux-all,macosx-all -java/awt/Modal/ModalFocusTransferTests/FocusTransferFWDNonModal1Test.java 8196432 linux-all,macosx-all -java/awt/Modal/ModalFocusTransferTests/FocusTransferFWDNonModal2Test.java 8196432 linux-all,macosx-all -java/awt/Modal/ModalFocusTransferTests/FocusTransferFWDNonModal3Test.java 8196432 linux-all,macosx-all -java/awt/Modal/ModalFocusTransferTests/FocusTransferFWDNonModal4Test.java 8196432 linux-all,macosx-all -java/awt/Modal/ModalFocusTransferTests/FocusTransferWDFDocModal2Test.java 8196432 linux-all -java/awt/Modal/ModalFocusTransferTests/FocusTransferWDFNonModal2Test.java 8196432 linux-all +java/awt/Modal/ModalFocusTransferTests/FocusTransferFWDAppModal1Test.java 8196432 macosx-all +java/awt/Modal/ModalFocusTransferTests/FocusTransferFWDAppModal2Test.java 8196432 macosx-all +java/awt/Modal/ModalFocusTransferTests/FocusTransferFWDAppModal3Test.java 8196432 macosx-all +java/awt/Modal/ModalFocusTransferTests/FocusTransferFWDAppModal4Test.java 8196432 macosx-all +java/awt/Modal/ModalFocusTransferTests/FocusTransferFWDDocModal1Test.java 8196432 macosx-all +java/awt/Modal/ModalFocusTransferTests/FocusTransferFWDDocModal2Test.java 8196432 macosx-all +java/awt/Modal/ModalFocusTransferTests/FocusTransferFWDDocModal3Test.java 8196432 macosx-all +java/awt/Modal/ModalFocusTransferTests/FocusTransferFWDDocModal4Test.java 8196432 macosx-all +java/awt/Modal/ModalFocusTransferTests/FocusTransferFWDModeless1Test.java 8196432 macosx-all +java/awt/Modal/ModalFocusTransferTests/FocusTransferFWDModeless2Test.java 8196432 macosx-all +java/awt/Modal/ModalFocusTransferTests/FocusTransferFWDModeless3Test.java 8196432 macosx-all +java/awt/Modal/ModalFocusTransferTests/FocusTransferFWDModeless4Test.java 8196432 macosx-all +java/awt/Modal/ModalFocusTransferTests/FocusTransferFWDNonModal1Test.java 8196432 macosx-all +java/awt/Modal/ModalFocusTransferTests/FocusTransferFWDNonModal2Test.java 8196432 macosx-all +java/awt/Modal/ModalFocusTransferTests/FocusTransferFWDNonModal3Test.java 8196432 macosx-all +java/awt/Modal/ModalFocusTransferTests/FocusTransferFWDNonModal4Test.java 8196432 macosx-all + java/awt/Modal/MultipleDialogs/MultipleDialogs1Test.java 8198665 macosx-all java/awt/Modal/MultipleDialogs/MultipleDialogs2Test.java 8198665 macosx-all java/awt/Modal/MultipleDialogs/MultipleDialogs3Test.java 8198665 macosx-all @@ -386,36 +377,32 @@ java/awt/Mouse/EnterExitEvents/FullscreenEnterEventTest.java 8051455 macosx-all java/awt/Mouse/MouseModifiersUnitTest/MouseModifiersUnitTest_Standard.java 7124407,8302787 macosx-all,windows-all java/awt/Mouse/RemovedComponentMouseListener/RemovedComponentMouseListener.java 8157170 macosx-all java/awt/Modal/ToFront/DialogToFrontNonModalTest.java 8221899 linux-all -java/awt/Modal/ToBack/ToBackAppModal1Test.java 8196441 linux-all,macosx-all -java/awt/Modal/ToBack/ToBackAppModal2Test.java 8196441 linux-all,macosx-all -java/awt/Modal/ToBack/ToBackAppModal3Test.java 8196441 linux-all,macosx-all -java/awt/Modal/ToBack/ToBackAppModal4Test.java 8196441 linux-all,macosx-all -java/awt/Modal/ToBack/ToBackAppModal5Test.java 8196441 macosx-all +java/awt/Modal/ToBack/ToBackAppModal1Test.java 8196441 linux-all +java/awt/Modal/ToBack/ToBackAppModal2Test.java 8196441 linux-all +java/awt/Modal/ToBack/ToBackAppModal3Test.java 8196441 linux-all +java/awt/Modal/ToBack/ToBackAppModal4Test.java 8196441 linux-all java/awt/Modal/ToBack/ToBackAppModal6Test.java 8196441 linux-all -java/awt/Modal/ToBack/ToBackModal1Test.java 8196441 linux-all,macosx-all -java/awt/Modal/ToBack/ToBackModal2Test.java 8196441 linux-all,macosx-all -java/awt/Modal/ToBack/ToBackModal3Test.java 8196441 linux-all,macosx-all -java/awt/Modal/ToBack/ToBackModal4Test.java 8196441 linux-all,macosx-all -java/awt/Modal/ToBack/ToBackTKModal1Test.java 8196441 linux-all,macosx-all -java/awt/Modal/ToBack/ToBackTKModal2Test.java 8196441 linux-all,macosx-all -java/awt/Modal/ToBack/ToBackTKModal3Test.java 8196441 linux-all,macosx-all -java/awt/Modal/ToBack/ToBackTKModal4Test.java 8196441 linux-all,macosx-all -java/awt/Modal/ToBack/ToBackTKModal5Test.java 8196441 macosx-all -java/awt/Modal/ToBack/ToBackDocModal1Test.java 8196441 linux-all,macosx-all -java/awt/Modal/ToBack/ToBackDocModal2Test.java 8196441 linux-all,macosx-all -java/awt/Modal/ToBack/ToBackDocModal3Test.java 8196441 linux-all,macosx-all -java/awt/Modal/ToBack/ToBackDocModal4Test.java 8196441 linux-all,macosx-all -java/awt/Modal/ToBack/ToBackDocModal5Test.java 8196441 linux-all,macosx-all -java/awt/Modal/ToBack/ToBackModeless1Test.java 8196441 macosx-all,linux-all -java/awt/Modal/ToBack/ToBackModeless2Test.java 8196441 macosx-all,linux-all -java/awt/Modal/ToBack/ToBackModeless3Test.java 8196441 macosx-all,linux-all -java/awt/Modal/ToBack/ToBackModeless4Test.java 8196441 macosx-all,linux-all -java/awt/Modal/ToBack/ToBackModeless5Test.java 8196441 macosx-all -java/awt/Modal/ToBack/ToBackNonModal1Test.java 8196441 macosx-all,linux-all -java/awt/Modal/ToBack/ToBackNonModal2Test.java 8196441 macosx-all,linux-all -java/awt/Modal/ToBack/ToBackNonModal3Test.java 8196441 macosx-all,linux-all -java/awt/Modal/ToBack/ToBackNonModal4Test.java 8196441 macosx-all,linux-all -java/awt/Modal/ToBack/ToBackNonModal5Test.java 8196441 macosx-all +java/awt/Modal/ToBack/ToBackModal1Test.java 8196441 linux-all +java/awt/Modal/ToBack/ToBackModal2Test.java 8196441 linux-all +java/awt/Modal/ToBack/ToBackModal3Test.java 8196441 linux-all +java/awt/Modal/ToBack/ToBackModal4Test.java 8196441 linux-all +java/awt/Modal/ToBack/ToBackTKModal1Test.java 8196441 linux-all +java/awt/Modal/ToBack/ToBackTKModal2Test.java 8196441 linux-all +java/awt/Modal/ToBack/ToBackTKModal3Test.java 8196441 linux-all +java/awt/Modal/ToBack/ToBackTKModal4Test.java 8196441 linux-all +java/awt/Modal/ToBack/ToBackDocModal1Test.java 8196441 linux-all +java/awt/Modal/ToBack/ToBackDocModal2Test.java 8196441 linux-all +java/awt/Modal/ToBack/ToBackDocModal3Test.java 8196441 linux-all +java/awt/Modal/ToBack/ToBackDocModal4Test.java 8196441 linux-all +java/awt/Modal/ToBack/ToBackDocModal5Test.java 8196441 linux-all +java/awt/Modal/ToBack/ToBackModeless1Test.java 8196441 linux-all +java/awt/Modal/ToBack/ToBackModeless2Test.java 8196441 linux-all +java/awt/Modal/ToBack/ToBackModeless3Test.java 8196441 linux-all +java/awt/Modal/ToBack/ToBackModeless4Test.java 8196441 linux-all +java/awt/Modal/ToBack/ToBackNonModal1Test.java 8196441 linux-all +java/awt/Modal/ToBack/ToBackNonModal2Test.java 8196441 linux-all +java/awt/Modal/ToBack/ToBackNonModal3Test.java 8196441 linux-all +java/awt/Modal/ToBack/ToBackNonModal4Test.java 8196441 linux-all javax/print/PrintSEUmlauts/PrintSEUmlauts.java 8135174 generic-all java/awt/font/Rotate/RotatedTextTest.java 8219641 linux-all java/awt/font/TextLayout/LigatureCaretTest.java 8266312 generic-all @@ -735,6 +722,7 @@ jdk/jfr/event/compiler/TestCodeSweeper.java 8338127 generic- jdk/jfr/event/oldobject/TestShenandoah.java 8342951 generic-all jdk/jfr/event/runtime/TestResidentSetSizeEvent.java 8309846 aix-ppc64 jdk/jfr/jvm/TestWaste.java 8371630 generic-all +jdk/jfr/event/oldobject/TestZ.java 8375615 generic-all ############################################################################ @@ -748,8 +736,6 @@ jdk/jfr/jvm/TestWaste.java 8371630 generic- # jdk_foreign -java/foreign/TestBufferStackStress.java 8350455 macosx-all - ############################################################################ # Client manual tests @@ -804,10 +790,14 @@ tools/sincechecker/modules/jdk.management.jfr/JdkManagementJfrCheckSince.java 83 # Preview project specific failures go here at the end of the file. # # These are NOT failures that occur with the '--enable-preview' option -# specified; those go in the appropriate ProblemList-enable-preview.txt file. +# specified in the task definition; those go in the appropriate +# ProblemList-enable-preview.txt file. +# # These are failures that occur WITHOUT the '--enable-preview' option -# specified AND occur because of some issue with preview project code, -# in either implementation or test code. +# specified in the task definition OR the '--enable-preview' option +# MAY BE specified in the test itself. In either case, the failure +# occurs because of some issue with preview project code, in either +# implementation or test code. ############################################################################# diff --git a/test/jdk/com/sun/jdi/ClassesByName2Test.java b/test/jdk/com/sun/jdi/ClassesByName2Test.java index b8f517d0448..d1f45e254e6 100644 --- a/test/jdk/com/sun/jdi/ClassesByName2Test.java +++ b/test/jdk/com/sun/jdi/ClassesByName2Test.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2001, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -137,6 +137,10 @@ public class ClassesByName2Test extends TestScaffold { } } + private static boolean isHiddenClass(String className) { + return className.contains("/"); + } + protected void runTests() throws Exception { BreakpointEvent bpe = startToMain("ClassesByName2Targ"); @@ -160,6 +164,13 @@ public class ClassesByName2Test extends TestScaffold { for (Iterator it = all.iterator(); it.hasNext(); ) { ReferenceType cls = (ReferenceType)it.next(); String name = cls.name(); + + if (isHiddenClass(name)) { + // Hidden classes may have been unloaded by the time classesByName + // is called so we skip those + continue; + } + List found = vm().classesByName(name); if (found.contains(cls)) { //System.out.println("Found class: " + name); diff --git a/test/jdk/com/sun/jndi/ldap/LdapStartTlsTest.java b/test/jdk/com/sun/jndi/ldap/LdapStartTlsTest.java new file mode 100644 index 00000000000..17c7d34fa47 --- /dev/null +++ b/test/jdk/com/sun/jndi/ldap/LdapStartTlsTest.java @@ -0,0 +1,423 @@ +/* + * Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.lang.reflect.Field; +import java.net.InetAddress; +import java.net.InetSocketAddress; +import java.net.ServerSocket; +import java.net.Socket; +import java.security.KeyStore; +import java.util.Arrays; +import java.util.Hashtable; +import java.util.List; + +import javax.naming.Context; +import javax.naming.ldap.InitialLdapContext; +import javax.naming.ldap.LdapContext; +import javax.naming.ldap.StartTlsRequest; +import javax.naming.ldap.StartTlsResponse; +import javax.net.ssl.HostnameVerifier; +import javax.net.ssl.SSLContext; +import javax.net.ssl.SSLPeerUnverifiedException; +import javax.net.ssl.SSLSession; +import javax.net.ssl.SSLSocket; +import javax.net.ssl.SSLSocketFactory; + +import com.sun.jndi.ldap.BerEncoder; +import com.sun.jndi.ldap.Connection; +import jdk.test.lib.net.URIBuilder; +import jdk.test.lib.security.CertUtils; +import jdk.test.lib.security.KeyEntry; +import jdk.test.lib.security.KeyStoreUtils; +import jdk.test.lib.security.SSLContextBuilder; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertSame; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; + +/* + * @test + * @bug 8261289 + * @summary Verify the behaviour of LDAPv3 Extended Response for StartTLS + * @modules java.naming/com.sun.jndi.ldap + * java.naming/com.sun.jndi.ldap.ext:+open + * @library /test/lib lib/ + * @build jdk.test.lib.net.URIBuilder + * jdk.test.lib.security.SSLContextBuilder + * jdk.test.lib.security.KeyStoreUtils + * BaseLdapServer LdapMessage + * @run junit ${test.main.class} + */ +class LdapStartTlsTest { + + private static final byte BER_TYPE_LDAP_SEQUENCE = 0x30; + private static final byte BER_TYPE_EXTENDED_RESPONSE = 0x78; + private static final byte BER_TYPE_ENUM = 0x0a; + private static final byte BER_TYPE_LDAP_SEARCH_RESULT_DONE_OP = 0x65; + + static List failedNegotiations() throws Exception { + // a SSLContext which we expect to cause the TLS handshake to fail when + // handshaking with a loopback address + final SSLContext localhostOnlySSLCtx = onlyLocalHostSSLCtx(); + + return List.of( + Arguments.of(new Server(localhostOnlySSLCtx), null), + Arguments.of(new Server(localhostOnlySSLCtx), new SimpleHostnameVerifier(false)) + ); + } + + static List successfulNegotiations() throws Exception { + // a SSLContext constructed out of a keystore which has relevant + // subject or subject alternate name and doesn't require a custom + // hostname verifier to allow for TLS verification to succeed + final String keyStoreFile = System.getProperty("test.src") + File.separator + "ksWithSAN"; + final String keyStorePass = "welcome1"; + final SSLContext sslContext = sslCtxFromKeyStoreFile(keyStoreFile, keyStorePass); + + // a different SSLContext which requires a custom hostname verifier to pass TLS verification + final SSLContext localhostOnlySSLCtx = onlyLocalHostSSLCtx(); + + return List.of( + Arguments.of(new Server(sslContext), null), + Arguments.of(new Server(localhostOnlySSLCtx), new SimpleHostnameVerifier(true)) + ); + } + + private static SSLContext onlyLocalHostSSLCtx() throws Exception { + // a cert which is issued to "localhost" (and without any subject alternative name + // for loopback IP address), which we expect the test to reject during TLS handshake + final String cert = CertUtils.ECDSA_CERT; + final KeyEntry ke = new KeyEntry("EC", CertUtils.ECDSA_KEY, new String[]{cert}); + return SSLContextBuilder.builder() + .keyStore(KeyStoreUtils.createKeyStore(new KeyEntry[]{ke})) + .trustStore(KeyStoreUtils.createTrustStore(new String[]{cert})) + .build(); + } + + private static SSLContext sslCtxFromKeyStoreFile(final String keyStoreFile, + final String keyStorePass) throws Exception { + final KeyStore keyStore = KeyStoreUtils.loadKeyStore(keyStoreFile, keyStorePass); + return SSLContextBuilder.builder() + .keyStore(keyStore) + .trustStore(keyStore) + .kmfPassphrase(keyStorePass) + .build(); + } + + @ParameterizedTest + @MethodSource(value = "failedNegotiations") + void testFailedNegotiation(final Server server, final SimpleHostnameVerifier verifier) + throws Exception { + + try (server) { + server.start(); + System.err.println("server started at " + server.getAddress()); + + final Hashtable envProps = createEnvProps(server); + final LdapContext ctx = new InitialLdapContext(envProps, null); + + StartTlsResponse startTlsResp = null; + try { + startTlsResp = (StartTlsResponse) ctx.extendedOperation(new StartTlsRequest()); + assertNotNull(startTlsResp, "StartTlsResponse is null"); + if (verifier != null) { + startTlsResp.setHostnameVerifier(verifier); + } + + final Connection ldapConn = getConnection(startTlsResp); + assertNotNull(ldapConn, "LDAP connection is null in " + startTlsResp); + // capture the input/output stream on the LDAP connection + final LdapConnStreams before = getStreams(ldapConn); + + // initiate the StartTLS negotiation/handshake + final StartTlsResponse tlsRsp = startTlsResp; + final SSLPeerUnverifiedException spue = assertThrows( + SSLPeerUnverifiedException.class, + () -> tlsRsp.negotiate(server.sslContext.getSocketFactory())); + System.err.println("got expected exception: " + spue); + + if (verifier != null) { + // assert that the custom hostname verifier was invoked + assertTrue(verifier.invoked, "custom HostnameVerifier was not invoked"); + } + // verify that after the failed StartTLS negotitation, the LDAP connection + // streams are the ones that were prior to the negotiation + final LdapConnStreams after = getStreams(ldapConn); + assertSame(before.in, after.in, + "unexpected InputStream on LDAP connection after a failed StartTLS negotiation"); + assertSame(before.out, after.out, + "unexpected OutputStream on LDAP connection after a failed StartTLS negotiation"); + } finally { + if (startTlsResp != null) { + startTlsResp.close(); + } + ctx.close(); + } + } + } + + @ParameterizedTest + @MethodSource(value = "successfulNegotiations") + void testSuccessfulNegotiation(final Server server, final SimpleHostnameVerifier verifier) + throws Exception { + try (server) { + server.start(); + System.err.println("server started at " + server.getAddress()); + + final Hashtable envProps = createEnvProps(server); + final LdapContext ctx = new InitialLdapContext(envProps, null); + + StartTlsResponse startTlsResp = null; + try { + startTlsResp = (StartTlsResponse) ctx.extendedOperation(new StartTlsRequest()); + assertNotNull(startTlsResp, "StartTlsResponse is null"); + if (verifier != null) { + startTlsResp.setHostnameVerifier(verifier); + } + + final Connection ldapConn = getConnection(startTlsResp); + assertNotNull(ldapConn, "LDAP connection is null in " + startTlsResp); + // capture the input/output stream on the LDAP connection + final LdapConnStreams before = getStreams(ldapConn); + // do the TLS negotiation. expected to complete successfully + final SSLSession sess = startTlsResp.negotiate(server.sslContext.getSocketFactory()); + assertNotNull(sess, "SSLSession is null after StartTLS negotiation"); + assertTrue(sess.isValid(), "SSLSession is invalid after StartTLS negotiation"); + if (verifier != null) { + // assert that the custom hostname verifier was invoked + assertTrue(verifier.invoked, "custom HostnameVerifier was not invoked"); + } + + // TLS session established, now do a trivial LDAP search and expect it to + // work fine + final Object result = ctx.lookup("CN=foobar"); + System.err.println("got result " + result); + assertNotNull(result, "Context.lookup() returned null"); + + // TLS negotiation as well as a trivial LDAP search completed fine, + // now close the StartTlsResponse + startTlsResp.close(); + + // verify that after the StartTlsResponse is closed, the streams + // of the underlying LDAP connection are switched back to the ones that were there + // before the TLS negotiation + final LdapConnStreams after = getStreams(ldapConn); + assertSame(before.in, after.in, + "unexpected InputStream on LDAP connection after StartTlsResponse was closed"); + assertSame(before.out, after.out, + "unexpected OutputStream on LDAP connection after StartTlsResponse was closed"); + } finally { + if (startTlsResp != null) { + startTlsResp.close(); + } + ctx.close(); + } + } + } + + private static Hashtable createEnvProps(final Server server) throws Exception { + final Hashtable envProps = new Hashtable<>(); + envProps.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory"); + final String providerUrl = URIBuilder.newBuilder() + .scheme("ldap") + .host(server.getInetAddress().getHostAddress()) + .port(server.getPort()) + .build().toString(); + envProps.put(Context.PROVIDER_URL, providerUrl); + // explicitly set LDAP version to 3 to prevent LDAP BIND requests + // during LdapCtx instantiation + envProps.put("java.naming.ldap.version", "3"); + return envProps; + } + + // using reflection, returns the LDAP connection instance associated with the StartTlsResponse + private static Connection getConnection(final StartTlsResponse tlsResponse) throws Exception { + final Field connField = tlsResponse.getClass().getDeclaredField("ldapConnection"); + connField.setAccessible(true); + return (Connection) connField.get(tlsResponse); + } + + // returns the input and output stream associated with the LDAP Connection + private static LdapConnStreams getStreams(final Connection connection) { + return new LdapConnStreams(connection.inStream, connection.outStream); + } + + private record LdapConnStreams(InputStream in, OutputStream out) { + } + + // a trivial HostnameVerifier which returns a given verification result from + // its verify method + private static final class SimpleHostnameVerifier implements HostnameVerifier { + private final boolean verificationResult; + private boolean invoked; + + private SimpleHostnameVerifier(final boolean verificationResult) { + this.verificationResult = verificationResult; + } + + @Override + public boolean verify(final String hostname, final SSLSession session) { + this.invoked = true; + return this.verificationResult; + } + } + + // the LDAP server used in the test + private static final class Server extends BaseLdapServer implements AutoCloseable { + private final SSLContext sslContext; + + private Server(final SSLContext sslContext) throws IOException { + super(new ServerSocket(0, 0, InetAddress.getLoopbackAddress())); + this.sslContext = sslContext; + } + + private InetSocketAddress getAddress() { + return new InetSocketAddress(this.getInetAddress(), this.getPort()); + } + + // handles and responds to the incoming LDAP request + @Override + protected void handleRequestEx(final Socket socket, + final LdapMessage request, + final OutputStream out, + final BaseLdapServer.ConnWrapper connWrapper) + throws IOException { + switch (request.getOperation()) { + case EXTENDED_REQUEST: { + System.err.println("handling ExtendedRequest from " + socket); + // write out the ExtendedResponse + final byte[] resp = makeExtendedResponse((byte) request.getMessageID()); + out.write(resp); + out.flush(); + System.err.println("ExtendedResponse: " + Arrays.toString(resp)); + // switch to using TLS over the server connection + switchToTLSConnection(socket, connWrapper); + return; + } + case SEARCH_REQUEST: { + System.err.println("handling SEARCH_REQUEST with id: " + + request.getMessageID() + " from " + socket); + // write out a search response + final byte[] resp = makeSearchResultDone((byte) request.getMessageID()); + out.write(resp); + out.flush(); + System.err.println("search response: " + Arrays.toString(resp)); + break; + } + default: { + throw new IOException("unexpected operation type: " + request.getOperation() + + ", request: " + request); + } + } + } + + @Override + public void close() { + System.err.println("stopping server " + this.getAddress()); + super.close(); + } + + // switch the underlying server implementation to expect TLS content + // on the connection + private void switchToTLSConnection(final Socket socket, + final BaseLdapServer.ConnWrapper connWrapper) + throws IOException { + SSLSocket sslSocket; + final SSLSocketFactory factory = this.sslContext.getSocketFactory(); + try { + sslSocket = (SSLSocket) factory.createSocket(socket, null, socket.getLocalPort(), false); + } catch (Exception e) { + throw new IOException(e); + } + sslSocket.setUseClientMode(false); + connWrapper.setWrapper(sslSocket); + } + + // construct a ExtendedResponse LDAP message for the given message id + private static byte[] makeExtendedResponse(final byte msgId) throws IOException { + // LDAPResult ::= SEQUENCE { + // resultCode ENUMERATED { + // success (0), + // ... + // }, + // matchedDN LDAPDN, + // diagnosticMessage LDAPString, + // referral [3] Referral OPTIONAL + // } + // + // ExtendedResponse ::= [APPLICATION 24] SEQUENCE { + // COMPONENTS OF LDAPResult, + // responseName [10] LDAPOID OPTIONAL, + // responseValue [11] OCTET STRING OPTIONAL + // } + final BerEncoder ber = new BerEncoder(); + ber.beginSeq(BER_TYPE_LDAP_SEQUENCE); + ber.encodeInt(msgId); + { + ber.beginSeq(BER_TYPE_EXTENDED_RESPONSE); + ber.encodeInt(0, BER_TYPE_ENUM); // resultCode = 0 == success + ber.encodeString("", false); // matchedDN == empty string + ber.encodeString("", false); // diagnosticMessage == empty string + ber.endSeq(); + } + ber.endSeq(); + + return ber.getTrimmedBuf(); + } + + // construct a SearchResultDone LDAP message for the given message id + private static byte[] makeSearchResultDone(final byte msgId) throws IOException { + // SearchResultDone ::= [APPLICATION 5] LDAPResult + // + // LDAPResult ::= SEQUENCE { + // resultCode ENUMERATED { + // success (0), + // ... + // }, + // matchedDN LDAPDN, + // diagnosticMessage LDAPString, + // referral [3] Referral OPTIONAL + // } + final BerEncoder ber = new BerEncoder(); + ber.beginSeq(BER_TYPE_LDAP_SEQUENCE); + ber.encodeInt(msgId); + { + ber.beginSeq(BER_TYPE_LDAP_SEARCH_RESULT_DONE_OP); + ber.encodeInt(0, BER_TYPE_ENUM); // resultCode = 0 == success + ber.encodeString("", false); // matchedDN == empty string + ber.encodeString("", false); // diagnosticMessage == empty string + ber.endSeq(); + } + ber.endSeq(); + + return ber.getTrimmedBuf(); + } + } +} diff --git a/test/jdk/java/awt/List/ListSelection/DeselectionUnitTest.java b/test/jdk/java/awt/List/ListSelection/DeselectionUnitTest.java new file mode 100644 index 00000000000..4db4637f432 --- /dev/null +++ b/test/jdk/java/awt/List/ListSelection/DeselectionUnitTest.java @@ -0,0 +1,159 @@ +/* + * 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. + */ + +import java.awt.Frame; +import java.awt.List; + +import static jdk.test.lib.Asserts.assertEquals; +import static jdk.test.lib.Asserts.assertFalse; +import static jdk.test.lib.Asserts.assertTrue; + +/** + * @test + * @bug 8369327 + * @summary Test awt list deselection methods + * @key headful + * @library /test/lib + * @build jdk.test.lib.Asserts + * @run main DeselectionUnitTest + */ +public final class DeselectionUnitTest { + + public static void main(String[] args) { + testNonDisplayable(DeselectionUnitTest::testSingleMode); + testNonDisplayable(DeselectionUnitTest::testMultipleMode); + testNonDisplayable(DeselectionUnitTest::testInvalidDeselection); + testNonDisplayable(DeselectionUnitTest::testEmptyListDeselection); + + testDisplayable(DeselectionUnitTest::testSingleMode); + testDisplayable(DeselectionUnitTest::testMultipleMode); + testDisplayable(DeselectionUnitTest::testInvalidDeselection); + testDisplayable(DeselectionUnitTest::testEmptyListDeselection); + } + + interface Test { + void execute(Frame frame); + } + + private static void testNonDisplayable(Test test) { + test.execute(null); + } + + private static void testDisplayable(Test test) { + Frame frame = new Frame(); + try { + frame.setSize(300, 200); + frame.setLocationRelativeTo(null); + frame.setVisible(true); + test.execute(frame); + } finally { + frame.dispose(); + } + } + + private static List createList(Frame frame, boolean multi) { + List list = new List(4, multi); + if (frame != null) { + frame.add(list); + } + list.add("Item1"); + list.add("Item2"); + list.add("Item3"); + return list; + } + + private static void testSingleMode(Frame frame) { + List list = createList(frame, false); + + // Select and deselect single item + list.select(1); + assertTrue(list.isIndexSelected(1)); + list.deselect(1); + assertEquals(-1, list.getSelectedIndex()); + assertEquals(0, list.getSelectedIndexes().length); + assertFalse(list.isIndexSelected(0)); + assertFalse(list.isIndexSelected(1)); + assertFalse(list.isIndexSelected(2)); + + // Deselect non-selected item (should be no-op) + list.select(0); + list.deselect(2); + assertEquals(0, list.getSelectedIndex()); + assertTrue(list.isIndexSelected(0)); + assertFalse(list.isIndexSelected(1)); + assertFalse(list.isIndexSelected(2)); + } + + private static void testMultipleMode(Frame frame) { + List list = createList(frame, true); + + // Select multiple items and deselect one + list.select(0); + list.select(1); + list.select(2); + assertEquals(3, list.getSelectedIndexes().length); + + list.deselect(1); + assertEquals(2, list.getSelectedIndexes().length); + assertTrue(list.isIndexSelected(0)); + assertFalse(list.isIndexSelected(1)); + assertTrue(list.isIndexSelected(2)); + + // Deselect all remaining + list.deselect(0); + list.deselect(2); + assertEquals(-1, list.getSelectedIndex()); + assertEquals(0, list.getSelectedIndexes().length); + assertFalse(list.isIndexSelected(0)); + assertFalse(list.isIndexSelected(1)); + assertFalse(list.isIndexSelected(2)); + } + + private static void testInvalidDeselection(Frame frame) { + List list = createList(frame, false); + + // Deselect invalid indices (should be no-op) + list.select(0); + list.deselect(-1); + list.deselect(5); + assertEquals(0, list.getSelectedIndex()); + assertTrue(list.isIndexSelected(0)); + assertFalse(list.isIndexSelected(1)); + assertFalse(list.isIndexSelected(2)); + } + + private static void testEmptyListDeselection(Frame frame) { + List list = new List(); + if (frame != null) { + frame.add(list); + } + + // Deselect on empty list (should be no-op) + list.deselect(0); + list.deselect(-1); + assertEquals(-1, list.getSelectedIndex()); + assertEquals(0, list.getSelectedIndexes().length); + assertFalse(list.isIndexSelected(0)); + } + +} diff --git a/test/jdk/java/awt/List/ListSelection/SelectInvalidTest.java b/test/jdk/java/awt/List/ListSelection/SelectInvalidTest.java new file mode 100644 index 00000000000..ac29b270c81 --- /dev/null +++ b/test/jdk/java/awt/List/ListSelection/SelectInvalidTest.java @@ -0,0 +1,216 @@ +/* + * 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. + */ + +import java.awt.Frame; +import java.awt.List; + +import jdk.test.lib.Platform; + +import static jdk.test.lib.Asserts.assertEquals; +import static jdk.test.lib.Asserts.assertFalse; +import static jdk.test.lib.Asserts.assertTrue; + +/** + * @test + * @bug 8369327 + * @summary Test awt list selection of invalid indexes + * @key headful + * @library /test/lib + * @build jdk.test.lib.Asserts jdk.test.lib.Platform + * @run main SelectInvalidTest + */ +public final class SelectInvalidTest { + + /** + * A special index on windows, selects or deselects all elements. + */ + private static final int WINDOWS_INVALID = -1; + + /** + * The list of invalid indexes, their usages should be noop. + */ + private static final int[] INVALID = { + WINDOWS_INVALID, Integer.MIN_VALUE, -100, 3, 100, Integer.MAX_VALUE + }; + + public static void main(String[] args) { + for (int i : INVALID) { + if (Platform.isWindows() && i == WINDOWS_INVALID) { + testDisplayable(SelectInvalidTest::testWinDeselectAllSingleMode, i); + testDisplayable(SelectInvalidTest::testWinSelectAllMultipleMode, i); + } else { + testDisplayable(SelectInvalidTest::testSingleMode, i); + testDisplayable(SelectInvalidTest::testMultipleMode, i); + testDisplayable(SelectInvalidTest::testEmptySelection, i); + } + } + } + + interface Test { + void execute(Frame frame, int invalid); + } + + private static void testDisplayable(Test test, int invalid) { + Frame frame = new Frame(); + try { + frame.setSize(300, 200); + frame.setLocationRelativeTo(null); + frame.setVisible(true); + test.execute(frame, invalid); + } finally { + frame.dispose(); + } + } + + private static void testSingleMode(Frame frame, int invalid) { + List list = new List(4, false); + frame.add(list); + list.add("Item1"); + list.add("Item2"); + list.add("Item3"); + + // Test initial state + list.select(invalid); + assertEquals(-1, list.getSelectedIndex()); + assertEquals(0, list.getSelectedIndexes().length); + assertFalse(list.isIndexSelected(0)); + assertFalse(list.isIndexSelected(1)); + assertFalse(list.isIndexSelected(2)); + + // Test single selection + list.select(1); + list.select(invalid); + assertEquals(1, list.getSelectedIndex()); + assertEquals(1, list.getSelectedIndexes().length); + assertEquals(1, list.getSelectedIndexes()[0]); + assertFalse(list.isIndexSelected(0)); + assertTrue(list.isIndexSelected(1)); + assertFalse(list.isIndexSelected(2)); + + // Test selection replacement in single mode + list.select(2); + list.select(invalid); + assertEquals(2, list.getSelectedIndex()); + assertEquals(1, list.getSelectedIndexes().length); + assertEquals(2, list.getSelectedIndexes()[0]); + assertFalse(list.isIndexSelected(0)); + assertFalse(list.isIndexSelected(1)); + assertTrue(list.isIndexSelected(2)); + } + + private static void testMultipleMode(Frame frame, int invalid) { + List list = new List(4, true); + frame.add(list); + list.add("Item1"); + list.add("Item2"); + list.add("Item3"); + + // Test multiple selections + list.select(0); + list.select(2); + list.select(invalid); + // Returns -1 for multiple selections + assertEquals(-1, list.getSelectedIndex()); + assertEquals(2, list.getSelectedIndexes().length); + assertTrue(list.isIndexSelected(0)); + assertFalse(list.isIndexSelected(1)); + assertTrue(list.isIndexSelected(2)); + + // Test partial deselection + list.deselect(0); + list.select(invalid); + // Single selection remaining + assertEquals(2, list.getSelectedIndex()); + assertEquals(1, list.getSelectedIndexes().length); + assertEquals(2, list.getSelectedIndexes()[0]); + assertFalse(list.isIndexSelected(0)); + assertFalse(list.isIndexSelected(1)); + assertTrue(list.isIndexSelected(2)); + } + + private static void testEmptySelection(Frame frame, int invalid) { + List list = new List(); + frame.add(list); + list.select(invalid); + assertEquals(-1, list.getSelectedIndex()); + assertEquals(0, list.getSelectedIndexes().length); + assertFalse(list.isIndexSelected(0)); + } + + private static void testWinDeselectAllSingleMode(Frame frame, int invalid) { + List list = new List(4, false); + frame.add(list); + list.add("Item1"); + list.add("Item2"); + list.add("Item3"); + + list.select(invalid); + assertEquals(-1, list.getSelectedIndex()); + assertEquals(0, list.getSelectedIndexes().length); + assertFalse(list.isIndexSelected(0)); + assertFalse(list.isIndexSelected(1)); + assertFalse(list.isIndexSelected(2)); + + list.select(1); + list.select(invalid); + assertEquals(-1, list.getSelectedIndex()); + assertEquals(0, list.getSelectedIndexes().length); + assertFalse(list.isIndexSelected(0)); + assertFalse(list.isIndexSelected(1)); + assertFalse(list.isIndexSelected(2)); + + list.select(2); + list.select(invalid); + assertEquals(-1, list.getSelectedIndex()); + assertEquals(0, list.getSelectedIndexes().length); + assertFalse(list.isIndexSelected(0)); + assertFalse(list.isIndexSelected(1)); + assertFalse(list.isIndexSelected(2)); + } + + private static void testWinSelectAllMultipleMode(Frame frame, int invalid) { + List list = new List(4, true); + frame.add(list); + list.add("Item1"); + list.add("Item2"); + list.add("Item3"); + + list.select(0); + list.select(2); + list.select(invalid); + assertEquals(-1, list.getSelectedIndex()); + assertEquals(3, list.getSelectedIndexes().length); + assertTrue(list.isIndexSelected(0)); + assertTrue(list.isIndexSelected(1)); + assertTrue(list.isIndexSelected(2)); + + list.deselect(0); + list.select(invalid); + assertEquals(-1, list.getSelectedIndex()); + assertEquals(3, list.getSelectedIndexes().length); + assertTrue(list.isIndexSelected(0)); + assertTrue(list.isIndexSelected(1)); + assertTrue(list.isIndexSelected(2)); + } + +} diff --git a/test/jdk/java/awt/List/ListSelection/SelectionUnitTest.java b/test/jdk/java/awt/List/ListSelection/SelectionUnitTest.java new file mode 100644 index 00000000000..7757eb61b08 --- /dev/null +++ b/test/jdk/java/awt/List/ListSelection/SelectionUnitTest.java @@ -0,0 +1,146 @@ +/* + * 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. + */ + +import java.awt.Frame; +import java.awt.List; + +import static jdk.test.lib.Asserts.assertEquals; +import static jdk.test.lib.Asserts.assertFalse; +import static jdk.test.lib.Asserts.assertTrue; + +/** + * @test + * @bug 8369327 + * @summary Test awt list selection methods + * @key headful + * @library /test/lib + * @build jdk.test.lib.Asserts + * @run main SelectionUnitTest + */ +public final class SelectionUnitTest { + + public static void main(String[] args) { + testNonDisplayable(SelectionUnitTest::testSingleMode); + testNonDisplayable(SelectionUnitTest::testMultipleMode); + testNonDisplayable(SelectionUnitTest::testEmptySelection); + + testDisplayable(SelectionUnitTest::testSingleMode); + testDisplayable(SelectionUnitTest::testMultipleMode); + testDisplayable(SelectionUnitTest::testEmptySelection); + } + + interface Test { + void execute(Frame frame); + } + + private static void testNonDisplayable(Test test) { + test.execute(null); + } + + private static void testDisplayable(Test test) { + Frame frame = new Frame(); + try { + frame.setSize(300, 200); + frame.setLocationRelativeTo(null); + frame.setVisible(true); + test.execute(frame); + } finally { + frame.dispose(); + } + } + + private static List createList(Frame frame, boolean multi) { + List list = new List(4, multi); + if (frame != null) { + frame.add(list); + } + list.add("Item1"); + list.add("Item2"); + list.add("Item3"); + return list; + } + + private static void testSingleMode(Frame frame) { + List list = createList(frame, false); + + // Test initial state + assertEquals(-1, list.getSelectedIndex()); + assertEquals(0, list.getSelectedIndexes().length); + assertFalse(list.isIndexSelected(0)); + assertFalse(list.isIndexSelected(1)); + assertFalse(list.isIndexSelected(2)); + + // Test single selection + list.select(1); + assertEquals(1, list.getSelectedIndex()); + assertEquals(1, list.getSelectedIndexes().length); + assertEquals(1, list.getSelectedIndexes()[0]); + assertFalse(list.isIndexSelected(0)); + assertTrue(list.isIndexSelected(1)); + assertFalse(list.isIndexSelected(2)); + + // Test selection replacement in single mode + list.select(2); + assertEquals(2, list.getSelectedIndex()); + assertEquals(1, list.getSelectedIndexes().length); + assertEquals(2, list.getSelectedIndexes()[0]); + assertFalse(list.isIndexSelected(0)); + assertFalse(list.isIndexSelected(1)); + assertTrue(list.isIndexSelected(2)); + } + + private static void testMultipleMode(Frame frame) { + List list = createList(frame, true); + + // Test multiple selections + list.select(0); + list.select(2); + // Returns -1 for multiple selections + assertEquals(-1, list.getSelectedIndex()); + assertEquals(2, list.getSelectedIndexes().length); + assertTrue(list.isIndexSelected(0)); + assertFalse(list.isIndexSelected(1)); + assertTrue(list.isIndexSelected(2)); + + // Test partial deselection + list.deselect(0); + // Single selection remaining + assertEquals(2, list.getSelectedIndex()); + assertEquals(1, list.getSelectedIndexes().length); + assertEquals(2, list.getSelectedIndexes()[0]); + assertFalse(list.isIndexSelected(0)); + assertFalse(list.isIndexSelected(1)); + assertTrue(list.isIndexSelected(2)); + } + + private static void testEmptySelection(Frame frame) { + List list = new List(); + if (frame != null) { + frame.add(list); + } + assertEquals(-1, list.getSelectedIndex()); + assertEquals(0, list.getSelectedIndexes().length); + assertFalse(list.isIndexSelected(0)); + } + +} diff --git a/test/jdk/java/awt/List/ListSelection/SetMultipleModeTest.java b/test/jdk/java/awt/List/ListSelection/SetMultipleModeTest.java new file mode 100644 index 00000000000..73c131c1105 --- /dev/null +++ b/test/jdk/java/awt/List/ListSelection/SetMultipleModeTest.java @@ -0,0 +1,133 @@ +/* + * 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. + */ + +import java.awt.Frame; +import java.awt.List; +import java.awt.Toolkit; +import java.util.Arrays; + +/** + * @test + * @bug 8369327 + * @summary Test awt list setMultipleMode selection + * @key headful + */ +public final class SetMultipleModeTest { + + public static void main(String[] args) { + // Non-displayable list + // test(null); Does not work per the spec + + // Displayable list + Frame frame = new Frame(); + try { + test(frame); + } finally { + frame.dispose(); + } + } + + private static void test(Frame frame) { + List list = new List(); + list.add("Item1"); + list.add("Item2"); + list.add("Item3"); + if (frame != null) { + frame.add(list); + frame.pack(); + } + + // Empty: mode switch preserves empty + list.setMultipleMode(true); + check(list); + list.deselect(0); + check(list); + list.setMultipleMode(false); + check(list); + + // Single to multi preserves selection + list.select(1); + list.setMultipleMode(true); + check(list, 1); + + // Multi to multi is no-op + list.select(0); + list.select(2); + check(list, 0, 1, 2); + list.setMultipleMode(true); + check(list, 0, 1, 2); + + // Multi to single keeps lead + list.setMultipleMode(false); + check(list, 2); + + // Single to single is no-op + list.setMultipleMode(false); + check(list, 2); + + // Round-trip + list.setMultipleMode(true); + check(list, 2); + list.setMultipleMode(false); + check(list, 2); + + // XAWT does not move the focus cursor on deselect(), + // so multi->single keeps the focused item, skip on XAWT + boolean isXToolkit = "sun.awt.X11.XToolkit".equals( + Toolkit.getDefaultToolkit().getClass().getName()); + if (!isXToolkit) { + // Deselect lead in multi, switch to single + list.setMultipleMode(true); + list.select(0); + list.select(1); + check(list, 0, 1, 2); + list.deselect(2); + check(list, 0, 1); + list.setMultipleMode(false); + check(list); + + // Deselect non-selected in multi, no-op + list.setMultipleMode(true); + list.select(0); + check(list, 0); + list.deselect(2); + check(list, 0); + list.setMultipleMode(false); + check(list); + } + + if (frame != null) { + frame.remove(list); + } + } + + private static void check(List list, int... expected) { + int[] actual = list.getSelectedIndexes(); + Arrays.sort(actual); + if (!Arrays.equals(expected, actual)) { + throw new RuntimeException( + "Expected %s, got %s".formatted(Arrays.toString(expected), + Arrays.toString(actual))); + } + } +} diff --git a/test/jdk/java/awt/Mixing/AWT_Mixing/GlassPaneOverlappingTestBase.java b/test/jdk/java/awt/Mixing/AWT_Mixing/GlassPaneOverlappingTestBase.java index f5dd838eff2..6bd9900a670 100644 --- a/test/jdk/java/awt/Mixing/AWT_Mixing/GlassPaneOverlappingTestBase.java +++ b/test/jdk/java/awt/Mixing/AWT_Mixing/GlassPaneOverlappingTestBase.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -21,11 +21,17 @@ * questions. */ +import java.awt.Component; import java.awt.Container; +import java.awt.KeyboardFocusManager; import java.awt.Point; +import java.awt.event.FocusAdapter; +import java.awt.event.FocusEvent; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import java.lang.reflect.InvocationTargetException; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; import javax.swing.JFrame; import javax.swing.SpringLayout; @@ -54,7 +60,7 @@ public abstract class GlassPaneOverlappingTestBase extends SimpleOverlappingTest protected void prepareControls() { wasLWClicked = false; - if(f != null) { + if (f != null) { f.setVisible(false); } f = new JFrame("Mixing : GlassPane Overlapping test"); @@ -63,7 +69,8 @@ public abstract class GlassPaneOverlappingTestBase extends SimpleOverlappingTest propagateAWTControls(f); - f.getGlassPane().setVisible(true); + f.getGlassPane() + .setVisible(true); Container glassPane = (Container) f.getGlassPane(); glassPane.setLayout(null); @@ -102,6 +109,7 @@ public abstract class GlassPaneOverlappingTestBase extends SimpleOverlappingTest * Run test by {@link OverlappingTestBase#clickAndBlink(java.awt.Robot, java.awt.Point) } validation for current lightweight component. *

        Also resize component and repeat validation in the resized area. *

        Called by base class. + * * @return true if test passed * @see GlassPaneOverlappingTestBase#testResize */ @@ -110,28 +118,54 @@ public abstract class GlassPaneOverlappingTestBase extends SimpleOverlappingTest if (!super.performTest()) { return false; } - if (!testResize) { return true; } + final CountDownLatch latch = new CountDownLatch(1); + f.addFocusListener(new FocusAdapter() { + @Override + public void focusGained(FocusEvent e) { + latch.countDown(); + } + }); wasLWClicked = false; try { SwingUtilities.invokeAndWait(new Runnable() { public void run() { testedComponent.setBounds(0, 0, - testedComponent.getPreferredSize().width, - testedComponent.getPreferredSize().height + 20); + testedComponent.getPreferredSize().width, + testedComponent.getPreferredSize().height + 20); + Component focusOwner = KeyboardFocusManager + .getCurrentKeyboardFocusManager() + .getFocusOwner(); + if (focusOwner == f) { + // frame already has focus + latch.countDown(); + } else { + f.requestFocusInWindow(); + } } }); } catch (InterruptedException | InvocationTargetException ex) { fail(ex.getMessage()); } - Point lLoc = testedComponent.getLocationOnScreen(); - lLoc.translate(1, testedComponent.getPreferredSize().height + 1); - clickAndBlink(robot, lLoc); + try { + if (!latch.await(1, TimeUnit.SECONDS)) { + throw new RuntimeException("Ancestor frame didn't receive focus"); + } + final Point[] points = new Point[1]; + SwingUtilities.invokeAndWait(() -> { + Point lLoc = testedComponent.getLocationOnScreen(); + lLoc.translate(1, testedComponent.getPreferredSize().height + 1); + points[0] = lLoc; + }); + clickAndBlink(robot, points[0]); + } catch (InterruptedException | InvocationTargetException e) { + throw new RuntimeException(e); + } return wasLWClicked; } diff --git a/test/jdk/java/awt/Mixing/AWT_Mixing/JComboBoxOverlapping.java b/test/jdk/java/awt/Mixing/AWT_Mixing/JComboBoxOverlapping.java index d71fa7b3522..31a042a995d 100644 --- a/test/jdk/java/awt/Mixing/AWT_Mixing/JComboBoxOverlapping.java +++ b/test/jdk/java/awt/Mixing/AWT_Mixing/JComboBoxOverlapping.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -26,15 +26,17 @@ import java.awt.Point; import java.awt.Robot; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; + import javax.swing.BoxLayout; import javax.swing.JComboBox; import javax.swing.JFrame; import javax.swing.SwingUtilities; + import test.java.awt.regtesthelpers.Util; /** - * AWT/Swing overlapping test for {@link javax.swing.JCombobox } component. + * AWT/Swing overlapping test for {@link javax.swing.JComboBox } component. *

        This test creates combobox and test if heavyweight component is drawn correctly then dropdown is shown. *

        See base class for details. */ @@ -55,18 +57,22 @@ public class JComboBoxOverlapping extends OverlappingTestBase { private boolean lwClicked = false; private Point loc; private Point loc2; - private JComboBox cb; + private JComboBox cb; private JFrame frame; - {testEmbeddedFrame = true;} + { + testEmbeddedFrame = true; + } protected void prepareControls() { frame = new JFrame("Mixing : Dropdown Overlapping test"); - frame.getContentPane().setLayout(new BoxLayout(frame.getContentPane(), BoxLayout.Y_AXIS)); + frame.getContentPane() + .setLayout(new BoxLayout(frame.getContentPane(), BoxLayout.Y_AXIS)); frame.setSize(200, 200); - cb = new JComboBox(petStrings); - cb.setPreferredSize(new Dimension(frame.getContentPane().getWidth(), 20)); + cb = new JComboBox<>(petStrings); + cb.setPreferredSize(new Dimension(frame.getContentPane() + .getWidth(), 20)); cb.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { @@ -92,13 +98,15 @@ public class JComboBoxOverlapping extends OverlappingTestBase { try { SwingUtilities.invokeAndWait(() -> { loc = cb.getLocationOnScreen(); - loc2 = frame.getContentPane().getLocationOnScreen(); + loc2 = frame.getContentPane() + .getLocationOnScreen(); }); } catch (Exception e) { throw new RuntimeException(e); } loc2.translate(75, 75); + robot.mouseMove(0, 0); // Avoid capturing mouse cursor pixelPreCheck(robot, loc2, currentAwtControl); loc.translate(3, 3); diff --git a/test/jdk/java/awt/Mixing/AWT_Mixing/JMenuBarOverlapping.java b/test/jdk/java/awt/Mixing/AWT_Mixing/JMenuBarOverlapping.java index f3a213e5144..ac2adb4ba13 100644 --- a/test/jdk/java/awt/Mixing/AWT_Mixing/JMenuBarOverlapping.java +++ b/test/jdk/java/awt/Mixing/AWT_Mixing/JMenuBarOverlapping.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -54,7 +54,7 @@ import test.java.awt.regtesthelpers.Util; * java.desktop/java.awt.peer * @build java.desktop/java.awt.Helper * @build Util - * @run main JMenuBarOverlapping + * @run main/timeout=180 JMenuBarOverlapping */ public class JMenuBarOverlapping extends OverlappingTestBase { @@ -73,6 +73,8 @@ public class JMenuBarOverlapping extends OverlappingTestBase { frame = new JFrame("Mixing : Dropdown Overlapping test"); frame.setLayout(new GridLayout(0,1)); frame.setSize(200, 200); + frame.setLocationRelativeTo(null); + frame.setVisible(true); menuBar = new JMenuBar(); JMenu menu = new JMenu("Test Menu"); @@ -104,8 +106,6 @@ public class JMenuBarOverlapping extends OverlappingTestBase { frame.setJMenuBar(menuBar); propagateAWTControls(frame); - frame.setLocationRelativeTo(null); - frame.setVisible(true); } @Override @@ -122,6 +122,7 @@ public class JMenuBarOverlapping extends OverlappingTestBase { // run robot Robot robot = Util.createRobot(); robot.setAutoDelay(ROBOT_DELAY); + robot.mouseMove(0, 0);// Avoid capturing mouse cursor loc2.translate(75, 75); pixelPreCheck(robot, loc2, currentAwtControl); diff --git a/test/jdk/java/awt/Mixing/AWT_Mixing/JPopupMenuOverlapping.java b/test/jdk/java/awt/Mixing/AWT_Mixing/JPopupMenuOverlapping.java index e80475088ac..003977e233a 100644 --- a/test/jdk/java/awt/Mixing/AWT_Mixing/JPopupMenuOverlapping.java +++ b/test/jdk/java/awt/Mixing/AWT_Mixing/JPopupMenuOverlapping.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -69,12 +69,14 @@ public class JPopupMenuOverlapping extends OverlappingTestBase { frame = new JFrame("Mixing : Dropdown Overlapping test"); frame.setLayout(new SpringLayout()); frame.setSize(200, 200); + frame.setLocationRelativeTo(null); popup = new JPopupMenu(); ActionListener menuListener = new ActionListener() { public void actionPerformed(ActionEvent event) { lwClicked = true; + frame.setVisible(false); } }; JMenuItem item; @@ -83,7 +85,6 @@ public class JPopupMenuOverlapping extends OverlappingTestBase { item.addActionListener(menuListener); } propagateAWTControls(frame); - frame.setLocationRelativeTo(null); frame.setVisible(true); loc = frame.getContentPane().getLocationOnScreen(); } @@ -93,9 +94,8 @@ public class JPopupMenuOverlapping extends OverlappingTestBase { // run robot Robot robot = Util.createRobot(); robot.setAutoDelay(ROBOT_DELAY); - + robot.mouseMove(0, 0);// Avoid capturing mouse cursor loc.translate(75, 75); - pixelPreCheck(robot, loc, currentAwtControl); try { @@ -107,7 +107,6 @@ public class JPopupMenuOverlapping extends OverlappingTestBase { }); robot.waitForIdle(); - clickAndBlink(robot, loc, false); SwingUtilities.invokeAndWait(new Runnable() { diff --git a/test/jdk/java/awt/Mixing/AWT_Mixing/JSplitPaneOverlapping.java b/test/jdk/java/awt/Mixing/AWT_Mixing/JSplitPaneOverlapping.java index 5875a04b62b..7e0b377faf3 100644 --- a/test/jdk/java/awt/Mixing/AWT_Mixing/JSplitPaneOverlapping.java +++ b/test/jdk/java/awt/Mixing/AWT_Mixing/JSplitPaneOverlapping.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -70,6 +70,8 @@ public class JSplitPaneOverlapping extends OverlappingTestBase { p.setPreferredSize(new Dimension(500, 500)); propagateAWTControls(p); sp1 = new JScrollPane(p); + currentAwtControl.setForeground(Color.WHITE); + currentAwtControl.setBackground(Color.WHITE); JButton button = new JButton("JButton"); button.setBackground(Color.RED); diff --git a/test/jdk/java/awt/Mixing/AWT_Mixing/MixingPanelsResizing.java b/test/jdk/java/awt/Mixing/AWT_Mixing/MixingPanelsResizing.java index 1bb9b442dd8..19a1df0ab91 100644 --- a/test/jdk/java/awt/Mixing/AWT_Mixing/MixingPanelsResizing.java +++ b/test/jdk/java/awt/Mixing/AWT_Mixing/MixingPanelsResizing.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -58,7 +58,7 @@ import test.java.awt.regtesthelpers.Util; */ public class MixingPanelsResizing { - static volatile boolean failed = false; + private static final int TOLERANCE_MACOSX = 15; private static JFrame frame; private static JButton jbutton; @@ -77,7 +77,8 @@ public class MixingPanelsResizing { private static int frameBorderCounter() { String JAVA_HOME = System.getProperty("java.home"); try { - Process p = Runtime.getRuntime().exec(JAVA_HOME + "/bin/java FrameBorderCounter"); + Process p = Runtime.getRuntime() + .exec(JAVA_HOME + "/bin/java FrameBorderCounter"); try { p.waitFor(); } catch (InterruptedException e) { @@ -85,7 +86,9 @@ public class MixingPanelsResizing { throw new RuntimeException(e); } if (p.exitValue() != 0) { - throw new RuntimeException("FrameBorderCounter exited with not null code!\n" + readInputStream(p.getErrorStream())); + throw new RuntimeException( + "FrameBorderCounter exited with not null code!\n" + + readInputStream(p.getErrorStream())); } return Integer.parseInt(readInputStream(p.getInputStream()).trim()); } catch (IOException e) { @@ -108,9 +111,11 @@ public class MixingPanelsResizing { private static void init() throws Exception { //*** Create instructions for the user here *** - borderShift = frameBorderCounter(); - borderShift = Math.abs(borderShift) == 1 ? borderShift : (borderShift / 2); + borderShift = + Math.abs(borderShift) == 1 + ? borderShift + : (borderShift / 2); SwingUtilities.invokeAndWait(new Runnable() { public void run() { // prepare controls @@ -127,12 +132,15 @@ public class MixingPanelsResizing { awtPanel.add(jbutton); jbutton.setForeground(jbColor); jbutton.setBackground(jbColor); + jbutton.setOpaque(true); JPanel jPanel = new JPanel(); jbutton2 = new JButton("SwingButton2"); jPanel.add(jbutton2); jbutton2.setForeground(jb2Color); jbutton2.setBackground(jb2Color); + jbutton2.setOpaque(true); + awtButton2 = new Button("AWT Button2"); jPanel.add(awtButton2); awtButton2.setForeground(awt2Color); @@ -158,7 +166,8 @@ public class MixingPanelsResizing { SwingUtilities.invokeAndWait(new Runnable() { public void run() { lLoc = frame.getLocationOnScreen(); - lLoc.translate(frame.getWidth() + borderShift, frame.getHeight() + borderShift); + lLoc.translate(frame.getWidth() + borderShift, + frame.getHeight() + borderShift); } }); @@ -171,25 +180,29 @@ public class MixingPanelsResizing { public void run() { Point btnLoc = jbutton.getLocationOnScreen(); Color c = robot.getPixelColor(btnLoc.x + 5, btnLoc.y + 5); - if (!c.equals(jbColor)) { + System.out.println("Color picked for jbutton: " + c); + if (!isAlmostEqualColor(c, jbColor)) { fail("JButton was not redrawn properly on AWT Panel during move"); } btnLoc = awtButton.getLocationOnScreen(); c = robot.getPixelColor(btnLoc.x + 5, btnLoc.y + 5); - if (!c.equals(awtColor)) { + System.out.println("Color picked for awtButton: " + c); + if (!isAlmostEqualColor(c, awtColor)) { fail("AWT Button was not redrawn properly on AWT Panel during move"); } btnLoc = jbutton2.getLocationOnScreen(); c = robot.getPixelColor(btnLoc.x + 5, btnLoc.y + 5); - if (!c.equals(jb2Color)) { + System.out.println("Color picked for jbutton2: " + c); + if (!isAlmostEqualColor(c, jb2Color)) { fail("JButton was not redrawn properly on JPanel during move"); } btnLoc = awtButton2.getLocationOnScreen(); c = robot.getPixelColor(btnLoc.x + 5, btnLoc.y + 5); - if (!c.equals(awt2Color)) { + System.out.println("Color picked for awtButton2: " + c); + if (!isAlmostEqualColor(c, awt2Color)) { fail("ATW Button was not redrawn properly on JPanel during move"); } } @@ -212,6 +225,7 @@ public class MixingPanelsResizing { pass(); }//End init() + /***************************************************** * Standard Test Machinery Section * DO NOT modify anything in this section -- it's a @@ -256,7 +270,8 @@ public class MixingPanelsResizing { try { Thread.sleep(sleepTime); //Timed out, so fail the test - throw new RuntimeException("Timed out after " + sleepTime / 1000 + " seconds"); + throw new RuntimeException( + "Timed out after " + (sleepTime / 1000) + " seconds"); } catch (InterruptedException e) { //The test harness may have interrupted the test. If so, rethrow the exception // so that the harness gets it and deals with it. @@ -313,6 +328,16 @@ public class MixingPanelsResizing { mainThread.interrupt(); }//fail() + private static boolean isAlmostEqualColor(Color color, Color refColor) { + System.out.println("Comparing color: " + color + " with reference " + + "color: " + refColor); + return color.equals(refColor) + || (Math.abs(color.getRed() - refColor.getRed()) < TOLERANCE_MACOSX + && Math.abs(color.getGreen() - refColor.getGreen()) < TOLERANCE_MACOSX + && Math.abs(color.getBlue() - refColor.getBlue()) < TOLERANCE_MACOSX); + } + static class TestPassedException extends RuntimeException { } + }// class JButtonInGlassPane diff --git a/test/jdk/java/awt/Mixing/AWT_Mixing/OverlappingTestBase.java b/test/jdk/java/awt/Mixing/AWT_Mixing/OverlappingTestBase.java index 3d4adecbd17..cdc76f08894 100644 --- a/test/jdk/java/awt/Mixing/AWT_Mixing/OverlappingTestBase.java +++ b/test/jdk/java/awt/Mixing/AWT_Mixing/OverlappingTestBase.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -21,6 +21,7 @@ * questions. */ +import java.awt.Button; import java.awt.Canvas; import java.awt.Choice; import java.awt.Color; @@ -28,6 +29,7 @@ import java.awt.Component; import java.awt.Container; import java.awt.Dimension; import java.awt.Font; +import java.awt.Helper; import java.awt.List; import java.awt.Point; import java.awt.Robot; @@ -54,7 +56,6 @@ import javax.swing.WindowConstants; import sun.awt.AWTAccessor; import sun.awt.EmbeddedFrame; import sun.awt.OSInfo; - import test.java.awt.regtesthelpers.Util; /** @@ -236,7 +237,7 @@ public abstract class OverlappingTestBase { try { Class definition = Class.forName("java.awt." + className); Constructor constructor = definition.getConstructor(new Class[]{String.class}); - java.awt.Component component = (java.awt.Component) constructor.newInstance(new Object[]{"AWT Component " + className}); + Component component = (Component) constructor.newInstance(new Object[]{"AWT Component " + className}); addAwtControl(container, component); } catch (Exception ex) { System.err.println(ex.getMessage()); @@ -270,16 +271,16 @@ public abstract class OverlappingTestBase { String getWindowMethodName = null; String eframeClassName = null; if (Toolkit.getDefaultToolkit().getClass().getName().contains("XToolkit")) { - java.awt.Helper.addExports("sun.awt.X11", OverlappingTestBase.class.getModule()); + Helper.addExports("sun.awt.X11", OverlappingTestBase.class.getModule()); getWindowMethodName = "getWindow"; eframeClassName = "sun.awt.X11.XEmbeddedFrame"; }else if (Toolkit.getDefaultToolkit().getClass().getName().contains(".WToolkit")) { - java.awt.Helper.addExports("sun.awt.windows", OverlappingTestBase.class.getModule()); + Helper.addExports("sun.awt.windows", OverlappingTestBase.class.getModule()); getWindowMethodName = "getHWnd"; eframeClassName = "sun.awt.windows.WEmbeddedFrame"; }else if (isMac) { - java.awt.Helper.addExports("sun.lwawt", OverlappingTestBase.class.getModule()); - java.awt.Helper.addExports("sun.lwawt.macosx", OverlappingTestBase.class.getModule()); + Helper.addExports("sun.lwawt", OverlappingTestBase.class.getModule()); + Helper.addExports("sun.lwawt.macosx", OverlappingTestBase.class.getModule()); eframeClassName = "sun.lwawt.macosx.CViewEmbeddedFrame"; } @@ -382,10 +383,9 @@ public abstract class OverlappingTestBase { protected String failMessage = "The LW component did not received the click."; private static boolean isValidForPixelCheck(Component component) { - if ((component instanceof java.awt.Scrollbar) || isMac && (component instanceof java.awt.Button)) { - return false; - } - return true; + return component != null + && !(component instanceof Scrollbar) + && !(isMac && (component instanceof Button)); } /** diff --git a/test/jdk/java/awt/Mixing/AWT_Mixing/SimpleOverlappingTestBase.java b/test/jdk/java/awt/Mixing/AWT_Mixing/SimpleOverlappingTestBase.java index 0dd42a36cd0..00140bc845f 100644 --- a/test/jdk/java/awt/Mixing/AWT_Mixing/SimpleOverlappingTestBase.java +++ b/test/jdk/java/awt/Mixing/AWT_Mixing/SimpleOverlappingTestBase.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -44,7 +44,7 @@ import test.java.awt.regtesthelpers.Util; *

        See base class for usage * * @author Sergey Grinev -*/ + */ public abstract class SimpleOverlappingTestBase extends OverlappingTestBase { { @@ -59,6 +59,7 @@ public abstract class SimpleOverlappingTestBase extends OverlappingTestBase { /** * Constructor which sets {@link SimpleOverlappingTestBase#useDefaultClickValidation } + * * @param defaultClickValidation */ protected SimpleOverlappingTestBase(boolean defaultClickValidation) { @@ -66,7 +67,7 @@ public abstract class SimpleOverlappingTestBase extends OverlappingTestBase { this.useDefaultClickValidation = defaultClickValidation; } - protected boolean isMultiFramesTest(){ + protected boolean isMultiFramesTest() { return true; } @@ -75,8 +76,10 @@ public abstract class SimpleOverlappingTestBase extends OverlappingTestBase { } //overridables + /** * Successors override this method providing swing component for testing + * * @return swing component to test */ protected abstract JComponent getSwingComponent(); @@ -93,6 +96,7 @@ public abstract class SimpleOverlappingTestBase extends OverlappingTestBase { /** * Current tested lightweight component + * * @see SimpleOverlappingTestBase#getSwingComponent() */ protected JComponent testedComponent; @@ -141,6 +145,7 @@ public abstract class SimpleOverlappingTestBase extends OverlappingTestBase { /** * Run test by {@link OverlappingTestBase#clickAndBlink(java.awt.Robot, java.awt.Point) } validation for current lightweight component. *

        Called by base class. + * * @return true if test passed */ protected boolean performTest() { @@ -156,23 +161,27 @@ public abstract class SimpleOverlappingTestBase extends OverlappingTestBase { /* this is a workaround for certain jtreg(?) focus issue: tests fail starting after failing mixing tests but always pass alone. */ + final CountDownLatch latch = new CountDownLatch(1); + JFrame ancestor = (JFrame) (testedComponent.getTopLevelAncestor()); if (ancestor != null) { - final CountDownLatch latch = new CountDownLatch(1); ancestor.addFocusListener(new FocusAdapter() { - @Override public void focusGained(FocusEvent e) { + @Override + public void focusGained(FocusEvent e) { latch.countDown(); } }); ancestor.requestFocus(); - try { - if (!latch.await(1L, TimeUnit.SECONDS)) { - throw new RuntimeException( - "Ancestor frame didn't receive focus"); - } - } catch (InterruptedException e) { - throw new RuntimeException(e); + } else { + latch.countDown(); + } + + try { + if (!latch.await(1, TimeUnit.SECONDS)) { + throw new RuntimeException("Ancestor frame didn't receive " + "focus"); } + } catch (InterruptedException e) { + throw new RuntimeException(e); } clickAndBlink(robot, lLoc); @@ -184,14 +193,18 @@ public abstract class SimpleOverlappingTestBase extends OverlappingTestBase { } public boolean isOel7orLater() { - if (System.getProperty("os.name").toLowerCase().contains("linux") && - System.getProperty("os.version").toLowerCase().contains("el")) { + if (System.getProperty("os.name") + .toLowerCase() + .contains("linux") && System.getProperty("os.version") + .toLowerCase() + .contains("el")) { Pattern p = Pattern.compile("el(\\d+)"); Matcher m = p.matcher(System.getProperty("os.version")); if (m.find()) { try { return Integer.parseInt(m.group(1)) >= 7; - } catch (NumberFormatException nfe) {} + } catch (NumberFormatException nfe) { + } } } return false; diff --git a/test/jdk/java/awt/Modal/ModalFocusTransferTests/FocusTransferDialogsTest.java b/test/jdk/java/awt/Modal/ModalFocusTransferTests/FocusTransferDialogsTest.java index 322dd6b94d4..d99f7bf9876 100644 --- a/test/jdk/java/awt/Modal/ModalFocusTransferTests/FocusTransferDialogsTest.java +++ b/test/jdk/java/awt/Modal/ModalFocusTransferTests/FocusTransferDialogsTest.java @@ -185,9 +185,10 @@ public class FocusTransferDialogsTest { javax.imageio.ImageIO.write(img, "jpg", new java.io.File("NOK.jpg")); throw e; - } + } finally { - robot.waitForIdle(delay); - EventQueue.invokeAndWait(this::closeAll); + robot.waitForIdle(delay); + EventQueue.invokeAndWait(this::closeAll); + } } } diff --git a/test/jdk/java/awt/Modal/helpers/TestDialog.java b/test/jdk/java/awt/Modal/helpers/TestDialog.java index a56ce1f5164..6d5972205fa 100644 --- a/test/jdk/java/awt/Modal/helpers/TestDialog.java +++ b/test/jdk/java/awt/Modal/helpers/TestDialog.java @@ -219,9 +219,9 @@ public class TestDialog extends Dialog implements ActionListener, dummyButton.equals(b)) && robot != null) { robot.mouseMove((int) b.getLocationOnScreen().x + b.getSize().width / 2, (int) b.getLocationOnScreen().y + b.getSize().height / 2); - robot.delay(delay); + robot.waitForIdle(delay); robot.click(); - robot.delay(delay); + robot.waitForIdle(delay); } } @@ -292,9 +292,9 @@ public class TestDialog extends Dialog implements ActionListener, if (robot != null) { robot.mouseMove((int) topPanel.getLocationOnScreen().x + topPanel.getSize().width / 2, (int) topPanel.getLocationOnScreen().y + topPanel.getSize().height / 2); - robot.delay(delay); + robot.waitForIdle(delay); robot.click(); - robot.delay(delay); + robot.waitForIdle(delay); } } diff --git a/test/jdk/java/awt/Modal/helpers/TestFrame.java b/test/jdk/java/awt/Modal/helpers/TestFrame.java index d002d6faf8e..d0cc7a827b1 100644 --- a/test/jdk/java/awt/Modal/helpers/TestFrame.java +++ b/test/jdk/java/awt/Modal/helpers/TestFrame.java @@ -209,9 +209,9 @@ public class TestFrame extends Frame implements ActionListener, dummyButton.equals(b)) && robot != null) { robot.mouseMove((int) b.getLocationOnScreen().x + b.getSize().width / 2, (int) b.getLocationOnScreen().y + b.getSize().height / 2); - robot.delay(delay); + robot.waitForIdle(delay); robot.click(); - robot.delay(delay); + robot.waitForIdle(delay); } } @@ -280,9 +280,9 @@ public class TestFrame extends Frame implements ActionListener, if (robot != null) { robot.mouseMove((int) topPanel.getLocationOnScreen().x + topPanel.getSize().width / 2, (int) topPanel.getLocationOnScreen().y + topPanel.getSize().height / 2); - robot.delay(delay); + robot.waitForIdle(delay); robot.click(); - robot.delay(delay); + robot.waitForIdle(delay); } } diff --git a/test/jdk/java/awt/Modal/helpers/TestWindow.java b/test/jdk/java/awt/Modal/helpers/TestWindow.java index 249f56ead7d..f747bc19000 100644 --- a/test/jdk/java/awt/Modal/helpers/TestWindow.java +++ b/test/jdk/java/awt/Modal/helpers/TestWindow.java @@ -215,9 +215,9 @@ public class TestWindow extends Window implements ActionListener, dummyButton.equals(b)) && robot != null) { robot.mouseMove((int) b.getLocationOnScreen().x + b.getSize().width / 2, (int) b.getLocationOnScreen().y + b.getSize().height / 2); - robot.delay(delay); + robot.waitForIdle(delay); robot.click(); - robot.delay(delay); + robot.waitForIdle(delay); } } diff --git a/test/jdk/java/foreign/StdLibTest.java b/test/jdk/java/foreign/StdLibTest.java index f1e35b53a39..aa9102cc168 100644 --- a/test/jdk/java/foreign/StdLibTest.java +++ b/test/jdk/java/foreign/StdLibTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,7 +23,7 @@ /* * @test - * @run testng/othervm/timeout=480 --enable-native-access=ALL-UNNAMED StdLibTest + * @run junit/othervm/timeout=600 --enable-native-access=ALL-UNNAMED StdLibTest */ import java.lang.invoke.MethodHandle; @@ -41,73 +41,83 @@ import java.util.List; import java.util.Set; import java.util.function.Function; import java.util.stream.Collectors; +import java.util.stream.IntStream; import java.util.stream.Stream; import java.lang.foreign.*; -import org.testng.annotations.*; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; -import static org.testng.Assert.*; +import static org.junit.jupiter.api.Assertions.*; -public class StdLibTest extends NativeTestHelper { +final class StdLibTest extends NativeTestHelper { - final static Linker abi = Linker.nativeLinker(); + static final Linker ABI = Linker.nativeLinker(); - private StdLibHelper stdLibHelper = new StdLibHelper(); + static final StdLibHelper STD_LIB_HELPER = new StdLibHelper(); - @Test(dataProvider = "stringPairs") + @ParameterizedTest + @MethodSource("stringPairs") void test_strcat(String s1, String s2) throws Throwable { - assertEquals(stdLibHelper.strcat(s1, s2), s1 + s2); + assertEquals(s1 + s2, STD_LIB_HELPER.strcat(s1, s2)); } - @Test(dataProvider = "stringPairs") + @ParameterizedTest + @MethodSource("stringPairs") void test_strcmp(String s1, String s2) throws Throwable { - assertEquals(Math.signum(stdLibHelper.strcmp(s1, s2)), Math.signum(s1.compareTo(s2))); + assertEquals(Math.signum(s1.compareTo(s2)), Math.signum(STD_LIB_HELPER.strcmp(s1, s2))); } - @Test(dataProvider = "strings") + @ParameterizedTest + @MethodSource("strings") void test_puts(String s) throws Throwable { - assertTrue(stdLibHelper.puts(s) >= 0); + assertTrue(STD_LIB_HELPER.puts(s) >= 0); } - @Test(dataProvider = "strings") + @ParameterizedTest + @MethodSource("strings") void test_strlen(String s) throws Throwable { - assertEquals(stdLibHelper.strlen(s), s.length()); + assertEquals(STD_LIB_HELPER.strlen(s), s.length()); } - @Test(dataProvider = "instants") + @ParameterizedTest + @MethodSource("instants") void test_time(Instant instant) throws Throwable { - StdLibHelper.Tm tm = stdLibHelper.gmtime(instant.getEpochSecond()); + StdLibHelper.Tm tm = STD_LIB_HELPER.gmtime(instant.getEpochSecond()); LocalDateTime localTime = LocalDateTime.ofInstant(instant, ZoneOffset.UTC); - assertEquals(tm.sec(), localTime.getSecond()); - assertEquals(tm.min(), localTime.getMinute()); - assertEquals(tm.hour(), localTime.getHour()); + assertEquals(localTime.getSecond(), tm.sec()); + assertEquals(localTime.getMinute(), tm.min()); + assertEquals(localTime.getHour(), tm.hour()); //day pf year in Java has 1-offset - assertEquals(tm.yday(), localTime.getDayOfYear() - 1); - assertEquals(tm.mday(), localTime.getDayOfMonth()); + assertEquals(localTime.getDayOfYear() - 1, tm.yday()); + assertEquals(localTime.getDayOfMonth(), tm.mday()); //days of week starts from Sunday in C, but on Monday in Java, also account for 1-offset - assertEquals((tm.wday() + 6) % 7, localTime.getDayOfWeek().getValue() - 1); + assertEquals(localTime.getDayOfWeek().getValue() - 1, (tm.wday() + 6) % 7); //month in Java has 1-offset - assertEquals(tm.mon(), localTime.getMonth().getValue() - 1); - assertEquals(tm.isdst(), ZoneOffset.UTC.getRules() - .isDaylightSavings(Instant.ofEpochMilli(instant.getEpochSecond() * 1000))); + assertEquals(localTime.getMonth().getValue() - 1, tm.mon()); + assertEquals(ZoneOffset.UTC.getRules() + .isDaylightSavings(Instant.ofEpochMilli(instant.getEpochSecond() * 1000)), tm.isdst()); } - @Test(dataProvider = "ints") + @ParameterizedTest + @MethodSource("ints") void test_qsort(List ints) throws Throwable { if (ints.size() > 0) { int[] input = ints.stream().mapToInt(i -> i).toArray(); - int[] sorted = stdLibHelper.qsort(input); + int[] sorted = STD_LIB_HELPER.qsort(input); Arrays.sort(input); - assertEquals(sorted, input); + assertArrayEquals(input, sorted); } } @Test void test_rand() throws Throwable { - int val = stdLibHelper.rand(); + int val = STD_LIB_HELPER.rand(); for (int i = 0 ; i < 100 ; i++) { - int newVal = stdLibHelper.rand(); + int newVal = STD_LIB_HELPER.rand(); if (newVal != val) { return; //ok } @@ -116,7 +126,8 @@ public class StdLibTest extends NativeTestHelper { fail("All values are the same! " + val); } - @Test(dataProvider = "printfArgs") + @ParameterizedTest + @MethodSource("printfArgs") void test_printf(List args) throws Throwable { String javaFormatArgs = args.stream() .map(a -> a.javaFormat) @@ -131,8 +142,8 @@ public class StdLibTest extends NativeTestHelper { String expected = String.format(javaFormatString, args.stream() .map(a -> a.javaValue).toArray()); - int found = stdLibHelper.printf(nativeFormatString, args); - assertEquals(found, expected.length()); + int found = STD_LIB_HELPER.printf(nativeFormatString, args); + assertEquals(expected.length(), found); } @Test @@ -140,25 +151,25 @@ public class StdLibTest extends NativeTestHelper { assertTrue(LINKER.defaultLookup().find("strlen\u0000foobar").isEmpty()); } - static class StdLibHelper { + static final class StdLibHelper { - final static MethodHandle strcat = abi.downcallHandle(abi.defaultLookup().find("strcat").get(), + final static MethodHandle strcat = ABI.downcallHandle(ABI.defaultLookup().findOrThrow("strcat"), FunctionDescriptor.of(C_POINTER, C_POINTER, C_POINTER)); - final static MethodHandle strcmp = abi.downcallHandle(abi.defaultLookup().find("strcmp").get(), + final static MethodHandle strcmp = ABI.downcallHandle(ABI.defaultLookup().findOrThrow("strcmp"), FunctionDescriptor.of(C_INT, C_POINTER, C_POINTER)); - final static MethodHandle puts = abi.downcallHandle(abi.defaultLookup().find("puts").get(), + final static MethodHandle puts = ABI.downcallHandle(ABI.defaultLookup().findOrThrow("puts"), FunctionDescriptor.of(C_INT, C_POINTER)); - final static MethodHandle strlen = abi.downcallHandle(abi.defaultLookup().find("strlen").get(), + final static MethodHandle strlen = ABI.downcallHandle(ABI.defaultLookup().findOrThrow("strlen"), FunctionDescriptor.of(C_INT, C_POINTER)); - final static MethodHandle gmtime = abi.downcallHandle(abi.defaultLookup().find("gmtime").get(), + final static MethodHandle gmtime = ABI.downcallHandle(ABI.defaultLookup().findOrThrow("gmtime"), FunctionDescriptor.of(C_POINTER.withTargetLayout(Tm.LAYOUT), C_POINTER)); // void qsort( void *ptr, size_t count, size_t size, int (*comp)(const void *, const void *) ); - final static MethodHandle qsort = abi.downcallHandle(abi.defaultLookup().find("qsort").get(), + final static MethodHandle qsort = ABI.downcallHandle(ABI.defaultLookup().findOrThrow("qsort"), FunctionDescriptor.ofVoid(C_POINTER, C_SIZE_T, C_SIZE_T, C_POINTER)); final static FunctionDescriptor qsortComparFunction = FunctionDescriptor.of(C_INT, @@ -166,13 +177,13 @@ public class StdLibTest extends NativeTestHelper { final static MethodHandle qsortCompar; - final static MethodHandle rand = abi.downcallHandle(abi.defaultLookup().find("rand").get(), + final static MethodHandle rand = ABI.downcallHandle(ABI.defaultLookup().findOrThrow("rand"), FunctionDescriptor.of(C_INT)); - final static MethodHandle vprintf = abi.downcallHandle(abi.defaultLookup().find("vprintf").get(), + final static MethodHandle vprintf = ABI.downcallHandle(ABI.defaultLookup().findOrThrow("vprintf"), FunctionDescriptor.of(C_INT, C_POINTER, C_POINTER)); - final static MemorySegment printfAddr = abi.defaultLookup().find("printf").get(); + final static MemorySegment printfAddr = ABI.defaultLookup().findOrThrow("printf"); final static FunctionDescriptor printfBase = FunctionDescriptor.of(C_INT, C_POINTER); @@ -225,7 +236,7 @@ public class StdLibTest extends NativeTestHelper { } } - static class Tm { + static final class Tm { //Tm pointer should never be freed directly, as it points to shared memory private final MemorySegment base; @@ -282,7 +293,7 @@ public class StdLibTest extends NativeTestHelper { MemorySegment nativeArr = arena.allocateFrom(C_INT, arr); //call qsort - MemorySegment qsortUpcallStub = abi.upcallStub(qsortCompar, qsortComparFunction, arena); + MemorySegment qsortUpcallStub = ABI.upcallStub(qsortCompar, qsortComparFunction, arena); // both of these fit in an int // automatically widen them to long on x64 @@ -297,7 +308,7 @@ public class StdLibTest extends NativeTestHelper { static int qsortCompare(MemorySegment addr1, MemorySegment addr2) { return addr1.get(C_INT, 0) - - addr2.get(C_INT, 0); + addr2.get(C_INT, 0); } int rand() throws Throwable { @@ -322,7 +333,7 @@ public class StdLibTest extends NativeTestHelper { variadicLayouts.add(arg.layout); } Linker.Option varargIndex = Linker.Option.firstVariadicArg(fd.argumentLayouts().size()); - MethodHandle mh = abi.downcallHandle(printfAddr, + MethodHandle mh = ABI.downcallHandle(printfAddr, fd.appendArgumentLayouts(variadicLayouts.toArray(new MemoryLayout[args.size()])), varargIndex); return mh.asSpreader(1, Object[].class, args.size()); @@ -331,47 +342,36 @@ public class StdLibTest extends NativeTestHelper { /*** data providers ***/ - @DataProvider - public static Object[][] ints() { + static Stream ints() { return perms(0, new Integer[] { 0, 1, 2, 3, 4 }).stream() - .map(l -> new Object[] { l }) - .toArray(Object[][]::new); + .map(Arguments::of); } - @DataProvider - public static Object[][] strings() { + static Stream strings() { + return strings0() + .map(Arguments::of); + } + + static Stream stringPairs() { + return strings0() + .flatMap(s -> strings0() + .map(s2 -> Arguments.of(s, s2))); + } + + static Stream strings0() { return perms(0, new String[] { "a", "b", "c" }).stream() - .map(l -> new Object[] { String.join("", l) }) - .toArray(Object[][]::new); + .map(l -> String.join("", l)); } - @DataProvider - public static Object[][] stringPairs() { - Object[][] strings = strings(); - Object[][] stringPairs = new Object[strings.length * strings.length][]; - int pos = 0; - for (Object[] s1 : strings) { - for (Object[] s2 : strings) { - stringPairs[pos++] = new Object[] { s1[0], s2[0] }; - } - } - return stringPairs; - } - - @DataProvider - public static Object[][] instants() { + static Stream instants() { Instant start = ZonedDateTime.of(LocalDateTime.parse("2017-01-01T00:00:00"), ZoneOffset.UTC).toInstant(); Instant end = ZonedDateTime.of(LocalDateTime.parse("2017-12-31T00:00:00"), ZoneOffset.UTC).toInstant(); - Object[][] instants = new Object[100][]; - for (int i = 0 ; i < instants.length ; i++) { - Instant instant = start.plusSeconds((long)(Math.random() * (end.getEpochSecond() - start.getEpochSecond()))); - instants[i] = new Object[] { instant }; - } - return instants; + return IntStream.range(0, 100) + .mapToObj(i -> start.plusSeconds((long)(Math.random() * (end.getEpochSecond() - start.getEpochSecond())))) + .map(Arguments::of); } - @DataProvider - public static Object[][] printfArgs() { + static Stream printfArgs() { ArrayList> res = new ArrayList<>(); List> perms = new ArrayList<>(perms(0, PrintfArg.values())); for (int i = 0 ; i < 100 ; i++) { @@ -379,8 +379,7 @@ public class StdLibTest extends NativeTestHelper { res.addAll(perms); } return res.stream() - .map(l -> new Object[] { l }) - .toArray(Object[][]::new); + .map(Arguments::of); } enum PrintfArg { diff --git a/test/jdk/java/foreign/TestBufferStackStress.java b/test/jdk/java/foreign/TestBufferStackStress.java index 0ec46311a6f..a0b7348331c 100644 --- a/test/jdk/java/foreign/TestBufferStackStress.java +++ b/test/jdk/java/foreign/TestBufferStackStress.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -24,11 +24,12 @@ /* * @test * @modules java.base/jdk.internal.foreign - * @build NativeTestHelper TestBufferStackStress + * @library /test/lib * @run junit TestBufferStackStress */ import jdk.internal.foreign.BufferStack; +import jdk.test.lib.Platform; import org.junit.jupiter.api.Test; import java.lang.foreign.Arena; @@ -40,17 +41,23 @@ import java.util.stream.IntStream; import static java.lang.foreign.ValueLayout.*; import static java.time.temporal.ChronoUnit.SECONDS; import static org.junit.jupiter.api.Assertions.*; +import static org.junit.jupiter.api.Assumptions.*; -public class TestBufferStackStress { +final class TestBufferStackStress { @Test - public void stress() throws InterruptedException { + void stress() throws InterruptedException { + if (Platform.isOSX()) { + // 8350455 was only fixed in macOS versions 26 or higher + assumeFalse(Platform.getOsVersionMajor() < 26, "Unsupported OS version: " + Platform.getOsVersionMajor()); + } + BufferStack stack = BufferStack.of(256, 1); - Thread[] vThreads = IntStream.range(0, 1024).mapToObj(_ -> + Thread[] vThreads = IntStream.range(0, 512).mapToObj(_ -> Thread.ofVirtual().start(() -> { long threadId = Thread.currentThread().threadId(); while (!Thread.interrupted()) { - for (int i = 0; i < 1_000_000; i++) { + for (int i = 0; i < 500_000; i++) { try (Arena arena = stack.pushFrame(JAVA_LONG.byteSize(), JAVA_LONG.byteAlignment())) { // Try to assert no two vThreads get allocated the same stack space. MemorySegment segment = arena.allocate(JAVA_LONG); diff --git a/test/jdk/java/foreign/TestBufferStackStress2.java b/test/jdk/java/foreign/TestBufferStackStress2.java index 402ce6bbe94..cf02d5ae608 100644 --- a/test/jdk/java/foreign/TestBufferStackStress2.java +++ b/test/jdk/java/foreign/TestBufferStackStress2.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -29,7 +29,6 @@ * * @bug 8356114 8356658 * @modules java.base/jdk.internal.foreign - * @build NativeTestHelper TestBufferStackStress2 * @run junit/timeout=480 TestBufferStackStress2 */ diff --git a/test/jdk/java/foreign/TestSegmentOffset.java b/test/jdk/java/foreign/TestSegmentOffset.java index cf335e4ff88..963063378a3 100644 --- a/test/jdk/java/foreign/TestSegmentOffset.java +++ b/test/jdk/java/foreign/TestSegmentOffset.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,30 +23,32 @@ /* * @test - * @run testng TestSegmentOffset + * @run junit TestSegmentOffset */ import java.lang.foreign.Arena; import java.lang.foreign.MemorySegment; -import org.testng.SkipException; -import org.testng.annotations.DataProvider; -import org.testng.annotations.Test; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; import java.util.ArrayList; +import java.util.Arrays; import java.util.List; import java.util.function.IntFunction; +import java.util.stream.Stream; + import static java.lang.System.out; import static java.lang.foreign.ValueLayout.JAVA_BYTE; -import static org.testng.Assert.*; +import static org.junit.jupiter.api.Assertions.*; -public class TestSegmentOffset { +final class TestSegmentOffset { - @Test(dataProvider = "slices") - public void testOffset(SegmentSlice s1, SegmentSlice s2) { - if (s1.kind != s2.kind) { - throw new SkipException("Slices of different segment kinds"); - } + @ParameterizedTest + @MethodSource("slices") + void testOffset(SegmentSlice s1, SegmentSlice s2) { if (s1.contains(s2)) { // check that a segment and its overlapping segment point to same elements long offset = s1.offset(s2); @@ -54,7 +56,7 @@ public class TestSegmentOffset { out.format("testOffset s1:%s, s2:%s, offset:%d, i:%s\n", s1, s2, offset, i); byte expected = s2.segment.get(JAVA_BYTE, i); byte found = s1.segment.get(JAVA_BYTE, i + offset); - assertEquals(found, expected); + assertEquals(expected, found); } } else if (!s2.contains(s1)) { // disjoint segments - check that offset is out of bounds @@ -72,7 +74,7 @@ public class TestSegmentOffset { } } - static class SegmentSlice { + final static class SegmentSlice { enum Kind { NATIVE(i -> Arena.ofAuto().allocate(i, 1)), @@ -94,7 +96,7 @@ public class TestSegmentOffset { final int last; final MemorySegment segment; - public SegmentSlice(Kind kind, int first, int last, MemorySegment segment) { + SegmentSlice(Kind kind, int first, int last, MemorySegment segment) { this.kind = kind; this.first = first; this.last = last; @@ -116,8 +118,8 @@ public class TestSegmentOffset { } } - @DataProvider(name = "slices") - static Object[][] slices() { + + static Stream slices() { int[] sizes = { 16, 8, 4, 2, 1 }; List slices = new ArrayList<>(); for (SegmentSlice.Kind kind : SegmentSlice.Kind.values()) { @@ -134,12 +136,15 @@ public class TestSegmentOffset { } } } - Object[][] sliceArray = new Object[slices.size() * slices.size()][]; + SegmentSlice[][] sliceArray = new SegmentSlice[slices.size() * slices.size()][]; for (int i = 0 ; i < slices.size() ; i++) { for (int j = 0 ; j < slices.size() ; j++) { - sliceArray[i * slices.size() + j] = new Object[] { slices.get(i), slices.get(j) }; + sliceArray[i * slices.size() + j] = new SegmentSlice[] { slices.get(i), slices.get(j) }; } } - return sliceArray; + return Arrays.stream(sliceArray) + // Only consider segment slices of the same kind + .filter(a -> a[0].kind == a[1].kind) + .map(Arguments::of); } } diff --git a/test/jdk/java/lang/LazyConstant/LazyListTest.java b/test/jdk/java/lang/LazyConstant/LazyListTest.java index 111e3cf8ab2..4201fff3bb7 100644 --- a/test/jdk/java/lang/LazyConstant/LazyListTest.java +++ b/test/jdk/java/lang/LazyConstant/LazyListTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2025, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -153,6 +153,15 @@ final class LazyListTest { assertEquals(-1, lazy.lastIndexOf(SIZE + 1)); } + @ParameterizedTest + @MethodSource("lazyLists") + void bounds(List list) { + IntStream.range(0, list.size()) + .forEach(i -> assertEquals(IDENTITY.apply(i), list.get(i))); + assertThrows(IndexOutOfBoundsException.class, () -> list.get(-1)); + assertThrows(IndexOutOfBoundsException.class, () -> list.get(list.size())); + } + @Test void toStringTest() { assertEquals("[]", newEmptyLazyList().toString()); @@ -423,6 +432,11 @@ final class LazyListTest { ); } + static Stream lazyLists() { + return IntStream.rangeClosed(0, SIZE) + .mapToObj(i -> List.ofLazy(i, IDENTITY)); + } + static List newLazyList() { return List.ofLazy(SIZE, IDENTITY); } diff --git a/test/jdk/java/lang/Thread/virtual/DeoptimizedFrame.java b/test/jdk/java/lang/Thread/virtual/DeoptimizedFrame.java new file mode 100644 index 00000000000..a185825dd79 --- /dev/null +++ b/test/jdk/java/lang/Thread/virtual/DeoptimizedFrame.java @@ -0,0 +1,85 @@ +/* + * Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * 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 8377715 + * @summary Test that thawing deoptimized frame preserves the deopt status + * @requires vm.continuations + * @library /test/lib /test/hotspot/jtreg + * @run main/othervm/native -agentlib:DeoptimizedFrame DeoptimizedFrame + */ + +import jdk.test.lib.Asserts; + +public class DeoptimizedFrame { + private static final Object lock = new Object(); + private static A receiver = new A(); + private static volatile int result; + + private static native int setupReferences(Thread t, Object o); + private static native void waitForVThread(); + private static native void notifyVThread(); + + public static void foo() { + synchronized (lock) { + result = receiver.m(); + } + } + + public static void main(String[] args) throws Exception { + warmUp(); + Asserts.assertTrue(receiver.m() == 1, "unexpected value=" + receiver.m()); + + Thread vthread = Thread.ofVirtual().unstarted(() -> foo()); + int res = setupReferences(vthread, lock); + Asserts.assertTrue(res == 0, "error setting references"); + + synchronized (lock) { + vthread.start(); + waitForVThread(); + receiver = new B(); + notifyVThread(); + } + vthread.join(); + Asserts.assertTrue(result == 3, "unexpected result=" + result); + } + + private static void warmUp() throws Exception { + for (int i = 0; i < 30_000; i++) { + foo(); + } + } + + static class A { + int m() { + return 1; + } + } + + static class B extends A { + int m() { + return 3; + } + } +} \ No newline at end of file diff --git a/test/jdk/java/lang/Thread/virtual/libDeoptimizedFrame.cpp b/test/jdk/java/lang/Thread/virtual/libDeoptimizedFrame.cpp new file mode 100644 index 00000000000..7fb5e07c1b5 --- /dev/null +++ b/test/jdk/java/lang/Thread/virtual/libDeoptimizedFrame.cpp @@ -0,0 +1,160 @@ +/* + * Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * 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 +#include +#include "jvmti.h" +#include "jni.h" + +extern "C" { + +static jvmtiEnv *jvmti = nullptr; +static jthread test_vthread = nullptr; +static jobject test_monitor = nullptr; +static jrawMonitorID agent_monitor = nullptr; +static bool called_contended_enter = false; + +class RawMonitorLocker { + private: + jvmtiEnv* _jvmti; + JNIEnv* _jni; + jrawMonitorID _monitor; + + void check_jvmti_status(JNIEnv* jni, jvmtiError err, const char* msg) { + if (err != JVMTI_ERROR_NONE) { + jni->FatalError(msg); + } + } + + public: + RawMonitorLocker(jvmtiEnv *jvmti, JNIEnv* jni, jrawMonitorID monitor): _jvmti(jvmti), _jni(jni), _monitor(monitor) { + check_jvmti_status(_jni, _jvmti->RawMonitorEnter(_monitor), "Fatal Error in RawMonitorEnter."); + } + ~RawMonitorLocker() { + check_jvmti_status(_jni, _jvmti->RawMonitorExit(_monitor), "Fatal Error in RawMonitorExit."); + } + void wait() { + check_jvmti_status(_jni, _jvmti->RawMonitorWait(_monitor, 0), "Fatal Error in RawMonitorWait."); + } + void notify_all() { + check_jvmti_status(_jni, _jvmti->RawMonitorNotifyAll(_monitor), "Fatal Error in RawMonitorNotifyAll."); + } +}; + +JNIEXPORT void JNICALL +MonitorContendedEnter(jvmtiEnv *jvmti, JNIEnv *jni, jthread vthread, jobject monitor) { + if (!jni->IsSameObject(test_vthread, vthread)) { + printf("Thread is not the required one\n"); + return; + } + + if (!jni->IsSameObject(test_monitor, monitor)) { + printf("Monitor is not the required one\n"); + return; + } + + RawMonitorLocker rml(jvmti, jni, agent_monitor); + called_contended_enter = true; + rml.notify_all(); + rml.wait(); +} + +static +jint Agent_Initialize(JavaVM *jvm, char *options, void *reserved) { + jint res; + jvmtiError err; + jvmtiCapabilities caps; + jvmtiEventCallbacks callbacks; + + printf("Agent_OnLoad started\n"); + + res = jvm->GetEnv((void **)&jvmti, JVMTI_VERSION); + if (res != JNI_OK || jvmti == nullptr) { + printf("Agent_OnLoad: Error in GetEnv: %d\n", res); + return JNI_ERR; + } + + memset(&caps, 0, sizeof(caps)); + caps.can_generate_monitor_events = 1; + err = jvmti->AddCapabilities(&caps); + if (err != JVMTI_ERROR_NONE) { + printf("Agent_OnLoad: Error in JVMTI AddCapabilities: %d\n", err); + return JNI_ERR; + } + + memset(&callbacks, 0, sizeof(callbacks)); + callbacks.MonitorContendedEnter = &MonitorContendedEnter; + err = jvmti->SetEventCallbacks(&callbacks, sizeof(jvmtiEventCallbacks)); + if (err != JVMTI_ERROR_NONE) { + printf("Agent_OnLoad: Error in JVMTI SetEventCallbacks: %d\n", err); + return JNI_ERR; + } + + err = jvmti->SetEventNotificationMode(JVMTI_ENABLE, JVMTI_EVENT_MONITOR_CONTENDED_ENTER, nullptr); + if (err != JVMTI_ERROR_NONE) { + printf("Agent_OnLoad: Error in JVMTI SetEventNotificationMode: %d\n", err); + return JNI_ERR; + } + + err = jvmti->CreateRawMonitor("agent sync monitor", &agent_monitor); + if (err != JVMTI_ERROR_NONE) { + printf("Agent_OnLoad: Error in JVMTI CreateRawMonitor: %d\n", err); + return JNI_ERR; + } + + return JNI_OK; +} + +JNIEXPORT jint JNICALL +Agent_OnLoad(JavaVM *jvm, char *options, void *reserved) { + return Agent_Initialize(jvm, options, reserved); +} + +JNIEXPORT jint JNICALL +Java_DeoptimizedFrame_setupReferences(JNIEnv *jni, jclass cls, jthread vthread, jobject monitor) { + test_vthread = (jthread)jni->NewGlobalRef(vthread); + test_monitor = jni->NewGlobalRef(monitor); + + if (test_vthread == nullptr || test_monitor == nullptr) { + printf("GlobalRef null"); + return JNI_ERR; + } + + return JNI_OK; +} + +JNIEXPORT void JNICALL +Java_DeoptimizedFrame_waitForVThread(JNIEnv *jni, jclass cls) { + RawMonitorLocker rml(jvmti, jni, agent_monitor); + while (!called_contended_enter) { + rml.wait(); + } +} + +JNIEXPORT void JNICALL +Java_DeoptimizedFrame_notifyVThread(JNIEnv *jni, jclass cls) { + RawMonitorLocker rml(jvmti, jni, agent_monitor); + rml.notify_all(); +} + +} // extern "C" \ No newline at end of file diff --git a/test/jdk/javax/accessibility/8380849/AccessibleActionAsSeparateClassTest.java b/test/jdk/javax/accessibility/8380849/AccessibleActionAsSeparateClassTest.java new file mode 100644 index 00000000000..cd3bf6d46c8 --- /dev/null +++ b/test/jdk/javax/accessibility/8380849/AccessibleActionAsSeparateClassTest.java @@ -0,0 +1,137 @@ +/* + * Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * 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 javax.accessibility.Accessible; +import javax.accessibility.AccessibleAction; +import javax.accessibility.AccessibleContext; +import javax.accessibility.AccessibleRole; +import javax.swing.JComponent; +import javax.swing.JFrame; +import javax.swing.SwingUtilities; +import javax.swing.UIManager; +import java.awt.Color; +import java.awt.Dimension; +import java.awt.Graphics; + +/* + * @test + * @key headful + * @bug 8380849 + * @summary manual test for VoiceOver activating an AccessibleAction + * @requires os.family == "mac" + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual AccessibleActionAsSeparateClassTest + */ + +public class AccessibleActionAsSeparateClassTest { + + public static void main(String[] args) throws Exception { + String INSTRUCTIONS = "INSTRUCTIONS:\n" + + "1. Open VoiceOver\n" + + "2. Move the VoiceOver cursor gray circle.\n" + + "3. Press CTRL + ALT + SPACE to click the button.\n\n" + + "Expected behavior: the ellipse should change to green."; + + PassFailJFrame.builder() + .title("AccessibleActionAsSeparateClassTest Instruction") + .instructions(INSTRUCTIONS) + .columns(40) + .testUI(AccessibleActionAsSeparateClassTest::createUI) + .build() + .awaitAndCheck(); + } + + public static JFrame createUI() { + JFrame f = new JFrame(); + f.add(new CustomComponent()); + f.pack(); + f.setVisible(true); + return f; + } + + /** + * This is a custom JComponent that uses AccessibleRole.PUSH_BUTTON. + * Its AccessibleContext identifes an AccessibleAction that is NOT + * the same object as the AccessibleContext. + */ + static class CustomComponent extends JComponent implements Accessible { + boolean clickedSuccessfully = false; + + public CustomComponent() { + setPreferredSize(new Dimension(120, 120)); + } + + @Override + protected void paintComponent(Graphics g) { + g.setColor(clickedSuccessfully ? Color.green : Color.gray); + g.fillOval(0, 0, getWidth(), getHeight()); + } + + @Override + public AccessibleContext getAccessibleContext() { + if (accessibleContext == null) { + accessibleContext = new AccessibleJComponent() { + AccessibleAction action = new AccessibleAction() { + @Override + public int getAccessibleActionCount() { + return 1; + } + + @Override + public String getAccessibleActionDescription(int i) { + if (i == 0) { + return UIManager.getString( + "AbstractButton.clickText"); + } else { + return null; + } + } + + @Override + public boolean doAccessibleAction(int i) { + if (i == 0) { + clickedSuccessfully = true; + repaint(); + return true; + } else { + return false; + } + } + }; + + @Override + public AccessibleRole getAccessibleRole() { + return AccessibleRole.PUSH_BUTTON; + } + + @Override + public AccessibleAction getAccessibleAction() { + return action; + } + }; + } + return accessibleContext; + } + } +} diff --git a/test/jdk/javax/swing/JDesktopPane/TestDesktopManagerNPE.java b/test/jdk/javax/swing/JDesktopPane/TestDesktopManagerNPE.java index 4a5d6329b05..b77fab3bd27 100644 --- a/test/jdk/javax/swing/JDesktopPane/TestDesktopManagerNPE.java +++ b/test/jdk/javax/swing/JDesktopPane/TestDesktopManagerNPE.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -22,11 +22,12 @@ */ /* @test - * @bug 8170794 + * @bug 8170794 8382396 * @key headful * @summary Verifies iconifying internalframe after setting DesktopManager * does not return NPE - * @run main TestDesktopManagerNPE + * @run main TestDesktopManagerNPE + * @run main/othervm -Dswing.volatileImageBufferEnabled=false TestDesktopManagerNPE */ import java.awt.Dimension; @@ -36,10 +37,6 @@ import javax.swing.DefaultDesktopManager; import javax.swing.JInternalFrame; import javax.swing.JDesktopPane; import javax.swing.JFrame; -import javax.swing.JMenu; -import javax.swing.JMenuItem; -import javax.swing.JMenuBar; -import javax.swing.KeyStroke; import javax.swing.SwingUtilities; public class TestDesktopManagerNPE { diff --git a/test/jdk/jdk/jfr/event/gc/detailed/TestShenandoahEvacuationInformationEvent.java b/test/jdk/jdk/jfr/event/gc/detailed/TestShenandoahEvacuationInformationEvent.java index 888ff9eb17a..75fe1ee7884 100644 --- a/test/jdk/jdk/jfr/event/gc/detailed/TestShenandoahEvacuationInformationEvent.java +++ b/test/jdk/jdk/jfr/event/gc/detailed/TestShenandoahEvacuationInformationEvent.java @@ -41,7 +41,7 @@ import jdk.test.lib.jfr.GCHelper; * @requires vm.hasJFR & vm.gc.Shenandoah * @requires vm.flagless * @library /test/lib /test/jdk - * @run main/othervm -Xmx64m -XX:+UnlockExperimentalVMOptions -XX:ShenandoahRegionSize=1m -XX:+UseShenandoahGC -XX:ShenandoahGCMode=generational jdk.jfr.event.gc.detailed.TestShenandoahEvacuationInformationEvent + * @run main/othervm -Xmx64m -XX:+UnlockExperimentalVMOptions -XX:ShenandoahRegionSize=1m -XX:+UseShenandoahGC -XX:ShenandoahGCMode=generational -XX:ShenandoahGenerationalMinPIPUsage=100 -XX:ShenandoahImmediateThreshold=100 jdk.jfr.event.gc.detailed.TestShenandoahEvacuationInformationEvent */ public class TestShenandoahEvacuationInformationEvent { diff --git a/test/jdk/jdk/jfr/event/gc/detailed/TestShenandoahPromotionInformationEvent.java b/test/jdk/jdk/jfr/event/gc/detailed/TestShenandoahPromotionInformationEvent.java index 08a360e14fd..c315694718b 100644 --- a/test/jdk/jdk/jfr/event/gc/detailed/TestShenandoahPromotionInformationEvent.java +++ b/test/jdk/jdk/jfr/event/gc/detailed/TestShenandoahPromotionInformationEvent.java @@ -39,7 +39,7 @@ import jdk.test.lib.jfr.Events; * @requires vm.hasJFR & vm.gc.Shenandoah * @requires vm.flagless * @library /test/lib /test/jdk - * @run main/othervm -Xmx64m -XX:+UnlockExperimentalVMOptions -XX:ShenandoahRegionSize=1m -XX:+UseShenandoahGC -XX:ShenandoahGCMode=generational jdk.jfr.event.gc.detailed.TestShenandoahPromotionInformationEvent + * @run main/othervm -Xmx64m -XX:+UnlockExperimentalVMOptions -XX:ShenandoahRegionSize=1m -XX:+UseShenandoahGC -XX:ShenandoahGCMode=generational -XX:ShenandoahGenerationalMinPIPUsage=100 -XX:ShenandoahImmediateThreshold=100 jdk.jfr.event.gc.detailed.TestShenandoahPromotionInformationEvent */ public class TestShenandoahPromotionInformationEvent { diff --git a/test/jdk/sun/java2d/OpenGL/MultiWindowFillTest.java b/test/jdk/sun/java2d/OpenGL/MultiWindowFillTest.java index 59c58d944d7..302bb43e24a 100644 --- a/test/jdk/sun/java2d/OpenGL/MultiWindowFillTest.java +++ b/test/jdk/sun/java2d/OpenGL/MultiWindowFillTest.java @@ -34,7 +34,7 @@ import javax.imageio.ImageIO; /** * @test - * @bug 8378201 + * @bug 8378201 8378506 * @key headful * @summary Verifies that window content survives a GL context switch to another * window and back diff --git a/test/jdk/sun/net/www/http/HttpClient/IsAvailable.java b/test/jdk/sun/net/www/http/HttpClient/IsAvailable.java index 9e903003f51..65752737c62 100644 --- a/test/jdk/sun/net/www/http/HttpClient/IsAvailable.java +++ b/test/jdk/sun/net/www/http/HttpClient/IsAvailable.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -23,60 +23,210 @@ /* * @test - * @bug 8009650 - * @summary HttpClient available() check throws SocketException when connection - * has been closed + * @bug 8009650 8180483 + * @summary Verifies the `HttpClient::available` behavior against several socket + * states. + * + * A "streaming POST" is controlled by `HttpURLConnection::streaming`, + * which becomes `true` when the caller uses either + * `setFixedLengthStreamingMode()` or `setChunkedStreamingMode()`, and + * *then writes the request body*. Non-streaming mode uses + * `PosterOutputStream.java`, which buffers the body and makes replay + * possible. Whereas, streaming mode allows user to directly write to + * the socket, so the body is not safely replayable. For many ordinary + * (i.e., non-streaming) requests, if a connection reuse fails, the + * stack can often recover by opening a new connection and retrying; + * see the retry logic in `HttpClient`. OTOH, for a "streaming POST", + * retry is dangerous or impossible because the body may already be in + * flight and is not buffered for replay. Hence, + * `HttpClient::available` tries to check whether the cached socket is + * still usable by doing a 1ms `read()`. Though that probe is + * destructive: it can consume and strand one byte from the socket + * input stream. Hence, probe failures should result in removal of the + * connection. + * * @modules java.base/sun.net * java.base/sun.net.www.http:+open * @library /test/lib + * + * @comment `othervm` is required since the `HttpURLConnection` logger state is tainted. + * @run junit/othervm ${test.main.class} */ +import java.io.Closeable; +import java.io.IOException; +import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodHandles; +import java.lang.invoke.MethodType; import java.net.InetAddress; -import java.net.InetSocketAddress; +import java.net.Socket; import java.net.URL; import java.net.ServerSocket; + +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; import sun.net.www.http.HttpClient; -import java.security.*; -import java.lang.reflect.Method; + +import java.util.function.Predicate; +import java.util.logging.ConsoleHandler; +import java.util.logging.Level; +import java.util.logging.Logger; + import jdk.test.lib.net.URIBuilder; -public class IsAvailable { +import static java.nio.charset.StandardCharsets.US_ASCII; +import static jdk.test.lib.Utils.adjustTimeout; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertNotEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; - public static void main(String[] args) throws Exception { - int readTimeout = 20; - ServerSocket ss = new ServerSocket(); - InetAddress loopback = InetAddress.getLoopbackAddress(); - ss.bind(new InetSocketAddress(loopback, 0)); +class IsAvailable { - try (ServerSocket toclose = ss) { + private static final Logger LOGGER = + Logger.getLogger(IsAvailable.class.getCanonicalName()); - URL url1 = URIBuilder.newBuilder() - .scheme("http") - .loopback() - .port(ss.getLocalPort()) - .toURL(); + // Class-level anchor to avoid the `HttpURLConnection` logger getting GC'ed + private static final Logger HUC_LOGGER = + Logger.getLogger("sun.net.www.protocol.http.HttpURLConnection"); - HttpClient c1 = HttpClient.New(url1); + @BeforeAll + static void init() { + increaseLoggerVerbosity(HUC_LOGGER); + } - Method available = HttpClient.class. - getDeclaredMethod("available", null); - available.setAccessible(true); + private static void increaseLoggerVerbosity(Logger logger) { + logger.setLevel(Level.FINEST); + var handler = new ConsoleHandler(); + handler.setLevel(Level.FINEST); + logger.addHandler(handler); + } - c1.setReadTimeout(readTimeout); - boolean a = (boolean) available.invoke(c1); - if (!a) { - throw new RuntimeException("connection should be available"); - } - if (c1.getReadTimeout() != readTimeout) { - throw new RuntimeException("read timeout has been altered"); - } + @Test + void testClosedSocket() throws Exception { + try (var infra = new Infra()) { - c1.closeServer(); + // Obtain the initial read timeout + int readTimeout = infra.readTimeout(); + + // Verify that the just established connection is available + LOGGER.info("Checking the connection (#1)..."); + assertTrue(infra.available(), "Freshly established connection should be available"); + assertEquals(readTimeout, infra.httpClient.getReadTimeout(), "Read-timeout should be restored"); + + // Verify that closing the socket removes the availability + LOGGER.info("Closing the socket..."); + infra.clientSocket.close(); + LOGGER.info("Checking the connection (#2)..."); + assertFalse(infra.available(), "Connection over closed socket should not be available"); + assertEquals(readTimeout, infra.httpClient.getReadTimeout(), "Read-timeout should be restored"); - a = (boolean) available.invoke(c1); - if (a) { - throw new RuntimeException("connection shouldn't be available"); - } } } + + @Test + void testSocketWithUnconsumedData() throws Exception { + try (var infra = new Infra()) { + + // Obtain the initial read timeout + int readTimeout = infra.readTimeout(); + + // Verify that the just established connection is available + LOGGER.info("Checking the connection (#1)..."); + assertTrue(infra.available(), "Freshly established connection should be available"); + assertEquals(readTimeout, infra.httpClient.getReadTimeout(), "Read-timeout should be restored"); + + // Write (unexpected) data to the socket + LOGGER.info("Writing data to the socket..."); + try (var clientSocketOutputStream = infra.clientSocket.getOutputStream()) { + clientSocketOutputStream.write("unexpected data".getBytes(US_ASCII)); + } + + // Writing to the socket on the server side may not make the data + // immediately visible to the client side. Make sure we wait long + // enough for the data to get delivered. + Thread.sleep(adjustTimeout(500)); + + // Verify that the presence of stale data on the socket removes the availability + LOGGER.info("Checking the connection (#2)..."); + assertFalse(infra.available(), "available should be false if it managed to read some data from the socket"); + assertEquals(readTimeout, infra.httpClient.getReadTimeout(), "Read-timeout should be restored"); + + } + } + + private static final class Infra implements Closeable { + + private static final InetAddress LOOPBACK_ADDRESS = InetAddress.getLoopbackAddress(); + + private static final Predicate AVAILABLE_ACCESSOR = findAvailableAccessor(); + + private static Predicate findAvailableAccessor() { + final MethodHandle availableMH; + try { + availableMH = MethodHandles + .privateLookupIn(HttpClient.class, MethodHandles.lookup()) + .findVirtual(HttpClient.class, "available", MethodType.methodType(boolean.class)); + } catch (NoSuchMethodException | IllegalAccessException e) { + throw new RuntimeException(e); + } + return httpClient -> { + try { + return (boolean) availableMH.invoke(httpClient); + } catch (Throwable e) { + throw new RuntimeException(e); + } + }; + } + + private final ServerSocket serverSocket; + + private final HttpClient httpClient; + + private final Socket clientSocket; + + private Infra() throws Exception { + this.serverSocket = new ServerSocket(0, 0, LOOPBACK_ADDRESS); + URL url = URIBuilder.newBuilder() + .scheme("http") + .loopback() + .port(serverSocket.getLocalPort()) + .toURL(); + this.httpClient = HttpClient.New(url); + this.clientSocket = serverSocket.accept(); + } + + private int readTimeout() { + int readTimeout = httpClient.getReadTimeout(); + assertNotEquals( + 1, readTimeout, + "When the read timeout is 1, " + + "we cannot validate whether \"available()\" has restored that value or not, " + + "since \"available()\" temporarily sets it to 1 as well"); + return readTimeout; + } + + private boolean available() { + return AVAILABLE_ACCESSOR.test(httpClient); + } + + @Override + public void close() { + closeQuietly("client socket", clientSocket); + closeQuietly("HttpClient", httpClient::closeServer); + closeQuietly("server socket", serverSocket); + } + + private static void closeQuietly(String name, Closeable closeable) { + if (closeable != null) { + try { + closeable.close(); + } catch (IOException e) { + LOGGER.warning("Failed closing " + name + ": " + e); + } + } + } + + } + } diff --git a/test/jdk/sun/security/krb5/RFC396xTest.java b/test/jdk/sun/security/krb5/RFC396xTest.java index e8f48d7c488..fd011c7f198 100644 --- a/test/jdk/sun/security/krb5/RFC396xTest.java +++ b/test/jdk/sun/security/krb5/RFC396xTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2009, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -52,6 +52,7 @@ public class RFC396xTest { public static void main(String[] args) throws Exception { System.setProperty("sun.security.krb5.msinterop.des.s2kcharset", "utf-8"); + DkCrypto.ALLOW_WEAK_PBKDF2_ITERATION_COUNT = true; test(); } diff --git a/test/jdk/sun/security/krb5/auto/DiffSaltParams.java b/test/jdk/sun/security/krb5/auto/DiffSaltParams.java index e03b4fe5098..04ee2960daa 100644 --- a/test/jdk/sun/security/krb5/auto/DiffSaltParams.java +++ b/test/jdk/sun/security/krb5/auto/DiffSaltParams.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017, 2018, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2017, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -38,11 +38,11 @@ public class DiffSaltParams { OneKDC kdc = new OneKDC(null).writeJAASConf(); kdc.addPrincipal("user1", "user1pass".toCharArray(), - "hello", new byte[]{0, 0, 1, 0}); + "hello", new byte[]{0, 1, 0, 0}); kdc.addPrincipal("user2", "user2pass".toCharArray(), "hello", null); kdc.addPrincipal("user3", "user3pass".toCharArray(), - null, new byte[]{0, 0, 1, 0}); + null, new byte[]{0, 1, 0, 0}); kdc.addPrincipal("user4", "user4pass".toCharArray()); Context.fromUserPass("user1", "user1pass".toCharArray(), true); diff --git a/test/jdk/sun/security/krb5/auto/KDC.java b/test/jdk/sun/security/krb5/auto/KDC.java index 37a4e828469..168a84722c7 100644 --- a/test/jdk/sun/security/krb5/auto/KDC.java +++ b/test/jdk/sun/security/krb5/auto/KDC.java @@ -366,11 +366,12 @@ public class KDC { name.indexOf('/') < 0 ? PrincipalName.KRB_NT_UNKNOWN : PrincipalName.KRB_NT_SRV_HST); - ktab.addEntry(pn, - getSalt(pn), - pass, - kvno, - true); + int[] etypes = EType.getDefaults("default_tkt_enctypes"); + EncryptionKey[] keys = new EncryptionKey[etypes.length]; + for (int i = 0; i < etypes.length; i++) { + keys[i] = keyForUser(pn, etypes[i], false); + } + ktab.addEntry(pn, keys, kvno, true); } else { nativeKdc.ktadd(name, tab); } @@ -671,10 +672,7 @@ public class KDC { */ private char[] getPassword(PrincipalName p, boolean server) throws KrbException { - String pn = p.toString(); - if (p.getRealmString() == null) { - pn = pn + "@" + getRealm(); - } + String pn = nameOf(p); char[] pass = passwords.get(pn); if (pass == null) { throw new KrbException(server? @@ -690,10 +688,7 @@ public class KDC { * @return the salt */ protected String getSalt(PrincipalName p) { - String pn = p.toString(); - if (p.getRealmString() == null) { - pn = pn + "@" + getRealm(); - } + String pn = nameOf(p); if (salts.containsKey(pn)) { return salts.get(pn); } @@ -725,10 +720,7 @@ public class KDC { case EncryptedData.ETYPE_AES256_CTS_HMAC_SHA1_96: case EncryptedData.ETYPE_AES128_CTS_HMAC_SHA256_128: case EncryptedData.ETYPE_AES256_CTS_HMAC_SHA384_192: - String pn = p.toString(); - if (p.getRealmString() == null) { - pn = pn + "@" + getRealm(); - } + String pn = nameOf(p); if (s2kparamses.containsKey(pn)) { return s2kparamses.get(pn); } @@ -742,6 +734,23 @@ public class KDC { } } + /** + * Returns the name of a PrincipalName inside KDC dbs. + * @param p the principal name + * @return the name + */ + private String nameOf(PrincipalName p) { + String pn = p.toString(); + if (p.getRealmString() == null) { + pn = pn + "@" + getRealm(); + } + if (pn.startsWith("krbtgt/")) { + // We always register krbtgt using REALM + pn = "krbtgt/" + pn.substring(7).toUpperCase(Locale.ROOT); + } + return pn; + } + /** * Returns the key for a given principal of the given encryption type * @param p the principal diff --git a/test/jdk/sun/security/krb5/auto/UserIterCount.java b/test/jdk/sun/security/krb5/auto/UserIterCount.java new file mode 100644 index 00000000000..f972e20ee1e --- /dev/null +++ b/test/jdk/sun/security/krb5/auto/UserIterCount.java @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2025, 2026, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * 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 8370615 + * @summary Improve Kerberos credentialing + * @library /test/lib + * @compile -XDignore.symbol.file UserIterCount.java + * @run main jdk.test.lib.FileInstaller TestHosts TestHosts + * @run main/othervm -Djdk.net.hosts.file=TestHosts UserIterCount + */ + +import java.util.HashMap; + +import sun.security.krb5.EncryptionKey; +import sun.security.krb5.KrbException; +import sun.security.krb5.PrincipalName; + +public class UserIterCount { + + static class MyKDC extends OneKDC { + static final HashMap CACHE + = new HashMap<>(); + + public MyKDC() throws Exception { + super(null); + } + + @Override + protected byte[] getParams(PrincipalName p, int etype) { + if (etype == 18) { + if (p.toString().startsWith(OneKDC.USER)) { + return new byte[]{0, 0, 16, 01}; + } else { + return new byte[]{0, 79, (byte)255, (byte)255}; + } + } else { + return super.getParams(p, etype); + } + } + + @Override + EncryptionKey keyForUser(PrincipalName p, int etype, boolean server) + throws KrbException { + var key = p.toString() + etype + server; + var v = CACHE.get(key); + if (v == null) { + v = super.keyForUser(p, etype, server); + CACHE.put(key, v); + } + return v; + } + } + + public static void main(String[] args) throws Exception { + new MyKDC().writeJAASConf(); + Context.fromUserPass(OneKDC.USER, OneKDC.PASS, false); + Context.fromUserPass(OneKDC.USER2, OneKDC.PASS2, false); + } +} diff --git a/test/jdk/sun/security/x509/GeneralName/DNSNameTest.java b/test/jdk/sun/security/x509/GeneralName/DNSNameTest.java index c4905cd5eb1..8b3a2398572 100644 --- a/test/jdk/sun/security/x509/GeneralName/DNSNameTest.java +++ b/test/jdk/sun/security/x509/GeneralName/DNSNameTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -21,132 +21,126 @@ * questions. */ -/** - * @test - * @summary DNSName parsing tests - * @bug 8213952 8186143 - * @modules java.base/sun.security.x509 - * @run testng DNSNameTest - */ +import static jdk.test.lib.Asserts.fail; import java.io.IOException; +import java.net.IDN; +import java.util.List; +import java.util.stream.Stream; import sun.security.x509.DNSName; -import org.testng.annotations.DataProvider; -import org.testng.annotations.Test; - -import static org.testng.Assert.*; +/* + * @test + * @summary DNSName parsing tests + * @bug 8213952 8186143 8381771 + * @library /test/lib + * @modules java.base/sun.security.x509 + * @run main DNSNameTest + */ public class DNSNameTest { - @DataProvider(name = "goodNames") - public Object[][] goodNames() { - Object[][] data = { - {"abc.com"}, - {"ABC.COM"}, - {"a12.com"}, - {"a1b2c3.com"}, - {"1abc.com"}, - {"123.com"}, - {"abc.com-"}, // end with hyphen - {"a-b-c.com"}, // hyphens - }; - return data; + + private static final List GOOD_NAMES = List.of( + "abc", + String.join(".", "a".repeat(63), "b".repeat(63), + "c".repeat(63), "d".repeat(61)), + "abc.com", + "tesT.Abc.com", + "ABC.COM", + "a12.com", + "a1b2c3.com", + "1abc.com", + "123.com", + "a-b-c.com", // hyphens + IDN.toASCII("公司.江利子") // IDN punycode + ); + + private static final List GOOD_SAN_NAMES = Stream.concat( + Stream.of( + "*.domain.com", // wildcard in 1st level subdomain + "*.com"), + GOOD_NAMES.stream()) + .toList(); + + private static final List BAD_NAMES = List.of( + // DNSName too long + String.join(".", "a".repeat(63), "b".repeat(63), + "c".repeat(63), "d".repeat(62)), + // DNSName label too long + "a".repeat(64), + " 1abc.com", // begin with space + "1abc.com ", // end with space + "1a bc.com ", // no space allowed + "-abc.com", // name begins with a hyphen + "abc.com-", // name ends with a hyphen + "abc.-com", // label begins with a hyphen + "abc-.com", // label ends with a hyphen + "a..b", // .. + ".a", // begin with . + "a.", // end with . + "", // empty + " ", // space only + "*.domain.com", // wildcard not allowed + "a*.com" // only allow letter, digit, or hyphen + ); + + private static final List BAD_SAN_NAMES = Stream.concat( + Stream.of( + "*", // wildcard only + "*.", // wildcard with a period + "*a.com", // partial wildcard disallowed + "abc.*.com", // wildcard not allowed in 2nd level + "**.domain.com", // double wildcard not allowed + "*.domain.com*", // can't end with wildcard + "a*.com"), // only allow letter, digit, or hyphen + BAD_NAMES.stream().filter(n -> !n.contains("*"))) + .toList(); + + + public static void main(String[] args) { + GOOD_NAMES.forEach(DNSNameTest::testGoodDNSName); + GOOD_SAN_NAMES.forEach(DNSNameTest::testGoodSanDNSName); + BAD_NAMES.forEach(DNSNameTest::testBadDNSName); + BAD_SAN_NAMES.forEach(DNSNameTest::testBadSanDNSName); } - @DataProvider(name = "goodSanNames") - public Object[][] goodSanNames() { - Object[][] data = { - {"abc.com"}, - {"ABC.COM"}, - {"a12.com"}, - {"a1b2c3.com"}, - {"1abc.com"}, - {"123.com"}, - {"abc.com-"}, // end with hyphen - {"a-b-c.com"}, // hyphens - {"*.domain.com"}, // wildcard in 1st level subdomain - {"*.com"}, - }; - return data; - } - - @DataProvider(name = "badNames") - public Object[][] badNames() { - Object[][] data = { - {" 1abc.com"}, // begin with space - {"1abc.com "}, // end with space - {"1a bc.com "}, // no space allowed - {"-abc.com"}, // begin with hyphen - {"a..b"}, // .. - {".a"}, // begin with . - {"a."}, // end with . - {""}, // empty - {" "}, // space only - {"*.domain.com"}, // wildcard not allowed - {"a*.com"}, // only allow letter, digit, or hyphen - }; - return data; - } - - @DataProvider(name = "badSanNames") - public Object[][] badSanNames() { - Object[][] data = { - {" 1abc.com"}, // begin with space - {"1abc.com "}, // end with space - {"1a bc.com "}, // no space allowed - {"-abc.com"}, // begin with hyphen - {"a..b"}, // .. - {".a"}, // begin with . - {"a."}, // end with . - {""}, // empty - {" "}, // space only - {"*"}, // wildcard only - {"*a.com"}, // partial wildcard disallowed - {"abc.*.com"}, // wildcard not allowed in 2nd level - {"*.*.domain.com"}, // double wildcard not allowed - {"a*.com"}, // only allow letter, digit, or hyphen - }; - return data; - } - - - @Test(dataProvider = "goodNames") - public void testGoodDNSName(String dnsNameString) { + private static void testGoodDNSName(String dnsNameString) { try { DNSName dn = new DNSName(dnsNameString); } catch (IOException e) { - fail("Unexpected IOException"); + fail("Unexpected IOException with input " + dnsNameString + ": " + + e.getMessage()); } } - @Test(dataProvider = "goodSanNames") - public void testGoodSanDNSName(String dnsNameString) { + private static void testGoodSanDNSName(String dnsNameString) { try { DNSName dn = new DNSName(dnsNameString, true); } catch (IOException e) { - fail("Unexpected IOException"); + fail("Unexpected IOException with input " + dnsNameString + ": " + + e.getMessage()); } } - @Test(dataProvider = "badNames") - public void testBadDNSName(String dnsNameString) { + private static void testBadDNSName(String dnsNameString) { try { DNSName dn = new DNSName(dnsNameString); - fail("IOException expected"); + fail("IOException expected with input " + dnsNameString); } catch (IOException e) { - if (!e.getMessage().contains("DNSName")) + if (!e.getMessage().contains("DNSName")) { fail("Unexpected message: " + e); + } } } - @Test(dataProvider = "badSanNames") - public void testBadSanDNSName(String dnsNameString) { + private static void testBadSanDNSName(String dnsNameString) { try { DNSName dn = new DNSName(dnsNameString, true); - fail("IOException expected"); + fail("IOException expected with input " + dnsNameString); } catch (IOException e) { - if (!e.getMessage().contains("DNSName")) + if (!e.getMessage().contains("DNSName")) { fail("Unexpected message: " + e); + } } } } diff --git a/test/jdk/tools/jpackage/helpers-test/jdk/jpackage/test/JPackageCommandTest.java b/test/jdk/tools/jpackage/helpers-test/jdk/jpackage/test/JPackageCommandTest.java index b0d44702d47..9a1aea54ee2 100644 --- a/test/jdk/tools/jpackage/helpers-test/jdk/jpackage/test/JPackageCommandTest.java +++ b/test/jdk/tools/jpackage/helpers-test/jdk/jpackage/test/JPackageCommandTest.java @@ -33,7 +33,6 @@ import java.util.List; import java.util.Objects; import java.util.Optional; import java.util.spi.ToolProvider; -import jdk.jpackage.internal.util.function.ExceptionBox; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.MethodSource; @@ -74,51 +73,45 @@ class JPackageCommandTest extends JUnitAdapter.TestSrcInitializer { void test() { - final Optional global; - switch (globalType) { + final Optional global = switch (globalType) { case SET_CUSTOM_TOOL_PROVIDER -> { - global = Optional.of(createNewToolProvider("jpackage-mock-global")); - JPackageCommand.useToolProviderByDefault(global.get()); + var tp = createNewToolProvider("jpackage-mock-global"); + JPackageCommand.useToolProviderByDefault(tp); + yield Optional.of(tp); } case SET_DEFAULT_TOOL_PROVIDER -> { - global = Optional.of(JavaTool.JPACKAGE.asToolProvider()); JPackageCommand.useToolProviderByDefault(); + yield Optional.of(JavaTool.JPACKAGE.asToolProvider()); } case SET_PROCESS -> { - global = Optional.empty(); JPackageCommand.useExecutableByDefault(); + yield Optional.empty(); } case SET_NONE -> { - global = Optional.empty(); + yield Optional.empty(); } - default -> { - throw ExceptionBox.reachedUnreachable(); - } - } + }; var cmd = new JPackageCommand(); - final Optional instance; - switch (instanceType) { + final Optional instance = switch (instanceType) { case SET_CUSTOM_TOOL_PROVIDER -> { - instance = Optional.of(createNewToolProvider("jpackage-mock")); - cmd.useToolProvider(instance.get()); + var tp = createNewToolProvider("jpackage-mock"); + cmd.useToolProvider(tp); + yield Optional.of(tp); } case SET_DEFAULT_TOOL_PROVIDER -> { - instance = Optional.of(JavaTool.JPACKAGE.asToolProvider()); cmd.useToolProvider(true); + yield Optional.of(JavaTool.JPACKAGE.asToolProvider()); } case SET_PROCESS -> { - instance = Optional.empty(); cmd.useToolProvider(false); + yield Optional.empty(); } case SET_NONE -> { - instance = Optional.empty(); + yield Optional.empty(); } - default -> { - throw ExceptionBox.reachedUnreachable(); - } - } + }; var actual = cmd.createExecutor().getToolProvider(); diff --git a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/JPackageCommand.java b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/JPackageCommand.java index b173d345596..861b717bea0 100644 --- a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/JPackageCommand.java +++ b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/JPackageCommand.java @@ -65,7 +65,6 @@ import jdk.jpackage.internal.model.DottedVersion; import jdk.jpackage.internal.util.MacBundle; import jdk.jpackage.internal.util.Result; import jdk.jpackage.internal.util.RuntimeReleaseFile; -import jdk.jpackage.internal.util.function.ExceptionBox; import jdk.jpackage.internal.util.function.ThrowingConsumer; import jdk.jpackage.internal.util.function.ThrowingFunction; import jdk.jpackage.internal.util.function.ThrowingRunnable; @@ -495,8 +494,7 @@ public class JPackageCommand extends CommandArguments { public static Path createInputRuntimeImage(RuntimeImageType role) { Objects.requireNonNull(role); - final Path runtimeImageDir; - switch (role) { + return switch (role) { case RUNTIME_TYPE_FAKE -> { Consumer createBulkFile = ThrowingConsumer.toConsumer(path -> { @@ -508,7 +506,7 @@ public class JPackageCommand extends CommandArguments { } }); - runtimeImageDir = TKit.createTempDirectory("fake_runtime"); + var runtimeImageDir = TKit.createTempDirectory("fake_runtime"); TKit.trace(String.format("Init fake runtime in [%s] directory", runtimeImageDir)); @@ -521,32 +519,28 @@ public class JPackageCommand extends CommandArguments { // Package bundles with 0KB size are unexpected and considered // an error by PackageTest. createBulkFile.accept(runtimeImageDir.resolve(Path.of("lib", "bulk"))); + + yield runtimeImageDir; } case RUNTIME_TYPE_HELLO_APP -> { - if (JPackageCommand.DEFAULT_RUNTIME_IMAGE != null && !isFakeRuntime(DEFAULT_RUNTIME_IMAGE)) { - runtimeImageDir = JPackageCommand.DEFAULT_RUNTIME_IMAGE; - } else { - runtimeImageDir = TKit.createTempDirectory("runtime-image").resolve("data"); + yield DEFAULT_RUNTIME_IMAGE.filter(Predicate.not(JPackageCommand::isFakeRuntime)).orElseGet(() -> { + var dir = TKit.createTempDirectory("runtime-image").resolve("data"); new Executor().setToolProvider(JavaTool.JLINK) .dumpOutput() .addArguments( - "--output", runtimeImageDir.toString(), + "--output", dir.toString(), "--add-modules", "java.desktop", "--strip-debug", "--no-header-files", "--no-man-pages") .execute(); - } - } - default -> { - throw ExceptionBox.reachedUnreachable(); + return dir; + }); } - } - - return runtimeImageDir; + }; } public JPackageCommand setPackageType(PackageType type) { @@ -868,6 +862,7 @@ public class JPackageCommand extends CommandArguments { } else if (TKit.isLinux()) { criticalRuntimeFiles = LinuxHelper.CRITICAL_RUNTIME_FILES; } else if (TKit.isOSX()) { + runtimeDir = MacBundle.fromPath(runtimeDir).map(MacBundle::homeDir).orElse(runtimeDir); criticalRuntimeFiles = MacHelper.CRITICAL_RUNTIME_FILES; } else { throw TKit.throwUnknownPlatformError(); @@ -972,8 +967,7 @@ public class JPackageCommand extends CommandArguments { } public JPackageCommand ignoreFakeRuntime() { - return ignoreDefaultRuntime(Optional.ofNullable(DEFAULT_RUNTIME_IMAGE) - .map(JPackageCommand::isFakeRuntime).orElse(false)); + return ignoreDefaultRuntime(DEFAULT_RUNTIME_IMAGE.map(JPackageCommand::isFakeRuntime).orElse(false)); } public JPackageCommand ignoreDefaultVerbose(boolean v) { @@ -1801,9 +1795,12 @@ public class JPackageCommand extends CommandArguments { // to allow the jlink process to print exception stacktraces on any failure addArgument("-J-Djlink.debug=true"); } - if (!hasArgument("--runtime-image") && !hasArgument("--jlink-options") && !hasArgument("--app-image") && DEFAULT_RUNTIME_IMAGE != null && !ignoreDefaultRuntime) { - addArguments("--runtime-image", DEFAULT_RUNTIME_IMAGE); - } + + DEFAULT_RUNTIME_IMAGE.filter(_ -> { + return Stream.of("--runtime-image", "--jlink-options", "--app-image").noneMatch(this::hasArgument) && !ignoreDefaultRuntime; + }).ifPresent(defaultRuntime -> { + addArguments("--runtime-image", defaultRuntime); + }); if (!hasArgument("--verbose") && TKit.verboseJPackage() && !ignoreDefaultVerbose) { addArgument("--verbose"); @@ -2015,26 +2012,23 @@ public class JPackageCommand extends CommandArguments { } Optional toolProvider() { - switch (mode) { + return switch (mode) { case USE_PROCESS -> { - return Optional.empty(); + yield Optional.empty(); } case USE_TOOL_PROVIDER -> { if (customToolProvider != null) { - return Optional.of(customToolProvider); + yield Optional.of(customToolProvider); } else { - return TKit.state().findProperty(DefaultToolProviderKey.VALUE).map(ToolProvider.class::cast).or(() -> { + yield TKit.state().findProperty(DefaultToolProviderKey.VALUE).map(ToolProvider.class::cast).or(() -> { return Optional.of(JavaTool.JPACKAGE.asToolProvider()); }); } } case INHERIT_DEFAULTS -> { - return TKit.state().findProperty(DefaultToolProviderKey.VALUE).map(ToolProvider.class::cast); + yield TKit.state().findProperty(DefaultToolProviderKey.VALUE).map(ToolProvider.class::cast); } - default -> { - throw ExceptionBox.reachedUnreachable(); - } - } + }; } ToolProviderSource() { @@ -2088,7 +2082,7 @@ public class JPackageCommand extends CommandArguments { // The value of the property will be automatically appended to // jpackage command line if the command line doesn't have // `--runtime-image` parameter set. - public static final Path DEFAULT_RUNTIME_IMAGE = Optional.ofNullable(TKit.getConfigProperty("runtime-image")).map(Path::of).orElse(null); + private static final Optional DEFAULT_RUNTIME_IMAGE = Optional.ofNullable(TKit.getConfigProperty("runtime-image")).map(Path::of); public static final String DEFAULT_VERSION = "1.0"; diff --git a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/LinuxHelper.java b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/LinuxHelper.java index 66462bedfd7..dc8d79ca841 100644 --- a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/LinuxHelper.java +++ b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/LinuxHelper.java @@ -585,17 +585,14 @@ public final class LinuxHelper { var appLayout = cmd.appLayout(); LauncherShortcut.LINUX_SHORTCUT.expectShortcut(cmd, predefinedAppImage, launcherName).map(shortcutWorkDirType -> { - switch (shortcutWorkDirType) { + return switch (shortcutWorkDirType) { case DEFAULT -> { - return (Path)null; + yield (Path)null; } case APP_DIR -> { - return cmd.pathToPackageFile(appLayout.appDirectory()); + yield cmd.pathToPackageFile(appLayout.appDirectory()); } - default -> { - throw new AssertionError(); - } - } + }; }).map(Path::toString).ifPresentOrElse(shortcutWorkDir -> { var actualShortcutWorkDir = data.find("Path"); TKit.assertTrue(actualShortcutWorkDir.isPresent(), "Check [Path] key exists"); diff --git a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/MacHelper.java b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/MacHelper.java index 4e0d57631b9..1ad0116bda7 100644 --- a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/MacHelper.java +++ b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/MacHelper.java @@ -1340,8 +1340,7 @@ public final class MacHelper { )).map(Path::of).collect(toSet()); } - static final Set CRITICAL_RUNTIME_FILES = Set.of(Path.of( - "Contents/Home/lib/server/libjvm.dylib")); + static final Set CRITICAL_RUNTIME_FILES = Set.of(Path.of("lib/server/libjvm.dylib")); private static final Method getServicePListFileName = initGetServicePListFileName(); diff --git a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/MacSign.java b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/MacSign.java index 81e5da34140..4c7e3872ed4 100644 --- a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/MacSign.java +++ b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/MacSign.java @@ -890,17 +890,14 @@ public final class MacSign { private String validatedCN() { return Optional.ofNullable(subjectCommonName).orElseGet(() -> { - switch (type) { + return switch (type) { case CODE_SIGN -> { - return StandardCertificateNamePrefix.CODE_SIGN.value() + validatedUserName(); + yield StandardCertificateNamePrefix.CODE_SIGN.value() + validatedUserName(); } case INSTALLER -> { - return StandardCertificateNamePrefix.INSTALLER.value() + validatedUserName(); + yield StandardCertificateNamePrefix.INSTALLER.value() + validatedUserName(); } - default -> { - throw new UnsupportedOperationException(); - } - } + }; }); } diff --git a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/WinShortcutVerifier.java b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/WinShortcutVerifier.java index 0e581c1e7dc..b512f16497f 100644 --- a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/WinShortcutVerifier.java +++ b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/WinShortcutVerifier.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -213,17 +213,14 @@ public final class WinShortcutVerifier { final var installDir = Path.of(installRoot.getMsiPropertyName()).resolve(getInstallationSubDirectory(cmd)); final Function workDir = startupDirectory -> { - switch (startupDirectory) { + return switch (startupDirectory) { case DEFAULT -> { - return installDir; + yield installDir; } case APP_DIR -> { - return ApplicationLayout.windowsAppImage().resolveAt(installDir).appDirectory(); + yield ApplicationLayout.windowsAppImage().resolveAt(installDir).appDirectory(); } - default -> { - throw new IllegalArgumentException(); - } - } + }; }; if (winMenu.isPresent()) { diff --git a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/mock/CommandActionSpecs.java b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/mock/CommandActionSpecs.java index ce3aa6f80e1..edead8b5601 100644 --- a/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/mock/CommandActionSpecs.java +++ b/test/jdk/tools/jpackage/helpers/jdk/jpackage/test/mock/CommandActionSpecs.java @@ -133,22 +133,19 @@ public record CommandActionSpecs(List specs) { } public Builder exit(CommandMockExit exit) { - switch (exit) { + return switch (exit) { case SUCCEED -> { - return exit(); + yield exit(); } case EXIT_1 -> { - return exit(1); + yield exit(1); } case THROW_MOCK_IO_EXCEPTION -> { - return action(CommandActionSpec.create("", () -> { + yield action(CommandActionSpec.create("", () -> { throw new MockingToolProvider.RethrowableException(new MockIOException("Kaput!")); })); } - default -> { - throw ExceptionBox.reachedUnreachable(); - } - } + }; } public Builder mutate(Consumer mutator) { diff --git a/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/model/DottedVersionTest.java b/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/model/DottedVersionTest.java index 65f9c71a910..48c3b97c77b 100644 --- a/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/model/DottedVersionTest.java +++ b/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/model/DottedVersionTest.java @@ -66,6 +66,7 @@ public class DottedVersionTest { var dv = cfg.createVersion.apply(cfg.input()); assertEquals(cfg.expectedSuffix(), dv.getUnprocessedSuffix()); assertEquals(cfg.expectedComponentCount(), dv.getComponents().length); + assertEquals(cfg.expectedComponentCount(), dv.getComponentsCount()); assertEquals(cfg.expectedToComponent(), dv.toComponentsString()); assertEquals(dv.toString(), cfg.input()); } diff --git a/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/util/function/ExceptionBoxTest.java b/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/util/function/ExceptionBoxTest.java index d7a6f0e714d..50925d8510d 100644 --- a/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/util/function/ExceptionBoxTest.java +++ b/test/jdk/tools/jpackage/junit/share/jdk.jpackage/jdk/jpackage/internal/util/function/ExceptionBoxTest.java @@ -84,6 +84,17 @@ public class ExceptionBoxTest { assertSame(err, thrown); } + @Test + public void test_unbox_reachedUnreachable() { + var err = new MyThrowable(); + var thrown = assertThrowsExactly(AssertionError.class, () -> { + ExceptionBox.unbox(err); + }); + + assertEquals(ExceptionBox.reachedUnreachable().getMessage(), thrown.getMessage()); + assertNull(thrown.getCause()); + } + @Test public void test_reachedUnreachable() { var err = ExceptionBox.reachedUnreachable(); @@ -320,4 +331,9 @@ public class ExceptionBoxTest { Objects.requireNonNull(format); System.out.println(String.format("[%s]: %s", Thread.currentThread(), String.format(format, args))); } + + private static final class MyThrowable extends Throwable { + + private static final long serialVersionUID = 1L; + } } diff --git a/test/jdk/tools/jpackage/macosx/MacSignTest.java b/test/jdk/tools/jpackage/macosx/MacSignTest.java index dbb78d2416c..67d4258786b 100644 --- a/test/jdk/tools/jpackage/macosx/MacSignTest.java +++ b/test/jdk/tools/jpackage/macosx/MacSignTest.java @@ -35,7 +35,6 @@ import java.util.function.Function; import java.util.function.Predicate; import java.util.regex.Pattern; import java.util.stream.Stream; -import jdk.jpackage.internal.util.function.ExceptionBox; import jdk.jpackage.test.Annotations.Parameter; import jdk.jpackage.test.Annotations.ParameterSupplier; import jdk.jpackage.test.Annotations.Test; @@ -392,25 +391,20 @@ public class MacSignTest { Objects.requireNonNull(keychain); String cmdlinePatternFormat; - String signIdentity; - - switch (option.optionName().orElseThrow()) { + String signIdentity = switch (option.optionName().orElseThrow()) { case KEY_IDENTITY_APP_IMAGE, KEY_USER_NAME -> { cmdlinePatternFormat = "^/usr/bin/codesign -s %s -vvvv --timestamp --options runtime --prefix \\S+ --keychain %s"; if (option.passThrough().orElse(false)) { - signIdentity = String.format("'%s'", option.asCmdlineArgs().getLast()); + yield String.format("'%s'", option.asCmdlineArgs().getLast()); } else { - signIdentity = MacSign.CertificateHash.of(option.certRequest().cert()).toString(); + yield MacSign.CertificateHash.of(option.certRequest().cert()).toString(); } } case KEY_IDENTITY_INSTALLER -> { cmdlinePatternFormat = "^/usr/bin/productbuild --resources \\S+ --sign %s --keychain %s"; - signIdentity = String.format("'%s'", option.asCmdlineArgs().getLast()); + yield String.format("'%s'", option.asCmdlineArgs().getLast()); } - default -> { - throw ExceptionBox.reachedUnreachable(); - } - } + }; return new FailedCommandErrorValidator(Pattern.compile(String.format( cmdlinePatternFormat, diff --git a/test/jdk/tools/jpackage/share/AddLShortcutTest.java b/test/jdk/tools/jpackage/share/AddLShortcutTest.java index ef8f277e267..fcb1c76fd50 100644 --- a/test/jdk/tools/jpackage/share/AddLShortcutTest.java +++ b/test/jdk/tools/jpackage/share/AddLShortcutTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -458,9 +458,6 @@ public class AddLShortcutTest { case DEFAULT -> { cmd.addArgument(shortcut.optionName()); } - default -> { - cmd.addArguments(shortcut.optionName(), value); - } } } diff --git a/test/jdk/tools/jpackage/share/AppVersionTest.java b/test/jdk/tools/jpackage/share/AppVersionTest.java index 2ef7f95398e..ccafd2c7b21 100644 --- a/test/jdk/tools/jpackage/share/AppVersionTest.java +++ b/test/jdk/tools/jpackage/share/AppVersionTest.java @@ -767,6 +767,11 @@ public final class AppVersionTest { AppTestSpec { Objects.requireNonNull(appDesc); Objects.requireNonNull(spec); + spec.findVersionSource(ModuleVersionSource.class).map(ModuleVersionSource::appDesc).ifPresent(moduleAppDesc -> { + if (!moduleAppDesc.equals(appDesc)) { + throw new IllegalArgumentException(); + } + }); } AppTestSpec(TestSpec spec) { diff --git a/test/jdk/tools/jpackage/share/ErrorTest.java b/test/jdk/tools/jpackage/share/ErrorTest.java index ba0f5663d45..a370b755dc4 100644 --- a/test/jdk/tools/jpackage/share/ErrorTest.java +++ b/test/jdk/tools/jpackage/share/ErrorTest.java @@ -873,20 +873,16 @@ public final class ErrorTest { for (var withAppImage : List.of(true, false)) { for (var existingCertType : CertificateType.values()) { Token keychain; - StandardCertificateNamePrefix missingCertificateNamePrefix; - switch (existingCertType) { + StandardCertificateNamePrefix missingCertificateNamePrefix = switch (existingCertType) { case INSTALLER -> { keychain = Token.KEYCHAIN_WITH_PKG_CERT; - missingCertificateNamePrefix = StandardCertificateNamePrefix.CODE_SIGN; + yield StandardCertificateNamePrefix.CODE_SIGN; } case CODE_SIGN -> { keychain = Token.KEYCHAIN_WITH_APP_IMAGE_CERT; - missingCertificateNamePrefix = StandardCertificateNamePrefix.INSTALLER; + yield StandardCertificateNamePrefix.INSTALLER; } - default -> { - throw new AssertionError(); - } - } + }; var builder = testSpec() .type(PackageType.MAC_PKG) diff --git a/test/jdk/tools/jpackage/share/ModularAppTest.java b/test/jdk/tools/jpackage/share/ModularAppTest.java index b14d70cc8f3..d28753b4746 100644 --- a/test/jdk/tools/jpackage/share/ModularAppTest.java +++ b/test/jdk/tools/jpackage/share/ModularAppTest.java @@ -152,10 +152,9 @@ public final class ModularAppTest { HelloApp.createBundle(appDesc, moduleOutputDir); final var workDir = TKit.createTempDirectory("runtime").resolve("data"); - final Path jlinkOutputDir; - switch (runtimeType) { + final Path jlinkOutputDir = switch (runtimeType) { case IMAGE -> { - jlinkOutputDir = workDir; + yield workDir; } case MAC_BUNDLE -> { var macBundle = new MacBundle(workDir); @@ -164,12 +163,9 @@ public final class ModularAppTest { Files.createDirectories(macBundle.homeDir().getParent()); Files.createDirectories(macBundle.macOsDir()); Files.createFile(macBundle.infoPlistFile()); - jlinkOutputDir = macBundle.homeDir(); + yield macBundle.homeDir(); } - default -> { - throw new AssertionError(); - } - } + }; // List of modules required for the test app. final var modules = new String[] { @@ -264,9 +260,6 @@ public final class ModularAppTest { case NON_EXISTING_DIR -> { yield nonExistingDir; } - default -> { - throw new AssertionError(); - } }).get(); }); }).mapMulti((path, acc) -> { diff --git a/test/jdk/tools/jpackage/share/RuntimeImageTest.java b/test/jdk/tools/jpackage/share/RuntimeImageTest.java index f5811596f75..5c2f5beb731 100644 --- a/test/jdk/tools/jpackage/share/RuntimeImageTest.java +++ b/test/jdk/tools/jpackage/share/RuntimeImageTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -21,13 +21,13 @@ * questions. */ +import static jdk.jpackage.test.JPackageCommand.RuntimeImageType.RUNTIME_TYPE_HELLO_APP; + import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; import jdk.jpackage.test.Annotations.Test; -import jdk.jpackage.test.Executor; import jdk.jpackage.test.JPackageCommand; -import jdk.jpackage.test.JavaTool; import jdk.jpackage.test.TKit; /* @@ -44,30 +44,9 @@ public class RuntimeImageTest { @Test public static void test() throws IOException { - - JPackageCommand cmd = JPackageCommand.helloAppImage(); - - if (JPackageCommand.DEFAULT_RUNTIME_IMAGE == null) { - final Path workDir = TKit.createTempDirectory("runtime").resolve("data"); - final Path jlinkOutputDir = workDir.resolve("temp.runtime"); - Files.createDirectories(jlinkOutputDir.getParent()); - - new Executor() - .setToolProvider(JavaTool.JLINK) - .dumpOutput() - .addArguments( - "--output", jlinkOutputDir.toString(), - "--add-modules", "java.desktop", - "--strip-debug", - "--no-header-files", - "--no-man-pages", - "--strip-native-commands") - .execute(); - - cmd.setArgumentValue("--runtime-image", jlinkOutputDir.toString()); - } - - cmd.executeAndAssertHelloAppImageCreated(); + JPackageCommand.helloAppImage() + .setArgumentValue("--runtime-image", JPackageCommand.createInputRuntimeImage(RUNTIME_TYPE_HELLO_APP)) + .executeAndAssertHelloAppImageCreated(); } @Test diff --git a/test/langtools/ProblemList-StaticJdk.txt b/test/langtools/ProblemList-StaticJdk.txt index 700099656e8..fc3f2226100 100644 --- a/test/langtools/ProblemList-StaticJdk.txt +++ b/test/langtools/ProblemList-StaticJdk.txt @@ -30,10 +30,14 @@ # Preview project specific failures go here at the end of the file. # # These are NOT failures that occur with the '--enable-preview' option -# specified; those go in the appropriate ProblemList-enable-preview.txt file. +# specified in the task definition; those go in the appropriate +# ProblemList-enable-preview.txt file. +# # These are failures that occur WITHOUT the '--enable-preview' option -# specified AND occur because of some issue with preview project code, -# in either implementation or test code. +# specified in the task definition OR the '--enable-preview' option +# MAY BE specified in the test itself. In either case, the failure +# occurs because of some issue with preview project code, in either +# implementation or test code. ############################################################################# diff --git a/test/langtools/ProblemList-enable-preview.txt b/test/langtools/ProblemList-enable-preview.txt index 1a831a0dde3..b28670c9839 100644 --- a/test/langtools/ProblemList-enable-preview.txt +++ b/test/langtools/ProblemList-enable-preview.txt @@ -23,10 +23,13 @@ ############################################################################# # -# List of quarantined tests for testing with --enable-preview +# List of quarantined tests for testing with the '--enable-preview' option +# where the option IS specified in the task definition and NOT in the test. # -# These are failures that ONLY occur with the '--enable-preview' option -# specified. There are separate sub-sections for each preview project. +# If the '--enable-preview' option is NOT specified in the task definition, +# and the option IS specified in the test, then an entry here WILL NOT work. +# +# There are separate sub-sections for each preview project. # ############################################################################# diff --git a/test/langtools/ProblemList.txt b/test/langtools/ProblemList.txt index 07ab6937c07..6734464e723 100644 --- a/test/langtools/ProblemList.txt +++ b/test/langtools/ProblemList.txt @@ -77,10 +77,14 @@ tools/javap/output/RepeatingTypeAnnotations.java # Preview project specific failures go here at the end of the file. # # These are NOT failures that occur with the '--enable-preview' option -# specified; those go in the appropriate ProblemList-enable-preview.txt file. +# specified in the task definition; those go in the appropriate +# ProblemList-enable-preview.txt file. +# # These are failures that occur WITHOUT the '--enable-preview' option -# specified AND occur because of some issue with preview project code, -# in either implementation or test code. +# specified in the task definition OR the '--enable-preview' option +# MAY BE specified in the test itself. In either case, the failure +# occurs because of some issue with preview project code, in either +# implementation or test code. ############################################################################# diff --git a/test/langtools/tools/javac/Diagnostics/compressed/IncompatibleArgTypesInLambda.java b/test/langtools/tools/javac/Diagnostics/compressed/IncompatibleArgTypesInLambda.java new file mode 100644 index 00000000000..29c0c50f4d8 --- /dev/null +++ b/test/langtools/tools/javac/Diagnostics/compressed/IncompatibleArgTypesInLambda.java @@ -0,0 +1,112 @@ +/* + * Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * 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 8381642 + * @summary IncompatibleArgTypesInLambda error reported at wrong position + * @library /tools/lib + * @modules + * jdk.compiler/com.sun.tools.javac.api + * jdk.compiler/com.sun.tools.javac.main + * @build toolbox.ToolBox toolbox.JavacTask + * @run junit ${test.main.class} + */ + +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.List; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestInfo; +import toolbox.JavacTask; +import toolbox.Task; +import toolbox.ToolBox; + +public class IncompatibleArgTypesInLambda { + + private static String SOURCE = """ + import java.util.function.Supplier; + import javax.swing.JButton; + + public class Test { + + public void test(Supplier sup) { + JButton button = new JButton("test"); + button.addActionListener(() -> { + String s = (sup != null) + ? sup.get() + : ""; + IO.println(s); + }); + } + } + """; + + private Path base; + private ToolBox tb = new ToolBox(); + + @Test + public void testCompactDiags() throws Exception { + Path classes = base.resolve("classes"); + Files.createDirectories(classes); + List log = new JavacTask(tb) + .options("-d", classes.toString(), "-XDrawDiagnostics", "-Xdiags:compact") + .sources(SOURCE) + .run(Task.Expect.FAIL) + .writeAll() + .getOutputLines(Task.OutputKind.DIRECT); + List expected = List.of( + "Test.java:8:34: compiler.err.prob.found.req: (compiler.misc.wrong.number.args.in.lambda: java.awt.event.ActionListener)", + "- compiler.note.compressed.diags", + "1 error" + ); + tb.checkEqual(expected, log); + } + + @Test + public void testVerboseDiags() throws Exception { + Path classes = base.resolve("classes"); + Files.createDirectories(classes); + List log = new JavacTask(tb) + .options("-d", classes.toString(), "-XDrawDiagnostics", "-Xdiags:verbose") + .sources(SOURCE) + .run(Task.Expect.FAIL) + .writeAll() + .getOutputLines(Task.OutputKind.DIRECT); + List expected = List.of( + "Test.java:8:15: compiler.err.cant.apply.symbol: kindname.method, addActionListener, java.awt.event.ActionListener, @34, kindname.class, javax.swing.AbstractButton, (compiler.misc.no.conforming.assignment.exists: (compiler.misc.wrong.number.args.in.lambda: java.awt.event.ActionListener))", + "1 error" + ); + tb.checkEqual(expected, log); + } + + @BeforeEach + public void setUp(TestInfo info) { + base = Paths.get(".") + .resolve(info.getTestMethod() + .orElseThrow() + .getName()); + } +} diff --git a/test/langtools/tools/javac/T8024207/FlowCrashTest.out b/test/langtools/tools/javac/T8024207/FlowCrashTest.out index 2b89e8d9d80..002b68027f7 100644 --- a/test/langtools/tools/javac/T8024207/FlowCrashTest.out +++ b/test/langtools/tools/javac/T8024207/FlowCrashTest.out @@ -1,2 +1,2 @@ -FlowCrashTest.java:18:42: compiler.err.cant.apply.symbols: kindname.method, toMap, @49,@19:49,@20:49,{(compiler.misc.inapplicable.method: kindname.method, java.util.stream.Collectors, toMap(java.util.function.Function,java.util.function.Function), (compiler.misc.infer.arg.length.mismatch: T,K,U)),(compiler.misc.inapplicable.method: kindname.method, java.util.stream.Collectors, toMap(java.util.function.Function,java.util.function.Function,java.util.function.BinaryOperator), (compiler.misc.infer.no.conforming.assignment.exists: T,K,U, (compiler.misc.incompatible.arg.types.in.lambda))),(compiler.misc.inapplicable.method: kindname.method, java.util.stream.Collectors, toMap(java.util.function.Function,java.util.function.Function,java.util.function.BinaryOperator,java.util.function.Supplier), (compiler.misc.infer.arg.length.mismatch: T,K,U,M))} +FlowCrashTest.java:18:42: compiler.err.cant.apply.symbols: kindname.method, toMap, @49,@19:49,@20:49,{(compiler.misc.inapplicable.method: kindname.method, java.util.stream.Collectors, toMap(java.util.function.Function,java.util.function.Function), (compiler.misc.infer.arg.length.mismatch: T,K,U)),(compiler.misc.inapplicable.method: kindname.method, java.util.stream.Collectors, toMap(java.util.function.Function,java.util.function.Function,java.util.function.BinaryOperator), (compiler.misc.infer.no.conforming.assignment.exists: T,K,U, (compiler.misc.wrong.number.args.in.lambda: java.util.function.Function))),(compiler.misc.inapplicable.method: kindname.method, java.util.stream.Collectors, toMap(java.util.function.Function,java.util.function.Function,java.util.function.BinaryOperator,java.util.function.Supplier), (compiler.misc.infer.arg.length.mismatch: T,K,U,M))} 1 error diff --git a/test/langtools/tools/javac/annotations/typeAnnotations/TypeAnnotatedCastsInFieldGroup.java b/test/langtools/tools/javac/annotations/typeAnnotations/TypeAnnotatedCastsInFieldGroup.java new file mode 100644 index 00000000000..337b23efbe8 --- /dev/null +++ b/test/langtools/tools/javac/annotations/typeAnnotations/TypeAnnotatedCastsInFieldGroup.java @@ -0,0 +1,78 @@ +/* + * Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * 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 8381739 + * @summary Verify comma-separated field declarations with type-annotated casts + * @library /tools/lib + * @modules + * jdk.compiler/com.sun.tools.javac.api + * jdk.compiler/com.sun.tools.javac.main + * @build toolbox.ToolBox toolbox.JavacTask + * @run junit ${test.main.class} + */ + +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestInfo; +import toolbox.JavacTask; +import toolbox.ToolBox; + +public class TypeAnnotatedCastsInFieldGroup { + + private Path base; + private ToolBox tb = new ToolBox(); + + @Test + public void testCompactDiags() throws Exception { + Path classes = base.resolve("classes"); + Files.createDirectories(classes); + new JavacTask(tb) + .options("-d", classes.toString(), "-XDrawDiagnostics", "-Xdiags:compact") + .sources(""" + import java.lang.annotation.ElementType; + import java.lang.annotation.Target; + + class Test { + int x = (@A int) 0, y = (@A int) 1; + } + + @Target({ElementType.TYPE_USE}) + @interface A {} + """) + .run() + .writeAll(); + } + + @BeforeEach + public void setUp(TestInfo info) { + base = Paths.get(".") + .resolve(info.getTestMethod() + .orElseThrow() + .getName()); + } +} diff --git a/test/langtools/tools/javac/diags/examples/WrongNumberArgsInLambda.java b/test/langtools/tools/javac/diags/examples/WrongNumberArgsInLambda.java new file mode 100644 index 00000000000..05c17dcfb03 --- /dev/null +++ b/test/langtools/tools/javac/diags/examples/WrongNumberArgsInLambda.java @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * 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. + */ + +// key: compiler.err.cant.apply.symbol +// key: compiler.misc.no.conforming.assignment.exists +// key: compiler.misc.wrong.number.args.in.lambda + +class WrongNumberArgsInLambda { + interface SAM { + void m(Integer x); + } + void op(SAM s) {} + void test() { + op((x, y) -> {}); + } +} diff --git a/test/langtools/tools/javac/lambda/8202372/T8202372.out b/test/langtools/tools/javac/lambda/8202372/T8202372.out index 368fe8bd808..6c4e199e19b 100644 --- a/test/langtools/tools/javac/lambda/8202372/T8202372.out +++ b/test/langtools/tools/javac/lambda/8202372/T8202372.out @@ -2,7 +2,7 @@ T8202372.java:26:13: compiler.err.cant.apply.symbol: kindname.method, addVoid, T T8202372.java:27:13: compiler.err.cant.apply.symbol: kindname.method, addVoid, T8202372.VoidFunc, @22, kindname.class, T8202372, (compiler.misc.no.conforming.assignment.exists: (compiler.misc.incompatible.ret.type.in.lambda: (compiler.misc.unexpected.ret.val))) T8202372.java:35:13: compiler.err.cant.apply.symbol: kindname.method, addNonVoid, T8202372.NonVoidFunc, @25, kindname.class, T8202372, (compiler.misc.no.conforming.assignment.exists: (compiler.misc.incompatible.ret.type.in.lambda: (compiler.misc.missing.ret.val: java.lang.String))) T8202372.java:36:13: compiler.err.cant.apply.symbol: kindname.method, addNonVoid, T8202372.NonVoidFunc, @25, kindname.class, T8202372, (compiler.misc.no.conforming.assignment.exists: (compiler.misc.incompatible.ret.type.in.lambda: (compiler.misc.missing.ret.val))) -T8202372.java:40:13: compiler.err.cant.apply.symbol: kindname.method, addParam, T8202372.ParamFunc, @23, kindname.class, T8202372, (compiler.misc.no.conforming.assignment.exists: (compiler.misc.incompatible.arg.types.in.lambda)) -T8202372.java:42:13: compiler.err.cant.apply.symbol: kindname.method, addParam, T8202372.ParamFunc, @23, kindname.class, T8202372, (compiler.misc.no.conforming.assignment.exists: (compiler.misc.incompatible.arg.types.in.lambda)) -T8202372.java:43:13: compiler.err.cant.apply.symbol: kindname.method, addParam, T8202372.ParamFunc, @23, kindname.class, T8202372, (compiler.misc.no.conforming.assignment.exists: (compiler.misc.incompatible.arg.types.in.lambda)) +T8202372.java:40:13: compiler.err.cant.apply.symbol: kindname.method, addParam, T8202372.ParamFunc, @23, kindname.class, T8202372, (compiler.misc.no.conforming.assignment.exists: (compiler.misc.wrong.number.args.in.lambda: T8202372.ParamFunc)) +T8202372.java:42:13: compiler.err.cant.apply.symbol: kindname.method, addParam, T8202372.ParamFunc, @23, kindname.class, T8202372, (compiler.misc.no.conforming.assignment.exists: (compiler.misc.wrong.number.args.in.lambda: T8202372.ParamFunc)) +T8202372.java:43:13: compiler.err.cant.apply.symbol: kindname.method, addParam, T8202372.ParamFunc, @23, kindname.class, T8202372, (compiler.misc.no.conforming.assignment.exists: (compiler.misc.incompatible.arg.types.in.lambda: java.lang.String, int)) 7 errors diff --git a/test/langtools/tools/javac/lambda/BadNestedLambda.out b/test/langtools/tools/javac/lambda/BadNestedLambda.out index 268ad85aa81..98dc8fedfd7 100644 --- a/test/langtools/tools/javac/lambda/BadNestedLambda.out +++ b/test/langtools/tools/javac/lambda/BadNestedLambda.out @@ -1,3 +1,3 @@ BadNestedLambda.java:9:35: compiler.err.prob.found.req: (compiler.misc.incompatible.ret.type.in.lambda: (compiler.misc.not.a.functional.intf: void)) -BadNestedLambda.java:9:24: compiler.err.prob.found.req: (compiler.misc.incompatible.arg.types.in.lambda) +BadNestedLambda.java:9:24: compiler.err.prob.found.req: (compiler.misc.wrong.number.args.in.lambda: java.lang.Runnable) 2 errors diff --git a/test/langtools/tools/javac/lambda/BadRecovery.out b/test/langtools/tools/javac/lambda/BadRecovery.out index e604ca167b7..872de721f45 100644 --- a/test/langtools/tools/javac/lambda/BadRecovery.out +++ b/test/langtools/tools/javac/lambda/BadRecovery.out @@ -1,4 +1,4 @@ -BadRecovery.java:17:9: compiler.err.cant.apply.symbol: kindname.method, m, BadRecovery.SAM1, @11, kindname.class, BadRecovery, (compiler.misc.no.conforming.assignment.exists: (compiler.misc.incompatible.arg.types.in.lambda)) +BadRecovery.java:17:9: compiler.err.cant.apply.symbol: kindname.method, m, BadRecovery.SAM1, @11, kindname.class, BadRecovery, (compiler.misc.no.conforming.assignment.exists: (compiler.misc.wrong.number.args.in.lambda: BadRecovery.SAM1)) BadRecovery.java:17:38: compiler.err.cant.resolve.location.args: kindname.method, someMemberOfReceiver, , @60, (compiler.misc.location.1: kindname.variable, receiver, java.lang.Object) BadRecovery.java:17:77: compiler.err.cant.resolve.location: kindname.variable, f, , , (compiler.misc.location: kindname.class, BadRecovery, null) 3 errors diff --git a/test/langtools/tools/javac/lambda/LambdaConv10.out b/test/langtools/tools/javac/lambda/LambdaConv10.out index 0f58e5e4054..f12eb9799ec 100644 --- a/test/langtools/tools/javac/lambda/LambdaConv10.out +++ b/test/langtools/tools/javac/lambda/LambdaConv10.out @@ -1,2 +1,2 @@ -LambdaConv10.java:15:39: compiler.err.prob.found.req: (compiler.misc.incompatible.arg.types.in.lambda) +LambdaConv10.java:15:39: compiler.err.prob.found.req: (compiler.misc.incompatible.arg.types.in.lambda: java.lang.Integer, int) 1 error diff --git a/test/langtools/tools/javac/lambda/TargetType44.out b/test/langtools/tools/javac/lambda/TargetType44.out index 18bf4f7937d..8994936d0ec 100644 --- a/test/langtools/tools/javac/lambda/TargetType44.out +++ b/test/langtools/tools/javac/lambda/TargetType44.out @@ -1,3 +1,3 @@ -TargetType44.java:22:9: compiler.err.cant.apply.symbols: kindname.method, m, @11,{(compiler.misc.inapplicable.method: kindname.method, TargetType44, m(TargetType44.Unary), (compiler.misc.no.conforming.assignment.exists: (compiler.misc.incompatible.arg.types.in.lambda))),(compiler.misc.inapplicable.method: kindname.method, TargetType44, m(TargetType44.Binary), (compiler.misc.no.conforming.assignment.exists: (compiler.misc.incompatible.arg.types.in.lambda)))} -TargetType44.java:25:9: compiler.err.cant.apply.symbols: kindname.method, m, @11,{(compiler.misc.inapplicable.method: kindname.method, TargetType44, m(TargetType44.Unary), (compiler.misc.no.conforming.assignment.exists: (compiler.misc.incompatible.arg.types.in.lambda))),(compiler.misc.inapplicable.method: kindname.method, TargetType44, m(TargetType44.Binary), (compiler.misc.no.conforming.assignment.exists: (compiler.misc.incompatible.arg.types.in.lambda)))} +TargetType44.java:22:9: compiler.err.cant.apply.symbols: kindname.method, m, @11,{(compiler.misc.inapplicable.method: kindname.method, TargetType44, m(TargetType44.Unary), (compiler.misc.no.conforming.assignment.exists: (compiler.misc.wrong.number.args.in.lambda: TargetType44.Unary))),(compiler.misc.inapplicable.method: kindname.method, TargetType44, m(TargetType44.Binary), (compiler.misc.no.conforming.assignment.exists: (compiler.misc.wrong.number.args.in.lambda: TargetType44.Binary)))} +TargetType44.java:25:9: compiler.err.cant.apply.symbols: kindname.method, m, @11,{(compiler.misc.inapplicable.method: kindname.method, TargetType44, m(TargetType44.Unary), (compiler.misc.no.conforming.assignment.exists: (compiler.misc.wrong.number.args.in.lambda: TargetType44.Unary))),(compiler.misc.inapplicable.method: kindname.method, TargetType44, m(TargetType44.Binary), (compiler.misc.no.conforming.assignment.exists: (compiler.misc.wrong.number.args.in.lambda: TargetType44.Binary)))} 2 errors diff --git a/test/langtools/tools/javac/lambda/VoidLambdaParameter.out b/test/langtools/tools/javac/lambda/VoidLambdaParameter.out index 5823c894bc4..90c001bcf12 100644 --- a/test/langtools/tools/javac/lambda/VoidLambdaParameter.out +++ b/test/langtools/tools/javac/lambda/VoidLambdaParameter.out @@ -1,5 +1,5 @@ VoidLambdaParameter.java:7:19: compiler.err.void.not.allowed.here -VoidLambdaParameter.java:7:18: compiler.err.prob.found.req: (compiler.misc.incompatible.arg.types.in.lambda) +VoidLambdaParameter.java:7:18: compiler.err.prob.found.req: (compiler.misc.wrong.number.args.in.lambda: java.lang.Runnable) VoidLambdaParameter.java:8:12: compiler.err.void.not.allowed.here VoidLambdaParameter.java:10:23: compiler.err.void.not.allowed.here 4 errors diff --git a/test/langtools/tools/javac/lambda/lambdaExpression/InvalidExpression4.out b/test/langtools/tools/javac/lambda/lambdaExpression/InvalidExpression4.out index 03831725452..21a26fb9e7a 100644 --- a/test/langtools/tools/javac/lambda/lambdaExpression/InvalidExpression4.out +++ b/test/langtools/tools/javac/lambda/lambdaExpression/InvalidExpression4.out @@ -1,2 +1,2 @@ -InvalidExpression4.java:16:17: compiler.err.prob.found.req: (compiler.misc.incompatible.arg.types.in.lambda) +InvalidExpression4.java:16:17: compiler.err.prob.found.req: (compiler.misc.incompatible.arg.types.in.lambda: int, java.lang.Integer) 1 error diff --git a/test/langtools/tools/javac/warnings/DeprecatedNoEffect.java b/test/langtools/tools/javac/warnings/DeprecatedNoEffect.java new file mode 100644 index 00000000000..b2c8a10c0ac --- /dev/null +++ b/test/langtools/tools/javac/warnings/DeprecatedNoEffect.java @@ -0,0 +1,14 @@ +/* + * @test /nodynamiccopyright/ + * @bug 8382368 + * @compile/ref=DeprecatedNoEffect.out -Xlint:deprecation -XDrawDiagnostics DeprecatedNoEffect.java + */ +public class DeprecatedNoEffect { + void m1() { + @Deprecated int i1; // there should be a "has no effect" warning here + } + @Deprecated + void m2() { + @Deprecated int i2; // there should be a "has no effect" warning here also + } +} diff --git a/test/langtools/tools/javac/warnings/DeprecatedNoEffect.out b/test/langtools/tools/javac/warnings/DeprecatedNoEffect.out new file mode 100644 index 00000000000..55003e62fb8 --- /dev/null +++ b/test/langtools/tools/javac/warnings/DeprecatedNoEffect.out @@ -0,0 +1,3 @@ +DeprecatedNoEffect.java:8:21: compiler.warn.deprecated.annotation.has.no.effect: kindname.variable +DeprecatedNoEffect.java:12:21: compiler.warn.deprecated.annotation.has.no.effect: kindname.variable +2 warnings diff --git a/test/langtools/tools/javac/warnings/WerrorLint2.fail1.out b/test/langtools/tools/javac/warnings/WerrorLint2.fail1.out new file mode 100644 index 00000000000..1b0497dfcb0 --- /dev/null +++ b/test/langtools/tools/javac/warnings/WerrorLint2.fail1.out @@ -0,0 +1,4 @@ +WerrorLint2.java:16:30: compiler.warn.empty.if +- compiler.err.warnings.and.werror +1 error +1 warning diff --git a/test/langtools/tools/javac/warnings/WerrorLint2.fail2.out b/test/langtools/tools/javac/warnings/WerrorLint2.fail2.out new file mode 100644 index 00000000000..3977e6318ef --- /dev/null +++ b/test/langtools/tools/javac/warnings/WerrorLint2.fail2.out @@ -0,0 +1,5 @@ +WerrorLint2.java:16:30: compiler.warn.empty.if +WerrorLint2.java:17:28: compiler.warn.diamond.redundant.args +- compiler.err.warnings.and.werror +1 error +2 warnings diff --git a/test/langtools/tools/javac/warnings/WerrorLint2.java b/test/langtools/tools/javac/warnings/WerrorLint2.java new file mode 100644 index 00000000000..c2ec7d370d9 --- /dev/null +++ b/test/langtools/tools/javac/warnings/WerrorLint2.java @@ -0,0 +1,19 @@ +/* + * @test /nodynamiccopyright/ + * @bug 8380971 + * + * @compile/fail/ref=WerrorLint2.fail1.out -XDrawDiagnostics -Xlint:all -Werror:all WerrorLint2.java + * @compile/ref=WerrorLint2.warn1.out -XDrawDiagnostics -Xlint:all -Werror:all,-empty WerrorLint2.java + * @compile/ref=WerrorLint2.warn1.out -XDrawDiagnostics -Xlint:all -Werror:-empty WerrorLint2.java + * @compile/fail/ref=WerrorLint2.fail1.out -XDrawDiagnostics -Xlint:all -XDfind=diamond -Werror:all WerrorLint2.java + * @compile/fail/ref=WerrorLint2.fail2.out -XDrawDiagnostics -Xlint:all -XDfind=diamond -Werror:all,-empty WerrorLint2.java + * @compile/ref=WerrorLint2.warn2.out -XDrawDiagnostics -Xlint:all -XDfind=diamond -Werror:-empty WerrorLint2.java + */ + +class WerrorLint2 { + ThreadLocal t; + void m() { + if (hashCode() == 1) ; // warning: [empty] empty statement after if + t = new ThreadLocal(); // warning: Redundant type arguments in new expression (use diamond operator instead). + } +} diff --git a/test/langtools/tools/javac/warnings/WerrorLint2.warn1.out b/test/langtools/tools/javac/warnings/WerrorLint2.warn1.out new file mode 100644 index 00000000000..91aff9bb948 --- /dev/null +++ b/test/langtools/tools/javac/warnings/WerrorLint2.warn1.out @@ -0,0 +1,2 @@ +WerrorLint2.java:16:30: compiler.warn.empty.if +1 warning diff --git a/test/langtools/tools/javac/warnings/WerrorLint2.warn2.out b/test/langtools/tools/javac/warnings/WerrorLint2.warn2.out new file mode 100644 index 00000000000..c271a489813 --- /dev/null +++ b/test/langtools/tools/javac/warnings/WerrorLint2.warn2.out @@ -0,0 +1,3 @@ +WerrorLint2.java:16:30: compiler.warn.empty.if +WerrorLint2.java:17:28: compiler.warn.diamond.redundant.args +2 warnings diff --git a/test/lib-test/ProblemList-StaticJdk.txt b/test/lib-test/ProblemList-StaticJdk.txt index 700099656e8..fc3f2226100 100644 --- a/test/lib-test/ProblemList-StaticJdk.txt +++ b/test/lib-test/ProblemList-StaticJdk.txt @@ -30,10 +30,14 @@ # Preview project specific failures go here at the end of the file. # # These are NOT failures that occur with the '--enable-preview' option -# specified; those go in the appropriate ProblemList-enable-preview.txt file. +# specified in the task definition; those go in the appropriate +# ProblemList-enable-preview.txt file. +# # These are failures that occur WITHOUT the '--enable-preview' option -# specified AND occur because of some issue with preview project code, -# in either implementation or test code. +# specified in the task definition OR the '--enable-preview' option +# MAY BE specified in the test itself. In either case, the failure +# occurs because of some issue with preview project code, in either +# implementation or test code. ############################################################################# diff --git a/test/lib-test/ProblemList.txt b/test/lib-test/ProblemList.txt index 2a5caedc8d8..6598210d4eb 100644 --- a/test/lib-test/ProblemList.txt +++ b/test/lib-test/ProblemList.txt @@ -43,10 +43,14 @@ # Preview project specific failures go here at the end of the file. # # These are NOT failures that occur with the '--enable-preview' option -# specified; those go in the appropriate ProblemList-enable-preview.txt file. +# specified in the task definition; those go in the appropriate +# ProblemList-enable-preview.txt file. +# # These are failures that occur WITHOUT the '--enable-preview' option -# specified AND occur because of some issue with preview project code, -# in either implementation or test code. +# specified in the task definition OR the '--enable-preview' option +# MAY BE specified in the test itself. In either case, the failure +# occurs because of some issue with preview project code, in either +# implementation or test code. ############################################################################# diff --git a/test/lib/jdk/test/lib/cds/CDSAppTester.java b/test/lib/jdk/test/lib/cds/CDSAppTester.java index 3eac8a35a37..80ff54021f5 100644 --- a/test/lib/jdk/test/lib/cds/CDSAppTester.java +++ b/test/lib/jdk/test/lib/cds/CDSAppTester.java @@ -60,6 +60,10 @@ abstract public class CDSAppTester { private boolean generateBaseArchive = false; private String[] baseArchiveOptions = new String[0]; + public String aotCacheFile() { + return this.aotCacheFile; + } + /** * All files created in the CDS/AOT workflow will be name + extension. E.g. * - name.aot diff --git a/test/lib/jdk/test/lib/cds/CDSArchiveUtils.java b/test/lib/jdk/test/lib/cds/CDSArchiveUtils.java index 35cee750822..04922654592 100644 --- a/test/lib/jdk/test/lib/cds/CDSArchiveUtils.java +++ b/test/lib/jdk/test/lib/cds/CDSArchiveUtils.java @@ -75,9 +75,14 @@ public class CDSArchiveUtils { "ro", // ReadOnly "bm", // relocation bitmaps "hp", // heap + "ac", // aot code }; private static int num_regions = shared_region_name.length; + public static String[] getRegions() { + return shared_region_name; + } + static { WhiteBox wb; try { diff --git a/test/lib/jdk/test/lib/cds/SimpleCDSAppTester.java b/test/lib/jdk/test/lib/cds/SimpleCDSAppTester.java index a8bba9c76e2..73e45711fe9 100644 --- a/test/lib/jdk/test/lib/cds/SimpleCDSAppTester.java +++ b/test/lib/jdk/test/lib/cds/SimpleCDSAppTester.java @@ -211,4 +211,22 @@ public class SimpleCDSAppTester { tester.run(args); return this; } + + public SimpleCDSAppTester rerunProduction(String... extraVmArgs) throws Exception { + tester.productionRun(extraVmArgs); + return this; + } + + public SimpleCDSAppTester rerunProduction(String[] extraVmArgs, String... extraAppArgs) throws Exception { + tester.productionRun(extraVmArgs, extraAppArgs); + return this; + } + + public String aotCacheFile() { + return tester.aotCacheFile(); + } + + public void setCheckExitValue(boolean b) { + tester.setCheckExitValue(b); + } } diff --git a/test/lib/jdk/test/lib/containers/systemd/SystemdRunOptions.java b/test/lib/jdk/test/lib/containers/systemd/SystemdRunOptions.java index 5f5d513a8b2..97d6542ec3b 100644 --- a/test/lib/jdk/test/lib/containers/systemd/SystemdRunOptions.java +++ b/test/lib/jdk/test/lib/containers/systemd/SystemdRunOptions.java @@ -1,5 +1,6 @@ /* * Copyright (c) 2024, Red Hat, Inc. + * Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -37,6 +38,8 @@ public class SystemdRunOptions { public ArrayList classParams = new ArrayList<>(); public String memoryLimit; // used in slice for MemoryLimit property public String cpuLimit; // used in slice for CPUQuota property + public String memoryLow; // used in the systemd-run scope for MemoryLow property + public String memoryHigh; // used in the systemd-run scope for MemoryHigh property public String sliceName; // name of the slice (nests CPU in memory) public String sliceDMemoryLimit; // used in jdk_internal.slice.d public String sliceDCpuLimit; // used in jdk_internal.slice.d @@ -118,6 +121,28 @@ public class SystemdRunOptions { return this; } + /** + * The memory soft protection set on the systemd-run scope that launches the JVM. + * + * @param memoryLow The memory soft protection to set (e.g. 500M). + * @return The run options. + */ + public SystemdRunOptions memoryLow(String memoryLow) { + this.memoryLow = memoryLow; + return this; + } + + /** + * The memory throttle limit set on the systemd-run scope that launches the JVM. + * + * @param memoryHigh The memory throttle limit to set (e.g. 500M). + * @return The run options. + */ + public SystemdRunOptions memoryHigh(String memoryHigh) { + this.memoryHigh = memoryHigh; + return this; + } + /** * The Cpu limit set in the top-level jdk_internal.slice.d * systemd config directory. diff --git a/test/lib/jdk/test/lib/containers/systemd/SystemdTestUtils.java b/test/lib/jdk/test/lib/containers/systemd/SystemdTestUtils.java index 9acff93aaca..5a868b8cd2a 100644 --- a/test/lib/jdk/test/lib/containers/systemd/SystemdTestUtils.java +++ b/test/lib/jdk/test/lib/containers/systemd/SystemdTestUtils.java @@ -1,5 +1,6 @@ /* * Copyright (c) 2024, Red Hat, Inc. + * Copyright (c) 2026, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -291,6 +292,18 @@ public class SystemdTestUtils { return String.format("%s.slice", sliceName); } + private static void addScopeMemoryProperties(List javaCmd, SystemdRunOptions opts) { + if (opts.memoryLow != null || opts.memoryHigh != null) { + javaCmd.add("--property=MemoryAccounting=true"); + } + if (opts.memoryLow != null) { + javaCmd.add("--property=MemoryLow=" + opts.memoryLow); + } + if (opts.memoryHigh != null) { + javaCmd.add("--property=MemoryHigh=" + opts.memoryHigh); + } + } + /** * Build the java command to run inside a systemd slice * @@ -304,6 +317,7 @@ public class SystemdTestUtils { List javaCmd = systemdRun(); javaCmd.add("--slice"); javaCmd.add(sliceFileName(sliceNameCpu(opts))); + addScopeMemoryProperties(javaCmd, opts); javaCmd.add("--scope"); javaCmd.add(Path.of(Utils.TEST_JDK, "bin", "java").toString()); javaCmd.addAll(opts.javaOpts);